Having a bit of an issue please see the following code:
window.onload = function () {
var imgHeight = $("#profile_img").height();
var infoPanels = imgHeight - 6;
//include borders and margin etc..
var infoPanelsHeight = infoPanels / 4;
$('.resize').css("height",infoPanelsHeight + "px");
$('.resize2').css("height",infoPanelsHeight + "px");
}
What i’m trying to do is find the height of an image (floated:left), then divide it by 4 and use the outcome to set the height of 4 divs (floated:right), so they equal the height of the image in total.
I’m using this on a resizing project of mine but because the image height depends on the viewing window (in this case a mobile screen), the number is very rarely rounded up correctly so the divs are always out by 1-4 px.
So for a work around I want to find the height of the image, then if the height isn’t dividable by 4 adjust so it is... resize the image then resize the divs using the new image height.
So my question is how do i check the height of the image, if it isn’t dividable by 4 then make it so it is?
I’m using jquery and javascript generally.
Thanks for your help in advance.
Sam Tassell.
I would try:
if (imgHeight % 4 != 0) { // checks if the imgHeight is not dividable by 4
$("#profile_img").attr("height") = Math.floor(imgHeight / 4) * 4; // set lowest height that is dividable by 4
}
Note:
The image may become a little blurry because the result depends on your browser capabilities.
% is called modulus operator
You need the mod operator %:
imgHeight % 4
if the result is not '0' then you know imgHeight is not divisible by 4.
Related
I'm still wet behind the ears with web dev, not the best at math, and have problems moving on when something is still broken. Hopefully you guys can help.
Quick: I'm using Jquery to make some (dynamic in number) divs in my header overlap by 30%, filling the entire width of the container. My current iteration rounds up one too many times, so my last element goes beneath the rest.
I have X elements filling the full width of my header container. Each element overlaps by 30% on either side. In an equation, I can work out the math no problem. Ensuring pixel precision with these numbers has proven more difficult. This is what I'm using to determine the width of each element.
width of element = [container width] / ((.7 * ([# of elements] - 1)) + 1)
left margin of element = [width of element] * .3
I make variables I call extraWidth and extraMargin which are the width and margin % 1 respectively. The default element width I use now is width-(width%1). For every element, I add the extraWidth and extraMargin to running total variables. Any time the total of either of these variables exceeds .5, that particular element has its width or margin set 1 higher than the default.
So I don't run on any longer, here's a JSFiddle with everything necessary to see what I'm dealing with. It runs fine most of the time, but at certain widths I'm 1 pixel too wide.
p.s.
Ran the JSFiddle, didn't work the same way as my live sandbox site, so check that out here. I feel like I included all the necessary bits, but I can't say for sure. On my Chrome, when window size is 575px (among many other widths) it's messed up.
EDIT
It should be noted that I'm making changes to my live site without updating this post. I'm not deleting any functions just yet though, just making new ones/minor alterations to existing ones.
Recursion! Recursion was the most elegant answer (which appears to work in ALL cases) I could come up with.
Iterating through my jQuery object one element at a time and calculating the width and margin based on the remaining container width rather than the whole container width makes this much easier to calculate.
function circleWidth(circles, containerWidth) {
var width = containerWidth / ((.7 * (circles.length - 1)) + 1);
var pxWidth = Math.round(width);
var margin = width * .3;
var pxMargin = Math.round(margin);
$(circles[0]).css({
'width': pxWidth + "px",
'margin-left': "-" + pxMargin + "px"
});
containerWidth -= (pxWidth - pxMargin);
if (circles.length > 1) {
circleWidth(circles.slice(1), containerWidth);
}
}
function circleSize(circles, containerWidth) {
var height = Math.ceil(containerWidth / ((.7 * (circles.length - 1)) + 1));
circles.each(function() {
$(this).css({
'height': height + "px"
});
});
circleWidth(circles, containerWidth);
$(circles[circles.length]).css({
'margin-left': $(circles[0]).css('margin-left')
});
$(circles[0]).css({
'margin-left': 0
});
}
Here's the fiddle with my final result. I'm sure I still have some optimization to do, but at least it's working now.
You have 2 choices:
Calculate pixelMargin as next integer. like:
var pixelMargin = Math.ceil(circleMargin);
or you can use pixelMargin in %.
1st one worked for me.
I have created this jsFiddle:
https://jsfiddle.net/j994tnu2/4/
if(textH < (parentH - deviation) || textH > (parentH + deviation)) {
text.style.transform = "scale(1, " + frameScale + ')';
//alert("transform");
}
https://jsfiddle.net/j994tnu2/5/
if(textH < (parentH - deviation) || textH > (parentH + deviation)) {
//text.style.transform = "scale(1, " + frameScale + ')';
//alert("transform");
}
Version 4 has 1 line uncommented which allows for a tranform: scale() of the div directly containing the text.
Version 5 has this 1 line commented which disallows this to happen.
My concern is that the way I've coded the text to resize is...
textScale1 = 0.78;
textScale2 = 1;
textScale3 = 1.4;
//textScale4 = fontSize2 / fontSize;
//applies the master frameScale once to a single style of a class
fontSize2 = Math.round(10 * fontSize2 * frameScale) / 10;
//uses the relative textScales to this element to style the rest
fontSize = Math.round(10 * fontSize2 / textScale1) / 10;
lineH = fontSize;
margin = Math.round(10 * fontSize2 / textScale2) / 10;
lineH2 = fontSize2;
margin2 = Math.round(10 * fontSize2 / textScale3) / 10;
by manually checking the font-size and margins of every element and changing them to a scale both relative to themselves in the text AND relative to the outer div container size. This is actually the good part which makes the text stay true to itself relative to the original format. However,
The problem I have is the difference between the onload = function and the addEventListener(resize, function). They are coded exactly the same but have "different" results.
If you resize the window you'll see that after about 3 resizes, the text fits the container on an absolute font-size level much more closely and has much less (or none at all) transform: scale() stretching or squashing.
But every time the onload = function gets called, the text will always be way too big or small for the container and will always get stretched or squashed by an unacceptable amount.
How can I code this up to make the font-sizes in the onload = function be true to the starting outer div height?
Thanks for looking into it.
EDIT: It's interesting. Commenting out the onload=function and letting the resize function do the first resize, you will get the exact same result of the onload=function. Which, consistency is good. But why does subsequent resizing increase the accuracy of the font-sizes? Even if I resize up and then back down to near the same spot the text will look less squished and more true to its proportions. The initial resize sucks. Why? How is it possible that it gains in accuracy over time?
So I've kept working at it and saw that the ratio of the outer text div to the inner text div (frameScale in the jsFiddle) would determine the percent deviation at the end. This is what I mean:
However far from 1.0, that frameScale would deviate would determine according to some odd exponential function how far the resultant frameScale was from 1. So if you started from 1 (meaning the outer text div was just as large as the inner text div) then the resultant ratio would also be one. If it was 1.3 then the ratio plummeted to 0.84. If it was 1.6 then it went to 0.72. If it was 2.00 then it went to 0.5 and so on. I couldn't figure it out so I decided to do a workaround.
If resizing it multiple times made the font-sizes more true then I decided to just resize it with the resizeListener function I was already calling. All I needed to do was resize to the grandparent element in the first part of the function and then resize to the parent element in the second part. The one kicker was that the grandparent-to-child height ratio could not be the same as the frameScale (parent-to-child). So I did this:
if(masterScale = frameScale) {
masterScale = masterScale - 0.5;
}
For whatever reason, 0.5 seems to work well. Maybe this will fail in many different situations but for now it's a good workaround. All I did was resize the container twice. Here is the jsFiddle:
https://jsfiddle.net/j994tnu2/6/
EDIT: This doesn't answer the question though. Why is the beginning frameScale's deviation from 1 determine increasing deviations from 1 after the transformation? If I wanted it perfect I could create an if() else if() tower adjusting for this all the way up to some ratio that wouldn't occur naturally:
1.0-1.04 >>> 1.0
1.05-1.29 >>> 0.94
1.3-1.34 >>> 0.84
1.35-1.6 >>> 0.8
1.61-??? >>> 0.7
1.99-??? >>> 0.49
For whatever reason, subtracting the amount needed to make 1.0 for the resultant ratio from the beginning ratio will adjust the resultant ratio to 1; which doesn't make sense. Here is a jsFiddle doing this very thing and with much better results than resizing to the grandparent element:
https://jsfiddle.net/j994tnu2/9/
I've got a Javascript curiosity that I must satisfy. Before I begin I should let you know that I am very aware of the fact that this can be handled with CSS alone, but I want to improve my Javascript skills so humor me :)
For reference to what I'm trying to get at: http://codepen.io/cmegown/pen/CGhpa
Let say we have a potentially infinite number of images, each wrapped inside of a figure set to display: inline-block so that it is the same size as the image inside. Each of these images can be any dimension, and the desired result is that the bottom of every image is perfectly aligned. The kicker here is that this is responsive, so the images may scale up or down. Here's my thinking of how this might be accomplished:
Loop through every image and find the tallest one (outerHeight), then grab that same image's width (outerWidth). Subtract the outerWidth from the outerHeight to get the "master" difference. Loop again through each image to calculate the difference for each specific image and subtract that from the "master" difference, then apply that number to the top margin. Rinse and repeat until each image is aligned to the bottom of the tallest image.
Right? I think the logic is sound, I just lack the skills to put this together properly in Javascript. Sorry for the super long post, but any and all help/advice is appreciated!
function alignImages() {
// caching selectors
var imgs = document.getElementsByTagName('img'),
maxHeight = 0;
for (idx in imgs) {
var img = imgs[idx];
if (img.height > maxHeight) {
maxHeight = img.height;
}
}
for (idx in imgs) {
var img = imgs[idx];
img.style.marginTop = (maxHeight - img.height) + "px";
}
}
I need to take a percentage value, convert it to pixels and move a div upwards using JQuery animate for a progress bar I'm trying to build. The div containing the graphic that needs to move upwards has a 268 pixel height (so that is our 100%).
as an example, I put 38% as the starting percentage value that I need to convert to a pixel value and move div with the id prog_anim to that number of pixels upwards (should be around 101 pixels)
var result = 38 / 100 * 268;
function bgr_animate(result) {
$('#prog_anim').animate({
'marginTop' : result
});
}
and then I have the following link on a button that performs the action:
a href="javascript:;" onclick="bgr_animate(result)"
being a total Javascript noob I have no idea where the above syntax is wrong. Can anyone correct me here? Thanks!
I see a few areas for improvement.
Instead of hardcoding 268, use var graphicHeight = $("#prog_anim").outerHeight();.
You'll need to reverse the direction of the margin top since you want it to move up. marginTop is one way to do that, but setting a CSS position: absolute; and using top instead of marginTop would be better.
So:
var result = -(38 / 100 * graphicHeight);
Try this:
function bgr_animate(percent, height) {
var pixels = percent / 100 * height;
$('#prog_anim').animate({
'marginTop' : pixels
});
}
And your button;
<a href="javascript:;" onclick="bgr_animate(30, 268)">
Try this out
$('#prog_anim').animate({
height: result
top:-=resultInc
}, 5000, function() {
alert("Animated");
});
Where resultInc is the number of pixels by which it grows
Using this you can move upwards and increase the height downwards giving the impression that it grew upwards
I have the following function for calculating the height of .node. It then takes away the height of a possible image, .node-image, from the height of the .node, and sets a column, .node-content-column to have a height that is the difference (i.e. 500 - 50 = 450; column becomes 450 in height).
function initColumnSizer() {
imageHeight = $('.node-image').outerHeight(true);
resizeHeight = ($('.node').outerHeight() + 75) - imageHeight;
$('.node-content-column').removeAttr('style');
$('.node-content-column').css('min-height', resizeHeight);
$('.node-content-column').css('height', 'auto !important');
$('.node-content-column').css('height', resizeHeight);
}
This function gets called on page load, and resizes .node-content-column as expected.
It also gets called when a div within .node is toggled using jQuery.toggle(), but this calculation returns a larger number everytime, instead of reverting back to the original once this toggle is reverted.
Can anyone see where I am going wrong with this calculation? Or if I am going about it the wrong way?
Thanks in advance!
Karl
1) Maybe the problem is in outerHeight() function (it takes into account padding and border). Try using just height or clientHeight:
var img = document.getElementById('imageid');
//or however you get a handle to the IMG
var width = img.clientWidth;
var height = img.clientHeight;
2) why do you need to cleanup the whole elements' style?
and then you try to assign height = auto, and after that: height = resizeHeight - what's the purpose for that ? check the logic of your code.
outerHeight(true) will return height + padding + border + margin. Possibly, you might want to use height() ?
Most possible is that "larger number everytime" have always constant difference -- for example 75.
May be you just have some dependecies between .node-content-column and .node?
If your nodes like .node-content-column, .node and .node-image are all singles, then it's better to use IDs for them -- not CSS classes.