Javascript calculating a formula - javascript

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

Related

jQuery for each 24 over a number

I have this code
if ($('input#grommet').is(':checked')) {
if (width <= 96) {
var grommetQTY = 4;
} else if (width > 96) {
grommetQTY = (Math.floor(width / 24));
grommetQTY = grommetQTY - 4;
grommetQTY = grommetQTY * 2;
grommetQTY = grommetQTY +4;
}
}
and I need to add 2 to the grommetQTY for each whole 24 inches (2 feet) over 96 width. Is there a way to do this?
What this is attempting to accomplish is giving the pricing for a banner. We add 2 more grommets at 2 feet intervals, but because this is custom sizing, it could be 96 feet wide, and I don't want to have to write an else if statement for each two foot interval. I am hoping there is a way to only add two to the quantity everytime the width goes another 24 inches over the standard 96 inch width so if width is 96 or less, qty is 4, at 120 its 6, at 144 its 8, etc
Rather than coming up with the equation for this, here is a for loop that will do what you need:
var grommetQTY = 0;
for(var i = 96; i < n; i++)
if(i%24 == 0)
grommetQTY += 2;
where n is the length. This is terrible inefficient and could be sped up by just doing:
var grommetQTY = 0;
for(var i = 96; i < n; i+=24)
grommetQTY += 2;
This is nicer but still not ideal. The ideal solution in your case would be an equation.
P.S - The equation is Math.floor( Math.max((n - 96), 0) / 24 ) * 2 + 4 if I understand you correctly.
You could do something like this:
var extra = width - 96
var grommetQTY = 4;
if (extra > 0) {
grommet += Math.floor((extra / 24)) * 2;
}
The variable extra holds, as the name implies, extra length that you would want to take into consideration. If it's 0 or below that means it's 96 and under.
Then, for extra > 0 you could alternatively change it to extra >= 24 as any extra value less than 24 will return 0.
Math.pow(2, grommetQTY) * (Math.floor(96 / 24))
2 to the grommetQTY for each whole 24 inches in 96. Is that what you need?
Math.pow(a, b) gives a to the power of b
Edit:
var qty = (Math.floor(n / 24)) * 2
Where n is the pixels (96 in your example).
Edit:
var qty = 4 + ((width > 96) ? ((Math.floor((width - 96) / 24) * 2) : 0);
Is that it?

checking rolled by image number?

So, I have a code that is rolling a random number from 1024 to 4096 and changing backgroundPosition to rolled number. (jsfiddle)
function slide()
{
var x = 1;
var y = 30;
var z = Math.floor((Math.random() * 4096) + 1024); // background offset
var zz = Math.floor((Math.random() * 14) + 0); // number
var clr = setInterval(function()
{
if(x >= z) x = 1;
document.getElementById("slide").style.backgroundPosition = x+"px 0px";
x+=y;
y-=0.1;
if (y<=0)
{
clearInterval(clr);
document.getElementById('rolledNumber').innerHTML = z;
}
}
,10);
}
"z" is a random number between 1024 and 4096, how can I check what number on image it is? I tried if (z >= 2285 && z <= 2210){var zz = 4;}, where "zz" is a number on image, but it's not working.
Hope you guys can understand it.
You have a few problems here:
1) if (z >= 2285 && z <= 2210)
is impossible. There is no number that satisfies both "larger than 2284" AND "smaller than 2211".
2) "z" is a random number between 1024 and 4096
var z = Math.floor((Math.random() * 4096) + 1024); will actually create a random number between 1024 and 5120. Imagine the case where Math.random() returns 1. Your result would be 1 * 4096 + 1024, or 5120.
3) Your background image is repeating - if you stick to one set of 15 numbers, you could access the number by mapping the pixel offset to an array.. something like this:
var boxWidth = 150;
var boxes = [1, 14, 2, 13, 3, 12, 4, 0, 11, 5, 10, 6, 9, 7, 8];
function getNumber (offset) {
var boxNumber = Math.floor(offset / boxWidth);
return boxes[boxNumber];
}
4) No one knows the application of this logic other than you, please reword your question such that it actually makes any sense and act like you've tried to find the problem yourself.
If anyone is interested - I figured out how to do this. I'm checking "x" value, and if it's between x and y, that means rolled number is z. Fragment of code:
if (x >= 410 && x <= 485){var rolledNumber = 1;}
if (x >= 335 && x <= 410){var rolledNumber = 14;}
if (x >= 260 && x <= 335){var rolledNumber = 2;}

Function to write new text size on window resize

I am trying to figure out an equation for a small problem I'm having. I'm not great at figuring these types of things out, but I know I've done it before with a different set of numbers.
Basically, I'm trying to figure out:
if 360px = 100%;
and 959px = 160%;
then 720px = X;
720px is an arbitrary number. I know that 360px should be 100% font size, while 959px should be 160% font size. I'd like the body font-size to change when the screen is enlarged or shrunken (on load usually) and I'd like to find out any font size percentage in between.
I would like to plug this into a javascript math function for something like this:
function widthToPerc(){
var width = $(window).width();
var toPerc = // THIS FORMULA RIGHT HERE TO GET A PERCENTAGE
$('body').css({"font-size" : toPerc + "%"});
}
And then initiate this on window load and window resize.
if your equation is linear, this should be the solution:
f(x) = a*x + b
f(360) = 100
f(959) = 160
a * 360 + b = 100
a * 959 + b = 160
Solve this and you get a ~= 0.1 and b ~= 63.94
So, as a result:
var ToPerc = width * 0.1 + 63.94; // 99.94% for 360px; 159.84% for 959px
if you need more precision solve with more decimals
function calculate(w){
//Assuming the numbers you provided and w coming without px
var d = 959-360;
var p = 160-100;
var c = w - 360;
var cp = p*c/d + 100
return cp
}
I'm not sure if this is what you mean, but here's how I understood it.
This seems more like a math problem to me, so let's turn the pixels and percentages into points:
p1 = (360,100)
p2 = (959,160)
p3 = (720,y3)
Now we find what in terms of percent is 720 is in between 360 and 959:
(720-360)/(959-360) = around 60%
To get y3, we then do this:
((160-100)*.60)+100 = 136
Making this work for any value in between 360 and 959
function widthToPerc(){
var width = $(window).width();
var toPerc;
var minX = 360;
var maxX = 959;
var minY = 100;
var maxY = 160;
if (width >= 360) {
toPerc = min;
}
else if (width <= 959) {
toPerc = max;
}
else {
toPerc = ((maxY-minY)*((width-minX)/(maxX-minX)))+minY;
}
$('body').css({"font-size" : toPerc + "%"});
}
OnLoad you will get the initial $(window).width(). You will store that in a global variable as I said from the very beggining.
var initWidth = $(window).width();
Then the function:
function widthToPerc(){
var width = $(window).width();
var diff = width - initWidth;
var toPerc;
if(diff > 0){ //window is bigger after resizing
toPerc = Math.floor((diff / initWidth) * 100) + 100;
}
else{ //window is smaller after resizing
diff = Math.abs(diff);
toPerc = Math.abs(Math.floor((diff / initWidth) * 100) - 100);
}
$('body').css({"font-size" : toPerc + "%"});
}
So let's say you have 600 as initial width and the user resize the browser to make it bigger. Now the width is 800.
So:
var initWidth = 600;
var width = 800;
var diff = 200; // 800 - 600
diff > 0 // true
toPerc = 0.3 // 200 / 600
toPerc = 30 // after *100 and rounded down
toPerc = 130 // 30 + 100
//the window is a 30% bigger than it was intially
$('body').css({"font-size" : "130%"});
Now let's see when window it's been resized and got smaller
var initWidth = 600;
var width = 400;
var diff = -200; // 400 - 600
diff < 0 // true
diff = 200 //after Math.abs
toPerc = 0.3 // 200 / 600
toPerc = 30 // after *100 and rounded down
toPerc = -70 // 30 - 100
toPerc = 70 // after Math.abs
//the window is a 30% smaller than it was intially
$('body').css({"font-size" : "70%"});

Relative "crossing" percent calculation

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.

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).

Categories