Relative "crossing" percent calculation - javascript

I have this math problem. I need to know the formula to get something like this:
50% of (x) = 150% of 70
100% of (x) = 100% of 70
150% of (x) = 50% of 70
200% of (x) = 25% of 70
...
It seems easy but I'm stuck with this tiny issue. Please note, the (x) is a variable and is irrelevant for this calculation.
For more information, I'm calculating the offset for an image. The offset need to be relative to the resizing. Here's an example (the width test is 1920px, the original offset is 70px) :
50% of 1920 = 150% of 70 = 105
100% of 1920 = 100% of 70 = 70
150% of 1920 = 50% of 70 = 35
200% of 1920 = 25% of 70 = 17,5
...
The final code is in javascript.
* EDIT *
In fact, I just need to understand how i increase a value and at the same time decrease a another in synchronous way.
...
25% ==> 200%
50% ==> 150%
100% ==> 100%
150% ==> 50%
200% ==> 25%
...
There is the render (sorry it's made quickly)
In fact, for my calculation, "70" is a constant. More my image is larger (>100%) more my offset needs to be smaller. This is also apply in inverted situation (my image is smaller <100%, more my offset needs to be bigger).

I am afraid it is not a linear equation at the very least:
function test(x){return x*-1 + 200}
alert(test(50)) // okay 150
alert(test(100)) // okay 100
alert(test(150)) // okay 50
alert(test(200)) // wrong 0
http://jsfiddle.net/basarat/Skss2/

If you need to find what x equals to (which is customary for equations):
70 / 100 * 50 (that is we calculate the 150% of 70) / 50 (this is 1% of x) * 100
UPD: Based on more comments, i think you'd be better off using some hard-coded values instead of calculated ones.
var myPercentage = 0;
if (initPercentage <= 50) {
myPercentage = 150;
} else if (initPercentage > 50 and initPercentage <= 100) {
...
}

You have a basic mathematic problem where:
a% * x = b% * 70
Solving for x, first expand the terms (order of * and / is not significant here):
a * x / 100 = b * 70 / 100
multiply both sides by 100
a * x = b * 70
divide both sides by a:
x = b * 70 / a
So now given a and b you can solve for x. Let a = 50 and b = 150, then:
x = 150 * 70 / 50
x = 210
Test: 150% of 70 = 105 and 50% of 210 = 105, so it works.
But then you have:
100% of (x) = 100% of 70
which means x == 70, which is inconsistent, and then:
150% of (x) = 50% of 70
which means x = 23.33333333, which is again inconsistent.
You could do a least square solution to work out the best value for x, but likely the values are so widely spread it wouldn't be much use.

Yes.. I resolved my issue but my logic was wrong. I'm sorry.
I used Excel to find my formula.

Related

Represent a number with a color, difference not enough for percentage based rgb

I have an array (1200 values) of numbers
[123, 145, 158, 133...]
I'd like to have a div for each value with a background color from red to green, red being the smallest number and green the largest.
The base setup looks like this: (templating with vuejs but unrelated to the problem)
const values = [123, 145, 158, 133...]; // 1200 values inside
const total = values.length;
<div
v-for="(val, i) in values"
:key="i"
:style="{backgroundColor: `rgb(${(100 - (val*100/total)) * 256}, ${(val*100/total) * 256}, 0)`}">
{{val}}
</div>
I'm not a maths specialist but since all my numbers are around 100, the rgb generated is the same. (around 12% yellowish color)
How can I give more weight to the difference between 137 and 147?
EDIT: final formula:
:style="{backgroundColor: `rgb(${(256/(maxValue-minValue) * (boule-maxValue) - 255)}, ${(256/20 * (boule-maxValue) + 255)}, 0)`}"
Checkout this post: https://stats.stackexchange.com/questions/70801/how-to-normalize-data-to-0-1-range.
Basically you want to linearly rescale your values to another interval. You need your current min and max values from the array. Then define the new min' and max' which are the limits of the new interval. This would be [0, 255] in your case.
To do the transformation use the formula:
newvalue= (max'-min')/(max-min)*(value-max)+max'
As an example:
If your min value is 127 and max is 147, and you want to map 137. Then:
256/20 * (137-147) + 255 which results in 127.
If you want to map 130. Then:
256/20 * (130-147) + 255 = 37.4.
It really depends on what meaning those values actually have
However, you can try this: if your values are always bigger than 100 and always less than 150 (you can choose these number of course) you can "stretch" your values using the values as minimum and maximum. Let's take 137 and 147 as examples:
(val-min) : (max-min) = x : 255
(137-100):(150-100) = x:255 -> 37:50 = x:255 -> 188
(147-100):(150-100) = x:255 -> 47:50 = x:255 -> 239
That is for the math. In the end, this is the calculation:
newValue = (val-min)*255/(max-min)
where min and max are your chosen values.
You could take a kind of magnifier for a range of data. In this example, the values between 20 and 30 are mapped to a two times greater range than the outside values inside of an interval of 0 ... 100.
function magnifier(value, start, end, factor) {
var middle = (start + end) / 2,
size = (end - start) * factor / 2,
left = middle - size,
right = middle + size;
if (value <= start) return value * left / start;
if (value <= end) return (value - start) * factor + left;
return (value - end) * (100 - right) / (100 - end) + right;
}
var i;
for (i = 0; i <= 100; i += 5) {
console.log(i, magnifier(i, 20, 30, 2));
}
.as-console-wrapper { max-height: 100% !important; top: 0; }

What's the easiest way to convert a number to a percentage in JavaScript?

I'm calculating the difference in size of images after they've been resized by the user. I take the images new width and divide it by the natural width. This is the code:
Math.round( (img.width / naturalWidth) * 100) / 100
The numbers I get as a result can look like the following (and the numbers commented out are what I'd like to convert them to).
0 // 0%
1 // 100%
1.2 // 120%
1.39402 // 139%
1.39502 // 140%
21.56 // 216%
0.4 // 40%
0.44 // 44%
0.1 // 10%
0.01 // 1%
0.005 // 1%
0.0049 // 0%
Never negative numbers. I need to round these numbers and then convert them into strings represented as percentages. Is there an easy and straightforward way to accomplish this?
You can use Math.round like this:
Math.round((img.width/ naturalWidth) * 100));
A simple example:
var a = 1.2;
var b = 1;
alert(Math.round((a / b) * 100) + '%'); // 120%
This should do the trick:
const formatAsPercentage = x => `${Math.round(x * 100)}%`
You can use it as:
formatAsPercentage(.05) // => "5%"
First multiply the number by 100 then use Math.round() to round the result. Finally, add the percent sign:
Math.round(img.width / naturalWidth * 100) + "%";
I've used in own project
function calculatePercent(config){
var currentProgressPercent;
var totalRecords = Number.parseFloat(config.totalRecords);
var current = Number.parseFloat(config.current);
currentProgressPercent = 0;
if (!(isNaN(totalRecords) || isNaN(current))) {
currentProgressPercent = (totalRecords === 0 ? 100 : Math.round((current / totalRecords) * 100));
}
currentProgressPercent += '%';
return currentProgressPercent;
}
var input = [0, 1, 1.2, 2.156, 0.4, 0.44, 0.1, 0.01, 0.005, 0.0049];
input.forEach(function(value){
alert(calculatePercent({current:value, totalRecords: 1}));
});
You might do some refactoring for your needs in variable names.

Javascript calculating a formula

I am working on changing a percentage value of a panel based on the screen size of a device.
I need to work out the following formula.
Starting at screen width 320 and ending at screen width 1200.
If screenWidth < 320 percentageWidth = 98
If screenWidth > 1200 percentageWidth = 65
From the above I can work out manually that:
If screenWidth = 760 percentageWidth = 82.
What is the formula I need so I can change percentageWidth on a screen width change?
That's just simple math:
You start with the minimum of 65 and add a relative amount depending on the screen width:
Demo
function getPercentageWidth(screenWidth) {
return 65 + 33 * (Math.min(Math.max(screenWidth, 320), 1200) - 320) / 880;
}
getPercentageWidth(0) // 65
getPercentageWidth(320) // 65
getPercentageWidth(1200) // 98
getPercentageWidth(2400) // 98
getPercentageWidth(760) // 81.5
Inverse version Demo
This version starts with 98 and subtracts the relative amount:
function getPercentageWidth(screenWidth) {
return 98 - 33 * (Math.min(Math.max(screenWidth, 320), 1200) - 320) / 880;
}
getPercentageWidth(0) // 98
getPercentageWidth(320) // 98
getPercentageWidth(1200) // 65
getPercentageWidth(2400) // 65
getPercentageWidth(760) // 81.5
The other answers use if/else but you can also use Math.min and Math.max:
Math.max(screenWidth, 320) // Will always return 320 or more
Math.min(screenWidth, 1200) // Will always return 1200 or less
So the result of (Math.min(Math.max(screenWidth, 320), 1200) - 320) / 880 will always be between 0 and 1.
Although you don't explicitly say so, it appears that you're predicting a linear correlation between screenWidth and percentageWidth. If so, here's an example of code that you can put into a function for the result:
minScreenWidth = 320;
maxScreenWidth = 1200;
diffScreenWidth = maxScreenWidth - minScreenWidth;
maxPercentageWidth = 98; // At screenWidth = 320
minPercentageWidth = 65; // At screenWidth = 1200
diffPercentageWidth = maxPercentageWidth - minPercentageWidth;
screenWidth = 760; // Change this as needed.
ratioScreenWidth = (screenWidth - minScreenWidth) / diffScreenWidth;
percentageWidth = maxPercentageWidth - (ratioScreenWidth * diffPercentageWidth);
// Since your example gave 82 as the desired result instead of 81.5,
// I infer that you want the answer rounded.
resultPercentageWidth = Math.round(percentageWidth);
#jantimon posted his answer first, with a very elegant one-line function (which I have upvoted). I kept working on this answer in the meantime because I had taken a different approach of breaking down the steps in the hope that it will help you analyze other math functions that you need to apply to JavaScript.
I see that you are a new user. Welcome. And when you return to view the answers, please remember to mark one of them as correct (whichever was most useful to you), and to upvote any that were useful to you, if your reputation points allow it.
Also, when you post questions in the future, please be aware that you're also expected to show examples of your own attempts and the results of those attempts.
You want something like:
function doCalc(sw) {
var pw;
if (sw < 320) {
pw = 98;
} else if (sw > 1200) {
pw = 65;
} else {
// pw = 98 - (98 - 65) * (sw - 320) / (1200 - 320);
pw = 98 - 33 * (sw - 320) / 880;
}
return Math.round(pw);
}
or if you like one liners:
function doCalc(sw) {
return Math.round(sw<320? 98 : sw>1200? 65 : 98 - 33*(sw-320)/880);
}
The first answer delivers opposite results, the second the wrong values for screenWidth < 320 and screenWidth > 1200. This one is hopefully correct and maybe a little more readable:
var calculatePercentageWidth = function(screenWidth) {
var MAX_SCREEN = {percentage: 65, width: 1200};
var MIN_SCREEN = {percentage: 98, width: 320};
if (screenWidth < MIN_SCREEN.width) {
return MIN_SCREEN.percentage;
} else if (screenWidth > MAX_SCREEN.width) {
return MAX_SCREEN.percentage;
} else {
var coefficient = (MIN_SCREEN.percentage - MAX_SCREEN.percentage) / (MAX_SCREEN.width - MIN_SCREEN.width);
return Math.round(MAX_SCREEN.percentage + (screenWidth - MIN_SCREEN.width) * coefficient);
}
}
If the values for the maximum and minimum width or percentage change, you only need to change the values in the constants at the top of the function.
To calculate the percentageWidth for screenWidth = 760, write:
calculatePercentageWidth(760);
jsfiddle
Corrected version:
var calculatePercentageWidth = function(screenWidth) {
var MAX_SCREEN = {percentage: 65, width: 1200};
var MIN_SCREEN = {percentage: 98, width: 320};
if (screenWidth < MIN_SCREEN.width) {
return MIN_SCREEN.percentage;
} else if (screenWidth > MAX_SCREEN.width) {
return MAX_SCREEN.percentage;
} else {
var coefficient = (MIN_SCREEN.percentage - MAX_SCREEN.percentage) / (MAX_SCREEN.width - MIN_SCREEN.width);
return Math.round(MIN_SCREEN.percentage - (screenWidth - MIN_SCREEN.width) * coefficient);
}
}
jsfiddle
What you are trying to do is called linear interpolation. For two points, (x0, y0) and (x1, y1) there exists a straight line. Linear interpolation takes any value x between x0 and x1 and calculates the y value that falls on that line. The general case is computed as:
y = y0 + (y1 - y0) * (x - x0) / (x1 - x0)
For your case, the two points are (320, 98) and (1200, 65). This results in the equation:
y = 98 - 33 * (x - 320) / 880
To validate your calculation, set x = 760:
y = 98 - 33 * (760 - 320) / 880
= 98 - 33 * 440 / 880
= 98 - 33 / 2
= 98 - 16.5
= 81.5

Best way to generate random number between x and y but not between a and b

I have a canvas that is 1000x600px. I want to spawn sprites outside the canvas (but evenly distributed).
What is the best way to retrieve random values between (-500, -500) and (1500, 1100) but not between (0, 0) and (1000, 600)? I understand a while loop could be used to generate numbers until they are in range but that seems superfluous. Thanks.
If you want to generate a number between -500 and 1500, excluding 0 to 1000, you can just generate a number between 0 and 1000 ( 0 - -500 + 1500 - 1000).
If the number is less than 500, you subtract 500; if the number is greater or equal to 500, add 500.
Or, more generically:
function randomInt(outerMin, outerMax, innerMin, innerMax)
{
var usableRange = innerMin - outerMin + outerMax - innerMax,
threshold = innerMin - outerMin,
num = Math.floor(Math.random() * (usableRange + 1));
if (num < threshold) {
return num - threshold;
} else {
return num - threshold + innerMax;
}
}
randomInt(-500, 1500, 0, 1000);
For two-dimensional points you have to get more creative. First, you generate two points that ARE inside the forbidden area and then spread those values to the good areas:
function randomVector(outer, inner)
{
var innerWidth = inner.right - inner.left,
innerHeight = inner.bottom - inner.top,
x = Math.floor(Math.random() * (innerWidth + 1)),
y = Math.floor(Math.random() * (innerHeight + 1)),
midx = Math.floor(innerWidth / 2),
midy = Math.floor(innerHeight / 2);
if (x < midx) { // left side of forbidden area, spread left
x = x / midx * (inner.left - outer.left) - inner.left;
} else { // right side of forbidden area, spread right
x = (x - midx) / midx * (outer.right - inner.right) + inner.right;
}
if (y < midy) { // top side of forbidden area, spread top
y = y / midy * (inner.top - outer.top) - inner.top;
} else { // bottom side of forbidden area, spread bottom
y = (y - midy) / midy * (outer.bottom - inner.bottom) + inner.bottom;
}
// at this point I'm not sure how to round them
// but it probably should have happened one step above :)
return {
x: Math.floor(x),
y: Math.floor(y)
}
}
randomVector({
left: -500,
top: -500,
right: 1500,
bottom: 1100
}, {
left: 0,
top: 0,
right: 1000,
bottom: 600
});
Important
This works because the areas outside of your "forbidden" area are equal in their respective dimension, i.e. padding-top == padding-bottom && padding-left == padding-right.
If this will be different, the distribution is no longer uniform.
Generate a random number between 0 and 1000, if its over 500 add 500 (or 600 respectivly) if not negate it.
Instead of having a set of forbidden rectangles, you could calculate a set of allowed rectangles. To get a random position inside any allowed rectangle, you first choose a random rectangle and then a random position inside that chosen rectangle.
When the retangles don't have an equal size, you need to weight them by area, otherwise smaller rectangles will have a higher density than larger ones (a 200x100 rectangle needs to be 100 times as likely as a 10x20 rectangle).
Just generate those numbers between (0,0) and (1,1) and then use some linear function to do the mapping.
Otherwise, divide the area where you want the random coordinates to fall in rectangles. Let's say you obtain N such rectangles. Each of those rectangles may be populated through mapping the output of a random generator betweeen (0,0) and (1,1) to that rectangle (this is a linear mapping).

Resizing and Calculating sizes of Elements depending on count and fixed wrapper

lets say you have a block (div) with a size of 100px X 100px.
Now I pass into this block one image with the size of 100 X 100px. The same size, so it fits.
Now the question: What is the best approach if I have 2, 3 or 6 images and I want them to appear in the 100 X 100px box.
Example: 1 Image -> 100 * 100, 2 Images 50 * 50 each, 9 images 33% * 33% each.
The images will always have same width and height.
Thanks for any tipps!
you answerd your own question :-)
imageWidth = containerWidth/amountImages
For your "Tile" Solution you can
imageWidth = containerWidth/amountImagesInRow
imageHeight = containerHeight/amountImagesInColumn
If you want to determine how many rows/col you need:
define a minimum width an do some kind of
for(...){
if imageWidth < minWidth
amountImages -= 1;
imageWidth = containerWidth/amountImages
}
imagesInRow = amountImages;

Categories