jQuery: Function bound to image's onload fetches old height() info - javascript

I've got a function bound (in the HTML) to an image's onload="". The function uses jQuery's height() method to find the height of the image, which is used to center it vertically. Code below.
The context is a slideshow of images with different dimesions, where the src="" of the <img> is changed as the user selects the next image. The bound function is successfully called every time the source changes, but the number it pulls with height() is old: that of the image before its source changed. In other words: When I start at the first image, the height() is right. When I go to the second the height is the same as before even though it should be different. When I go to the third image, the height is that of the second image. And so on. I know that it can fetch the height: If I call this function with another element's onclick once I'm sure the image has loaded, it works fine.
How can I make sure that the height() info my function grabs is current, i.e. that of the image as it is now? I know this isn't a problem with downloads or speed; I'm testing locally.
Many thanks in advance!
Code:
HTML for image:
<img class="slidePhoto" id="slideImage" src="img1.jpg" onload="centerImg()" />
Relevant part of JS for centerImg():
function centerImg(){
var offset = Number(($('#slideImage').height())/2*-1);
$('.slidePhoto').css({'top': '50%', 'margin-top': offset});
}

If the image source is changing with a button click, could you tie a jquery click event handler to the button to change the image, and then pull the height rather than trying to pull the height in the "onload" event of the image tag?
jQuery Click Event

I believe that since you've set the height explicitly on the element, that's what you're getting when you ask for the height the next time. A couple options:
(I'd try this) Create a new Image outside the DOM (var i = new Image(); i=src='...) and read the size from that (i.height). That should provide you with an accurate height (although some cross-browser testing will be necessary).
In your load function you could try setting the height to "auto" before measuring it. Not sure if this will help.
Just create a new <img> tag and replace the current one with this.
One of these should work.

You should use jQuery to setup the load event. I believe this is what you are looking for.
$('img.slidePhoto').load(function() {
var offset = $(this).height()/2*-1;
$(this).css({'top': '50%', 'margin-top': offset})
}
(FYI: That should go in your $(document).ready() method.)
See the jQuery documentation for the .load() method.

Related

How to detect when all images are loaded and elements are rendered at their appropriate heights

How can I check (with jquery or vanilla js) that all images on a page are loaded, and that they have been rendered at their final, full height, and that their parent elements have adjusted to that height?
I'm implementing a scrollspy function using jquery - something that determines where a user is on a page and highlights their position in a nav, updating their position as they scroll. In order for this to work properly, I need to know the offset.top of each section on the page I want to spy on. If I calculate the offset.top too early, before all images are loaded and displaying at their full height, the offset().top calculation will be incorrect. I want to avoid running the offset().top calculation too many times.
Things i've tried that don't fulfill my needs:
$(document).ready() and $(window).onload() are both too early, as images may not have been rendered at their full height, therefore making the sections not rendered at their full height.
the imagesLoaded library. same problem as above, doesn't account for rendering of images to their full height.
Based on my experience I think it's not trivial. window.onload may help, but it's not reliable when images are loaded dynamically. In the past I was using some kind of hack to make it workable. Basically, I was using window.setInterval and checking if image is really available by looking at property naturalWidth (see: https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement).
Here is an example of implementation: https://jsfiddle.net/yu8zr20h/
You are solving this issue in an incorrect way. You need to compare the current Y-value of the users window to the Y-value of all the components, or at least the containers containing the different nav values.
Imagine this is your html-code:
<div id="firstContainer">
<!-- Some content -->
</div>
<div id="secondContainer">
<!-- Some other content -->
</div>
Now you can check the height relative to the complete html page using
document.gelElementBtId('element-id').offsetTop
and the current height of the user using
scrollY
More information using this JSFiddle.
If you have image size metadata (e.g. Rails Active Storage provide it out of the box), you can write height to say dataset:
<img id="image" data-height="700" src="image.jpg" />
Then wait for it to be rendered (watch natural height):
let timer;
let image = document.getElementById("image");
function waitImage() {
if (image.naturalHeight < image.dataset.height) {
timer = setTimeout(function(){
showItems();
}, 300);
} else {
clearTimeout(timer);
useYourFullyRenderedImage();
}
}

In HTML/JavaScript, is there a way to know an images final layout dimensions the moment the image starts loading?

I have a script that examines elements and makes all the elements equal the height of the tallest element of the set. This works fine except for when images take a while to load, because by then the heights have already been set.
To overcome this I added an onload listener to the img tag and after the image has completely loaded, it resets the height of everything correctly.
Now the problem is, if there is a particularly large image, or slow connection, things still look strange while the image is downloading. Is there a way JavaScript can know the ultimate display height of the image at the BEGINNING of the download, rather than the end?
Something like this should work.
var bigImage = new Image();
bigImage.src = "path/to/image";
bigImage.onload = function() {
//create image tag with dimensions and insert into dom
console.log(bigImage.width, bigImage.height);
}

Update the margin of a div in relation to the height of a div that dynamically changes

I'm wondering if this is possible with jQuery or JS.
I have a margin set on a div that is set by getting the height of a container that contains images.
var articleImageHeight = $('.slides_control').height();
$('.individual-article-contents').css('margin-top', articleImageHeight);
However, the container's images are essentially a slider, so the height of this container can change.
I'm wondering if it's possible to update the articleImageHeight variable live as the height of the container changes?
I am using slidesJS for the slider in the container.
Here's an example of what I'm working on: http://goo.gl/FdftC
Many thanks,
R
What I would probably do for this is to add your snippet of script as a function and then to call that function every time the slide changes. This will mean you need to make a slight modification to the plugin. Having a look at the plug the main animate function is simply called animate().
So as a quick example
updateHeight = function(){
articleImageHeight = $('.slides_control').height();
$('.individual-article-contents').css('margin-top', articleImageHeight);
}
The above adds your bit to a function and then add updateHeight(); to line 236... if you're using the un-minified version of the plugin.
Just above the line that says } // end animate function
.. just a thought a what might look a bit nicer is to use .animate rather than .css for updating the top margin... but hey I don't know what you're working on so is entirely up to you.
----EDIT----
Just an update... we found an animateComplete() callback on the plugin which worked a charm.

Problems with Dynamic height and width images on mouseenter and mouseleave function

I am working on this image hover zoom part using jquery . The codes works fine , as the bigger image is showed on mouseenter and hides on mouseleave. since, the image showed on hover can have dynamic width and height(it depends on the image size..) i want to decrease the image width and height to 75% of the actual width and height.. even that is fine and it works..
now the problem i am facing is, whn mouse enters for second time, the image is reduced again.. third time it gets smaller than the second time... so eachtime mouse enters, image gets smaller and smaller...(which i think is obivous since each time mouseenters it reduces the image by 75%...) i have tried lots of things like creating a global variable, and checkin it.. if (first time) thn (reduce) else (reduce from the original image ).
BUT cannot make it work.. here is my code....
http://jsfiddle.net/ugnNU/11/
hoping for some advice. your help will be appreciated.
Thanks.
I tried to update your code as little as possible. Here is an example of how to do what I think you are trying to do. http://jsfiddle.net/ugnNU/12/
There are many many ways to get there, I chose this one because it came close to what you already had.
I added this:
var childImage = $(this).children("div.tooltip");
if (childImage.attr('saveWidth') == ""){
//we haven't saved it's height yet
childImage.attr('saveWidth', childImage.width());
childImage.attr('saveHeight', childImage.height());
}
var hoverImgWidth = childImage.attr('saveWidth');
var finalHoverImagewidth = hoverImgWidth * 0.75;
var hoverImgHeight = childImage.attr('saveHeight');
var finalHoverImageWidth = hoverImgHeight * 0.75;
Basically it just checks to see if we have already saved the 'tooltip' image height inside an attribute. If we have, it just uses that value. But if not, we save the height or width inside that attribute and then uses it.
I'm also only selecting ("div.tooltip") once and saving it in childImage. The reason for this is that each time you do this $(selector) jQuery has to go find that element. If you do this alot, it can impact performance. So it's good practice to just save your selector in a local variable.
http://jsfiddle.net/ugnNU/13/
It does not use a custom attribute. It just undoes in mouseleave, what you did in mouseenter
each time you call this code
var hoverImgWidth = $(this).children("div.tooltip").width();
var finalHoverImagewidth = hoverImgWidth * 0.75;
The width value of div.tooltip gets multiplied with 0.75.
The next time the code is executed this gets the current width (the lowered value) and lowers that again.
You could set the size back again when you hide it, but my advice would be to calculate the values on document ready and only show and hide the image with the mouseenter and mouseleave events.

How to detect when the height of your page changes?

I have a javascript heavy app which has widgets like autocomplete dropdowns and tabs and so forth. Sometimes when dropdowns appear and disappear, or when you switch between tabs, it changes the height of the document. This can cause annoyances if the scrollbar appears and disappears rapidly, because it shifts the page. I would like to detect when a page changes its height, so I can fix the height to the maximum so far, so that if the scrollbar appears it won't disappear only a second later. Any suggestions?
Update: onresize won't work because that's for changes in the size of the viewport/window - I want changes in the length of the document. I hadn't known about the watch function, looks like it will work at least for FF, but IE doesn't support it.
I belive this question has already been answered on stackoverflow here:
Detect Document Height Change
Basically you have to store the current document height and keep checking for a change via a timeoutcall
The element to watch here is document.body.clientHeight (or in jquery $(document).height() )
I think you can trap "onresize" events
here is a link to the w3schools.com description
You can user resize event to trap the change of the size of window using jquery as follows:
$(window).resize(function(){
// your code to check sizes and take action
}
);
Alternately you can track the change in document (not tested)
$(document).resize(function(){
// your code to check sizes and take action
}
);
One idea would be to use the watch() method on the clientHeight property:
document.body.watch("clientHeight", function(property, oldHeight, newHeight) {
// what you want to do when the height changes
});
The function you specify will get executed whenever the specified property changes. At any point you can use the unwatch() method to get it to stop.

Categories

Resources