Context: In Sketch, I am writing a plugin to render text on the canvas that shows a vertical list of text and its font size + weight combinations.
[ Uses JavaSCript [
The problem: I cannot figure out how to programmatically increase the Y pos of each layer properly.
Say I have two arrays:
const fontWeights = ['normal', 'bold'];
const fontSizes = ['small', 'medium', 'large'];
I want to generate a vertical list of each combination of fontWeight + fontSize, so it looks like this:
smallNormal
smallBold
mediumNormal
mediumBold
largeNormal
largeBold
(or graphically, see image)
function renderLayers() {
return fontWeights.map((weight, weightsIndex) =>
fontSizes.map((size, sizeIndex) =>
return (
<TextLayer
fontSize={size}
fontWeight={weight}
yPos={ (weightsIndex + sizeIndex) * 100 }
/>
}
That kinda works, except there is a case where:
0 + 0 * 100 = 0
0 + 1 * 100 = 100
1 + 0 * 100 = 100 // <-- that should be 200
All I really want to do is offset each iteration by a fixed amount. I am sure that there's some logic / mathematical way to do this, but i am stuck.
Help would be great thanks!
You can just keep an external variable to store the yPos:
function renderLayers() {
let y = 0;
return fontWeights.map((weight) =>
fontSizes.map((size) => {
y = y + 100;
return <TextLayer fontSize={size} fontWeight={weight} yPos={y} />;
})
);
}
The map index might not be the best for this job because it alternates between 0 and the length of the array - 1, so it's really not what you want. You need some variable on the outside of the maps that can store the "count" of both iterations combined.
I've added a new line, but you could also just do:
return <TextLayer fontSize={size} fontWeight={weight} yPos={y += 100} />;
Related
This question already has answers here:
Does JavaScript have a method like "range()" to generate a range within the supplied bounds?
(88 answers)
Closed 11 months ago.
OK time to pick the hive mind brain.
I am creating a dropdown (well 2 of them) and I need them to do the following
Height from 4'0" to 7'0"
Weight from 100lb to 400lb in 5lb incraments.
What would be the best/easiest way to create this array without having to manually create an array
It just needs to be as simple as
const heights = [
{ id: '', name: '' },
]
I just to not know how to best create it in as few Lines of code or manually creating the array
Same with height in 5lb increments
EDIT: SO people know WHY I am asking this - try doing a google search and enjoy the frustration.
For the weights, you can use the Array.fill function as seen in this answer.
// https://stackoverflow.com/questions/3895478/does-javascript-have-a-method-like-range-to-generate-a-range-within-the-supp
const range = (start, stop, step = 1) =>
Array(Math.ceil((stop - start) / step) + 1).fill(start).map((x, y) => x + y * step)
const weights = range(100, 500, 5).map((x, index) => ({
id: index,
name: x
}))
console.log(weights)
// or with one line of code
const w = Array(Math.ceil((500 - 100) / 5) + 1).fill(100).map((x, index) => ({
name: x + index * 5, id: index
}))
console.log(w)
For the heights, you can use a simple algorithm as a while loop with a condition for the increment
const start = {
integer: 4,
fractionnal: 0
}
const end = {
integer: 7,
fractionnal: 0
}
const heights = []
let index = 1
while (start.integer < end.integer || start.fractionnal <= end.fractionnal) {
heights.push({
id: index,
name: `${start.integer}.${start.fractionnal}`
})
if (start.fractionnal < 11) start.fractionnal += 1
else {
start.integer += 1
start.fractionnal = 0
}
}
console.log(heights)
Im trying to draw a simple map with some simple circle objects on it. Each object has a field with an int value (can range between -1000 to 1000 for example). I would like to give each object a color based on the value, for example, I would like the higher the value the color would be closer to red, and the lower the value it would be close to blue. But the specific color pallet doesn't really matter.
Is there any simple way to do something like that? Are there any libs that give this functionality?
This is crafted from my earlier answer somewhere here in SO. What it does, it gets the hex value of certain colour group (R, G, B, A [for alpha channel]). Now the hex value is emphasised based on the actual passed value (I made a functional example, feel free to modify).
And you can overwrite any of the RGBA values directly if you want, like giving "0" or "255" to them directly.
const getHex = (value) => Math.floor(value).toString(16).padStart(2, '0');
const getRGB = ({
R = 0,
G = 0,
B = 0,
A
}) => ['#', getHex(R), getHex(G), getHex(B), A].join('');
const testValues = [-1000, -750, -500, -250, 0, 250, 500, 750, 1000];
const results = testValues.map((value) => {
// if negative, no red value at all, otherwise value multiplied between 0 - 255:
const R = (Math.max(value, 0) > 0) ? value * 0.255 : 64;
// green is quite obsolete in this case, but some emphasis for lightness:
const G = (Math.abs(value) < 250) ? Math.abs(value) * 0.128 : 32;
// if negative, blue value is multiplied between 0 - 255, otherwise value 0:
const B = (Math.min(value, 0) < 0) ? Math.abs(value) * 0.255 : 64;
return getRGB({ R, G, B });
});
// TESTING PURPOSES:
const showResult = (result, i) => {
const textItem = document.createElement('div');
textItem.textContent = `#${i}`;
textItem.style.color = result;
document.body.appendChild(textItem);
};
results.forEach(showResult);
I am creating fake statistics real-time data for that I need to show the number of users available on the website for one game of 5 minutes,
I want to generate random numbers within a range of 1 to 100, but in incremental order. Which means every number that I get should be greater than the previous one.
Expected output:
Output at each function call will be like 1,5,12,25,...,98,100 in randomized and incremental order only.
Thanks in advance.
My code:
randomnumber(fixed,count,range){
return fixed+count*range;
},
function(){
var count = 1;
this.socketData( ({ data }) => {
count++
data.data.totalUsers += this.randomnumber(50,count,Math.abs(Math.floor(Math.random() * (100 - 1) +1)));
}
Assumptions
So, some assumptions to state:
no numbers can be duplicated
numbers must be ascending
numbers must be in range 1 - 100 (inclusive)
Which means we can have anywhere from 1x entry i.e. [100], up to 100 entries [0,1,2,...98,99,100].
So, to implement this strategy, we'll need to:
create X random entries (modify the seed as desired - 100x means we allow for all scenarios, I've chosen to randomise it)
sort the results
remove duplicates
TLDR;
Below is the implementation - works just as well for the range 50 - 200:
// range inclusive
const minRange = 1
const maxRange = 100
const rangePlusOne = maxRange - minRange + 1
// seed = [1 - 100]
const seedNumberOfEntries = parseInt(Math.random() * rangePlusOne) + 1
// generate, sort, unique
console.log([...new Set(
new Array(seedNumberOfEntries)
.fill(0)
.map(() => parseInt(Math.random() * rangePlusOne) + minRange)
.sort((a,b) => a-b)
)]
)
I suggest you create them in one loop and add to an array then sort that array. This should get you a sorted list of incremental random numbers.
You can then just pull 'next' whenever you want the next one.
let numbers = [];
for (let i =0, l = 100; i<l;i++){
let number = Math.floor(Math.random() * 100);
numbers.push(number);
}
numbers.sort(function (a, b) {
return a - b;
});
console.log(numbers);
const from = 0;
const to = 100;
const rand = Number(String(Math.random()).slice(2, 2 + 15));
const num = from + (rand % (to - from - 1)) + 1;
console.log(num);
Hope this will helps you can give range from & to
I'm trying to calculate the optimal set of plates to put on a barbell to get to the desired weight. It's working well, but the problem is it will always find the first possible weight under the target weight.
For example, if you want your barbell to weigh 29kg, you can either put 27.5kg or 30kg given the set of plates below, where each plate is assumed to be a pair. Once you know these two options, you would choose 30kg since it's closer to 29 than 27.5.
In this example, I just have it calculating 27.5, but I haven't figured out how to go back and calculate the closest possible weight once the if statement fails.
const BAR = 20;
const PLATES = [
1.25,
2.5,
2.5,
5,
5,
10,
10,
20,
20,
];
const sumPlates = (plates) => {
return plates.reduce((acc, plate) => {
return acc + (plate * 2);
}, 0);
};
const rack = (targetWeight) => {
const sortedPlates = PLATES.sort((a, b) => b - a);
const rackedPlates = sortedPlates.reduce((acc, plate) => {
if ((BAR + (plate * 2) + sumPlates(acc)) > targetWeight) {
// Calculate here the closest possible rack weight
return acc;
}
acc.push(plate);
return acc;
}, []);
return {
targetWeight,
barbellWeight: BAR + sumPlates(rackedPlates),
plates: rackedPlates,
};
};
console.log(rack(47)); // gives 45 but should give 47.5
console.log(rack(29)); // gives 27.5 but should give 30
It is actually a modified version of a Change-making problem, which itself is a modified version of Knapsack problem.
Depending on the size and type of the given weight, you can use dynamic programming solution in the link to find all possible combinations, and do a O(N) iteration to find the closest one to the target weight.
However given your current implementation, I would just do the following:
var x = rack(targetSum);
var y = rack(2*targetSum - x);
ans = the closer one to targetSum
Working in React. I have a multi-dimensional array with the values 0 or 1. I would like to run these through an iterator and add a class if the value is truthy, then return divs. And for every array value, I would like to build the board by dynamically changing the inline style 'top' and 'left' so every board piece gets dynamically positioned as it is run through the iterator. So far, I have tried flattening the array, then running through a map function. And I have tried two-levels of map. I can get either to produce the required number of divs, but they're all on top of one another. So it's basically a board with 64 tiles on the same spot. I am unable to get the style to dynamically update for each pass through the iterator. I can get this to work fine in vanilla javascript by just iterating through the array and appendChild each produced div.
I would like the end result to produce a bunch of divs (tiles), with the same class, some have an additional class to show they're populated, and all have slightly different 'top' and 'left styles' to produce a grid of these tiles.
Here is my code, which produces a lot of divs on top of one another.
class CheckerBoard extends Component {
render() {
let rows = this.props.rows.slice();
let flattened = _.flatten(rows);
let tiles = _.map(flattened, function (mapped) {
for(let i = 0; i < 20; i++){
for(let j = 0; j < 10; j++){
if(mapped){
return <div className="checkerTile filled" style={{top: `${i * 50}px`, left: `${j * 50}px`}}></div>
} else {
return <div className="checkerTile" style={{top: `${i * 50}px`, left: `${j * 50}px`}}></div>
}
}
}
});
return (
<div className="CheckerBoard">
{tiles}
</div>
);
}
}
You're generating 20 x 10 x number of items in flattened tiles, which is way more than 64.
How did you come up with these numbers? Also keep in mind that the nested loops execute within a map, which gives 200 iterations (200 new divs) per element in the flattened collection.
If you want an 8x8 checkbord with 64 elements you can do this with a single pass of the map function where column number is index % 8 and row is Math.floor(index / 8):
var Board = React.createClass({
render: function() {
return <div>{this.props.tiles.map( (tile, idx) => {
let position = {
left : `${ 50 * (idx % 8) }px`,
top : `${ 50 * Math.floor(idx/8) }px`
};
return <div className="tile" style={ position }>{ idx }</div>
})}</div>;
}
});
https://jsfiddle.net/cypued0h/
For a more general case, where the number of columns is configurable:
var Board = React.createClass({
render: function() {
return <div>{this.props.tiles.map( (tile, idx) => {
let position = {
left : `${ 50 * (idx % this.props.columns) }px`,
top : `${ 50 * Math.floor(idx / this.props.columns ) }px`
};
return <div className="tile" style={ position }>{ idx }</div>
})}</div>;
}
});
https://jsfiddle.net/cypued0h/1/