I'm trying to have resizable divs in my app. To do so I have to persist the changes that the user specified in my database.
My question is how do I change the units given to me from px to something else? When I do:
console.log(event.target.style.width)
it shows me the width in px. Is there any way to get it in, say, % or vh/vw?
How about:
event.target.style.width / document.documentElement.clientWidth * 100
Divide the width in pixels by the total viewport width, then multiply by 100 to get a percentage.
Related
I want to convert px to the viewport units (vh and vw). So I used these with no success?
var newWidth = yourElement.outerWidth / document.documentElement.clientWidth *100;
var newHeight = yourElement.outerHeight / document.documentElement.clientHeight *100;
I just get NaN.
I put my calculation in a timeout to be sure I'm selecting the element only when it's rendered.
How can I convert px to viewport units correctly?
yourElement.offsetWidth should work for you
Check out this answer to identify the sizes properly: How do I retrieve an HTML element's actual width and height?
Update:
I've created this Code Page demo to show what I'm talking about. This demo shows two methods, the first is the brute-force method and the second is Robert McKee's method.
With the first method, press the Scroll to End button to derive the vertical (y) scaling value, which is then shown next to the button that was just pushed. The list of values below the buttons, you will also see the number of 1px scrolls horizontally and vertically needed to fully scroll to the lower-left corner of the scroll-area, shown in the Scroll Y Count and Scroll X Count fields. With the scaling value now showing and the adjacent checkbox checked, pressing the Scroll to End button shows that the same number of 1px horizontal and scaled vertical scrolls now get to the lower-right end of the scroll-area.
With the second method, press the Calculate Y Scale button to calculate the y scale value without needing to actually scroll. After the value is calculated the second dive is scrolled to show that it works.
The first method finds a y scale value that allow scrolling so that the horizontal and vertical scrolls over and down such that they both get to the left side and bottom with exactly the same number of scrolls. I'm not sure why there is a difference, but the second method is very close, only one scroll different, so its good enough.
Original Question:
I need to calculate the scaling values needed to scroll the horizontal and vertical scrollbars of a div so that when the horizontal scrolling completely traverses the width of the div, the vertical scrolling also completely traverses the height of the same div.
I do this now by first manually counting the number of of calls of the $( '#div' ).scrollLeft( ++x ) jQuery function and, separately, the number of calls of the $( '#div' ).scrollTop( ++y ) function, with the x and y values starting at 0, and increasing by 1 per call, that are needed to scroll over the div's width and height, respectively. In my case the div is 540 px wide by 759 px high, and it take 342 times to cover the width and 660 for the height. From this I can calculate the y scaling value to put in the vertical scroll function call, $( '#div' ).scrollTop( ++y * yScale ), to be 660/342 for my div. The issue is that the div's width and height aren't always the same so I can't use a pre-calculated value for the y scaling value for all possible contents that the scrolling div needs to display.
Why with a 1 pixel x and y increment isn't the number of each scroll calls not 540 and 759 rather than 342 and 660 for my specific case?
Before trying to automate the calculations, I tried calling the scrollTop function multiple times with a parameter value starting with 0, and incrementing by 1 pixel in each successive call (0, 1, 2, ... 10, 11, .., 20, etc.), and I found that the amount scrolled by each scroll call was not consistent.
I include this because with the inconsistency I found that I couldn't rely on the average scrolled amount by a few scroll calls to calculate the total number of calls needed to traverse the full distance of each div axis direction.
I can automate this with a loop that counts the number of repeated calls for each dimension, stopping counting for each direction when the respective scrollbar stops scrolling, and stopping looping when both scrollbars stop scrolling, but I'd rather not have to do this if there is a purely mathematical way to calculate the scaling values. Besides, this would look odd to the user as the div contents jumped around each time it is loaded, especially for larger contents and slow the display.
Does anyone know how to do this?
Thanks.
If you are trying to calculate yScaling, here you go:
var elem = $('#div2a').parent()[0]; // same as divScroller[0]
var yScaling = (elem.scrollHeight-elem.clientHeight) / (elem.scrollWidth-elem.clientWidth);
which for your divs, comes out to 1.9298245614035088.
If you want the values you are trying to calculate in "Ave Scroll Y" and "Ave Scroll X", then those values are 1 and 1/1.9298245614035088 which is 0.5181818181818182.
This is why the formula works:
Assume you have a viewport of 100px width, and the content inside that viewport is 400px. When fully scrolled left, the scrollLeft will be 300px (400px - 100px). 300px of the 400px will be off the screen, and the last 100px will be visible inside the viewport. That is why when you are trying to calculate the maximum value for scrollLeft, you use scrollWidth - clientWidth of the viewport (.scroller). Do the same thing to calculate the maximum scrollTop, and the Y-Scaling is the ratio between those two numbers.
Use currentScrollX and currentScrollY for setting current position of scrollbar and destinationScrollX and destinationScrollY for where you want to go
Then each animation loop runs the following to recalculate currentScrollX and currentScrollY
var speed = 20; // adjust accordingly
// Home into destination
currentScrollX += (destinationScrollX - currentScrollX) / speed;
currentScrollY += (destinationScrollY - currentScrollY) / speed;
To end scrolling simply do something like
if (Math.abs(destinationScrollX - currentScrollX) < 0.05 && Math.abs(destinationScrollY - currentScrollY) < 0.05) {
currentScrollX = destinationScrollX;
currentScrollY = destinationScrollY;
// stop scrolling flag / code goes here
}
// At this point set scrollTop(currentScrollY) and scrollLeft(currentScrollX)
Update
If you want to scroll x and y a certain number of pixels in 30 frames based on their width / height then
var scaleX = widthOfScrollingDiv / 30;
var scaleY = heightOfScrollingDiv / 30;
You then animate for 30 frames and you'll reach the destination at the same time even if width and height aren't the same.
Currently using the aspect ratio of a background image to size the Div containing it.
I'm using padding-bottom (imgwidth / imgheight * w) to give it it's "responsive height".
It lines up perfectly until I start zooming in and out for different screen sizes. 100% width and above is perfect (only because I lock the max size at 1500 or I guess I'd have the same issue otherwise).
But zooming in at for example 90% I start getting gaps between the two as I have two background divs one on top of the other.
It's being caused because, for example:
padding-bottom: calc(100% * 600 / 1500);
Is returning a decimal point when zoomed in and the value is being rounded up for pixels.
Is there a solution to this? Or some javascript that can correct it?
I have made a script: http://jsfiddle.net/radar24/XZgh4/ which scales the given dimension into the outer div. everything seems fine, until I enter a dimension such as 200 x 99. then the box grows outside.
I really cannot find the cause of this, can anyone help?
The problem is that you're not restricting your proportions along both axes. Your box has a height:width proportion of 5:3. If you don't restrict along both axes, you can have bleeding outside of the boxes. An example might show this best.
Take the case of the height being the bigger of the two dimensions. Your code is only restricting it along the 500px axis. Consequently, if we throw a box in there with 5: >3 proportions, you get a creeping edge.
For instance, put "3" and "5" in your boxes. Fits perfectly. Now make it 3.1 and 5. Ruh roh.
You'll need to add another if statement in each section that THEN determines if the dimension ratio goes outside this boundary. In the above case, you'll need to make it so that the height of the 5:3.1 is not 500px, but rather, the height (less than 500px) that would make 3.1 to be equal to 300px. That would be 483px.
Does that makes sense?
If not, I'll try to rephrase again:
Put another set of if statements in the two if statements you already have. These check if, upon setting the LARGER dimension, it makes the SMALLER dimension go outside the bounds of the box in that direction.
in pseudocode
if (height > width)
calculate the height
calculate the width
if (width > div.width)
width = div.width
height = div.width * aspect;
Just ask me if this isn't clear enough!
Edit: Here's a JSFiddle that gets it right. You'll need to add further code if you want a white border along each edge.
Edit2: Here's the white border come back!
Edit3: You can also try prettying it up and using just aspects to do this. I did the first one for you. Three to go!
It's a pretty small mistake. You forgot to convert the width and height to integers before comparing them. So you would need to change if (width >= height) to if (parseInt(width) >= parseInt(height)).
jQuery .val() always return a string you should parse it into integer
changed jsfiddle
....
height = parseInt($('#height').val()) || 0;// making 0 as default value.
width = parseInt($('#width').val()) || 0;
....
Is there any way via jquery or javascript to make an element stretch its height to a certain set of numbers? I mean, as it accommodates more content, its height would only follow a pattern of numbers (multiples of a number).
Let's say in multiples of 100... a div's height as it extends taller would only be in this series -- 200px, 300px, 400px, etc. Hence, if it exceeds by just even 1 pixel off 200, it would automatically resize to 300.
It's hard to explain.
I need this because I made a vertically seamless pattern with torn edges and it would totally look perfect if it shows each tile completely.
I only know basic jquery and I don't have a bit of an idea on how to work this out.
My sincerest gratitude to whoever tends to my query!
var h = $('div').height();
$('div').height( Math.ceil(h/100) * 100 );
something like:
$('element').css({ height : (0|(targetHeight + 99) / 100) * 100 });
if you want it automatic:
$(function(){
var $elem = $('#element')
$elem.css({ height : (0|($(elem).height() + 99) / 100) * 100 });
});
This function will take the current height and the unit number you want it to snap to, rounding to the nearest multipleOf.
function snapHeight(height, multipleOf) {
return multipleOf * Math.round(height / multipleOf);
}
Examples:
snapHeight(930, 100); // returns 900
snapHeight(930, 50); // returns 950
$('#element').height(snapHeight($('#element').height(), 100)); // in jQuery