Calculating axis length in proportion to fixed related length - javascript

Basics
I am working on a small tool that is supposed help with some geometric calculations for print-related products.
Overview
I have two inputs (w and h) where the user is supposed to enter a width and a height for a box. This box is supposed to be a representation of the users measurements as a small CSS-based box.
The problem is that I cannot just take the measurements and apply them as pixels, or even pixels * 10, or anything, as width/height for the display box, because my space is limited.
The box can have a maximum measurement of 69 x 69.
What I want to achieve is that to apply the longer entered measurement to its according axis, then calculate the other axis in proportion to this.
My approach
I am not a maths person at all. But I did my best and I put together a function that will accomplish the above:
updateRectBox: function(w, h){
// define maximum width and height for box
var max_x=69;
var max_y=69;
var factor,x,y;
factor=w/h;
if(w==h){
// if we have a 1:1 ratio, we want the box to fill `69px` on both axis
x=max_x;
y=max_y;
} else {
if(w>h){
// if width is larger than height, we calculate the box height using the factor
x=max_x;
y=(factor>1 ? max_y/factor : max_y*factor);
} else {
// if height is larger than width, we calculate the box width using the factor
x=(factor>1 ? max_x/factor : max_x*factor);
y=max_y;
}
}
// using this to set the box element's properties
jQuery('#rect').css({
'width': (x)+'px',
'height': (y)+'px'
});
}
This function works well, but:
Question
I know this can be done more beautifully, with less code. But due to my lack of math skills, I just cannot think of anything more compact than what I wrote.
I've created a working fiddle to make it easier for you to test your optimizations.

Your function accomplishes exactly what it needs to. There are ways which are arguably more elegant to write, however.
The basic idea is that you have a box with dimensions (w × h) and you want a box which is a scaled version of this one to fit in a (69 × 69) box.
To fit in a (69 × 69) box, your (w × h) box must be less than 69 wide, and less than 69 tall. Suppose you scale by the quantity s. Then your new box has dimension (s * w × s * h). Using the above constraint, we know that:
s * w <= 69 and that s * h <= 69. Rewrite these, solving for s, and you get:
s <= 69 / w and s <= 69 / h. Both must hold true, so you can rewrite this as:
s <= min( 69 / w, 69 / h). In addition, you want s to be as large as possible (so the box completely fills the region) so s = min( 69 / w, 69 / h).
Your code accomplishes the same, but through if-statements. You can rewrite it considerably terser by doing:
updateRectBox: function(width, height) {
// define maximum width and height for box
var max_width = 69;
var max_height = 69;
var scale = Math.min( max_width / width, max_height / height );
var x = scale * width;
var y = scale * height;
// using this to set the box element's properties
jQuery('#rect').css({
'width': x+'px',
'height': y+'px'
});
}
Changing the variable names helps make it slightly more readable (w and h presumably do mean width and height, but making this explicit is helpful).
All this said, it's unlikely that there will be noticeable performance differences between this and your original. The code is extremely fast, since it does very little. That said, I made a jsperf which shows that using Math.min is about 1.7 times faster on my browser.

Related

How to lower one number when the other rises?

I take a value from the mouse (mouseX) position in Processing, as this value gets higher, I want the amount of boxes that are rendered to lower in steps of 5 (rotStep).
I did a lot of reading and found out the method I should use is called 'Negative correlation' or at least I think it is. I have never had high-grade math so I'm pretty much in the dark here. Maybe there is a function that already exists to do this. After a lot of googling I came in here to ask.
Tried dividing the mouseX input by itself and some other random sums but it seems this might be more complicated than I anticipated.
I am trying to get into generative art generation and could use a hint to get further with my attempt of rendering more boxes (quads) as the mouseX value lowers.
void setup() {
pixelDensity(displayDensity());
size(500, 500);
background(0);
noFill();
stroke(255);
}
void draw() {
translate(width/2, height/2);
ellipse(0, 0, 50, 50);
background(0);
mouseX= constrain(mouseX, 1, width);
mouseY= constrain(mouseY, 1, height);
float rotationMax = 90;
float rotStep = (mouseX/15)+5;
//I need to add a negative correlation so the number
//of squares lowers as the mouseX position gets higher
//and all this in steps of 5
float quadSize = mouseX;
float qs = quadSize;
for (float i=0; i<rotationMax; i+=rotStep) {
float deg = rotStep;
float rad = radians(deg);
stroke(255);
strokeWeight(1);
rotate(rad);
quad(-qs, -qs, qs, -qs, qs, qs, -qs, qs);
}
}
The rotStep variable should decrease when the mouseX variable increases and vice versa. The variable rotStep should also increase or decrease in steps of 5.
The best advice I can give you is to get out a piece of paper and a pencil, and draw a table of mouse positions and the number of boxes you want. It might look like this:
mouseX boxes
---------------
0 | 50
100 | 40
200 | 30
300 | 20
400 | 10
500 | 0
This is just an example, so your numbers would probably be different. But the idea is to have a general mapping of mouseX to the number of boxes you want to draw.
Once you have that, then you can try to find an equation that gets you from mouseX to your box count. That might be a single equation, or it might involve if statements to bucket values together.
You can get a "negative correlation" by subtracting from the maximum possible value, or by using mouseX as a divisor.
float reverseMouseX = width - mouseX;
float inverseMouseX = 1 / mouseX;
For both of these approaches, as mouseX increases, the value of the variable will decrease. Then you can use these values in your equation or in your if statement logic.
To get to the example table I showed above, I might do something like this:
int boxes = (width - mouseX) / 10;
This is a general approach, but you can apply it to your goal to come up with a specific solution.
Good luck!

Get touch position on element when parent/body has scale transformation

I need to get the exact mouse/touch position from the left border of an element on move.
The problem is, that my body is scaled down with transform:scale() depending on window/device size.
The touch- and mouse-events x, pageX, and clientX properties values in relation to the elements offsetLeft property are wrong because of the scaling, so I can't use them to make a substraction and get the correct position.
With mouse-events I just use the offsetX property and it works fine.
The problem is, there is no offsetX property with touch-events.
I did some researches and found this issue where pointer-events are mentioned.
I never heard about pointer-events before and was quiet happy because I thought this would solve my issue.
But this pointed me to a new problem. pointer events are NOT supported in safari and ios.
Since the application is designed for ipad first this is a big problem.
So now I'm looking for a offsetX-like property I could use but there is none.
I know I could multiply for example the touch-events pageX by the inverted scale, but this would break if i change the scaling in the styles so no way to use this technique.
//no way to do this:
const windowWidth = window.innerWidth
let scale = 1
if(windowWidth < 1000) {
scale = 1.55
} else if(windowWidth < 1101) {
scale = 1.45
} else if(windowWidth < 1201) {
scale = 1.35
} else if(windowWidth < 1301) {
scale = 1.25
} else if(windowWidth < 1401) {
scale = 1.2
} else if(windowWidth < 1501) {
scale = 1.12
} else if(windowWidth < 1601) {
scale = 1.06
}
const x = (e.changedTouches ? (e.changedTouches[0].pageX * scale) - this.offsetLeft : e.offsetX)
I've created a demo where you can play around (switch in dev tools between mobile and desktop/resize for scalings).
My explanation could be a little bit confusing please ask me if something isn't clear.
Help would be greatly appreciated.
If it's just scaling, grab the current scale amount by getting the currently applied transform style and parsing it, then divide by the scale factor.
If you need to get fancier, such as if rotations or 3D transforms are used, you can multiply by the inverse transformation matrix: see this post and the accompanying jsfiddle for details and code.

Find scale amount based on new dimensions

If I have an image that has 100 x 100 size, then I resize it to 200 x 200, how can I calculate how much it was scaled?
In this example the scale amount would be 2.0. How can I get that number from the known variables (original size, new size) ?
Simply divide the new height by the original height and divide the new width by the original width...
double xfactor = (double)NewImage.Height / (double)OldImage.Height;
double yfactor = (double)NewImage.Width / (double)OldImage.Width;

Javascript stage scale calculator

I've searched far and wide throughout the web thinking that somebody may have had a similar need, but have come short. I'm needing to create a calculator that will adjust the size of a stage for draggable objects based on a Width and Height field (in feet).
I'm needing to maintain a max width and height that would, ideally, be set in a variable for easy modification. This max width and height would be set in pixels. I would set dimensions of the draggable items on the stage in "data-" attributes, I imagine. I'm not looking to match things up in terms of screen resolutions.
What's the best way to approach this? I'm pretty mediocre at math and have come up short in being able to create the functions necessary for scaling a stage of objects and their container like this.
I'm a skilled jQuery user, so if it makes sense to make use of jQuery in this, that'd be great. Thanks in advance.
There are at least a couple of ways to scale things proportionately. Since you will know the projected (room) dimensions and you should know at least one of the scaled dimensions (assuming you know the width of the stage), you can scale proportionately by objectLengthInFeet / roomWidthInFeet * stageWidthInPixels.
Assuming a stage width of 500 pixels for an example, once you know the room dimensions and the width of the stage:
var stageWidth = 500,
roomWidth = parseFloat($('#width').val(), 10) || 0, // default to 0 if input is empty or not parseable to number
roomHeight = parseFloat($('#height').val(), 10) || 0, // default to 0 if input is empty or not parseable to number
setRoomDimensions = function (e) {
roomWidth = parseFloat($('#width').val(), 10);
roomHeight = parseFloat($('#height').val(), 10);
},
feetToPixels = function feetToPixels(feet) {
var scaled = feet / roomWidth * stageWidth;
return scaled;
};
Here's a demo: http://jsfiddle.net/uQDnY/

Javascript scale check function performance

All right people, I've got a slight performance bottle neck.
Basically I have a graph that consists of a screen div ("screen") and a chart div ("chart"), when this graph finishes rendering it checks to see what scale it needs to set on the chart in order to have the chart fit inside the screen. The problem is that whatever scale I come up with needs to be an exponent of 1.2. In other words you need to be able to get to the number of the new scale by taking 1.2 to the power of some number.
This function is what calculates the scale I need.
fitScale = function (width, height)
{
var scale = 1,
gWidth = graph.element.offsetWidth,
gHeight = graph.element.offsetHeight;
while (gWidth > width * scale && gHeight > height * scale)
scale *= 1.2;
while (gWidth < width * scale || gHeight < height * scale)
scale /= 1.2;
return 900 / scale;
}
The problem is that this sucks...
What it's doing is getting the chart size (width, height) and the screen size (gWidth, gHeight) and looping through a new scale until it hits the right number.
First it makes the scale bigger until at least one dimension of the chart times the scale is bigger than one dimension of the screen.
Than it loops back to make sure that both the dimensions of chart * scale are at least a little bit smaller than the screen.
I'de like to perform this action with just one math calculation. Maybe by calculating a snug fit and then by rounding down, but I can't figure out how to round down to an exponent of 1.2
-fix-
Here's the resulting working version...
fitScale = function (width, height)
{
var wScale = graph.element.offsetWidth / width,
hScale = graph.element.offsetHeight / height,
snugg = wScale < hScale ? wScale : hScale,
exp = Math.log(snugg) / Math.log(1 / 1.2),
scale = Math.pow(1 / 1.2, Math.ceil(exp));
return 900 / scale;
}
My math skills are rusty, so go easy if I wander off the Path of Truth here.
Basically you want to know what power y of 1.2 is equal to some given number x. While the log function would appear not to be helpful since it tells you what power of e will equal your number x, with some mad logarithm skillz you can in fact use that to get to where you want to go:
var y = Math.log(x) / Math.log(1.2);
Odds are pretty good that y won't be a whole number which is I think what you want, so if you just go ahead and Math.floor(y), you should be all set.

Categories

Resources