I'm wondering if there is a way to detect load event of multiple images (particularly, a function should execute when the last image in a given set has completed loading).
For instance, an user clicks on a link and lighbox appears with 10 images. When all images have loaded, loading bar should disappear.
jQuery(".lightbox-image").each(function(){
var image = jQuery(this);
jQuery('<img />').attr('src', image.attr('src')).load(function(){
hideLoadingBar();
});
});
This unfortunately triggers hideLoadingBar(); too early (after one image has completed loading).
P.S.
I also need my function to work after images have been cached so: jQuery('#img1, #img2').load(); won't work.
Check out this jQuery imagesLoaded plugin, it should suit your needs I think.
Well, it seems that no one has better idea, so below is my solution/workaround. The other answer to this question is probably what you want to use because it's a library created specifically for that but here's the solution that I'm going to use because it's shorter and simple:
var allImages = jQuery(".lightbox-image").length;
var counter = 0;
jQuery(".lightbox-image").each(function(){
var image = jQuery(this).find('.myimage');
jQuery('<img />').attr('src', image.attr('src')).load(function(){
counter++;
if(counter >= allImages){
hideLoadingBar();
}
});
});
Works for cached images and not cached images.
Related
I inherited a project where a page is loaded, then code attached to that page fills in a div with dynamically generated html - it basically fills an existing div with a html string.
This string contains links to images, etc.
I want to tell when all the images, etc have loaded- I cannot seem to get any jQuery standard checks
to work - ie I have tried attaching $(window).load() after the dynamic stuff has been inserted.
I am wondering if I should write $(window).load() dynamically as well, or if there is any other
method- ie $("#thediv").load (doesn't seem to work. I cannot query all the new html for image tags, etc-
too much stuff is being put in.
The $(window).load() doesn't work for dynamic content as far as I know. You can use the .load event for each image separated. Here's an example:
var container = $("<div> ... Stuff ... </div>");
var images = container.find('img');
var imageIdx = 0;
images.load(function(){
imageIdx++;
if (imageIdx == images.length){
callback();
}
});
Where callback() is the function that runs after all images where loaded.
From my comment: window load applies to the initial page load only. Not dynamic loading of content within it. Attach load handlers to each loaded image element and count them.
This is the shortest version I could come up with for you:
// After HTML load finishes
var img = 0;
var imgCount = $("#thediv img").load(function(){
if (++img == imgCount){
// We are done loading all images!
}
}).length;
$(window).ready() only applies to the content within the HTML file and you can only use load to attach an onload event handler to a specific image (not a container), something like this might work for you.
window.ImageLoadHandled = false;
window.ImageLoadCount = 0;
function ImageLoadHandler() {
// guard against calling this function twice
if(window.ImageLoadHandled) return;
window.ImageLoadHandled = true;
// All images have loaded || timeout expired...
}
$("#myAjaxedDiv img").load( function() {
window.ImageLoadCount++;
if( window.ImageLoadCount == $("#myAjaxedDiv img").length ) {
// all images in #myAjaxedDiv have loaded
ImageLoadHandler();
}
});
// if images haven't loaded after 5 seconds, call the code
setTimeout( ImageLoadHandler, 5000 )
The only problem with this is that if an image fails to load for whatever reason, the code will never be hit, which is quite risky. To counteract this I'd recommend creating a setTimeout() method to call your code after a few seconds timeout in-case there is a problem loading images (client or server side) and I've also taken #TrueBlueAussie's correction into account in the edit.
Your alternative is to preload the images with your HTML page
Problem- I am displaying some images on a page which are being served by some proxy server. In each page I am displaying 30 images ( 6 rows - 5 in each row). Here if due to overload or due to any other issue if proxy server could not able to server images( either all images or some of them) in 6 seconds then I want to replace unloaded image url with some other url using javascript so that I could display 30 images at the end.
What I tried is below.
objImg = new Image();
objImg.src = 'http://www.menucool.com/slider/prod/image-slider-4.jpg';
if(!objImg.complete)
{
alert('image not loaded');
}else{
img.src = 'http://www.menucool.com/slider/prod/image-slider-4.jpg';
}
I also tried with below code.
$('img[id^="picThumbImg_"]').each(function(){
if($(this).load()) {
//it will display loaded image id's to console
window.console.log($(this).attr('id'));
}
});
I could not use set time-out for each image because it will delay all page load.
I checked other similar question on stack-overflow but no solution worked me perfectly as I need to display multiple images.Please guide how to proceed.
You don't have to wait 6 seconds, or using TimeOut. You can check if the images are loaded or not using the onload Javascript/Jquery event. I know, it will take a little bit to dispatch the onerror event, let see:
Why don't use the load Jquery event on the window or the image itself?
$(window).load(function(){
//check each image
})
Disadvantage:
It will wait for other resources like scripts, stylesheets & flash, and not just images, which may or may not be OK to you.
If the image loads from the cache, some browsers may not fire off the event (included yours and that's why your code is not working)
Why don't use the error Jquery event on the image itself?
$('img[id^="picThumbImg_"]').error(function(){
//image loading error
})
Disadvantages:
It doesn't work consistently nor reliably cross-browser
It doesn't fire correctly in WebKit if the image src is set to the same src as before
It doesn't correctly bubble up the DOM tree
Can cease to fire for images that already live in the browser's cache
Note:: Error is almost the same that the load event
Improving the code!:
$('img[id^="picThumbImg_"]').one('error', function() {
// image load error
}).each(function() {
if(!this.complete) $(this).error();
});
This will avoid few things of the previous code, but you still will have to wait if it's a 404 and you're replacing it in the onerror event, that will take a little bit right?
So, what now!
You can use this awesome plugin!. Once you add the reference, you just have to use something like:
var imgLoad = imagesLoaded('#img-container');
imgLoad.on( 'always', function() {
// detect which image is broken
for ( var i = 0, len = imgLoad.images.length; i < len; i++ ) {
if(!imgLoad.images[i].isLoaded){
//changing the src
imgLoad.images[i].img.src = imgLoad.images[i].img.getAttribute("data-src2");
}
}
});
Your HTML markup should look like:
<div id="img-container">
<div class="row">
...
</div>
<div class="row">
<img src="original-path.jpg" data-src2="alternative-path.jpg">
...
</div>
<div class="row">
...
</div>
</div>
Note: You don't need jQuery in this case and this plugin is suggested by Paul Irish ;)
Give all your images a specific class. Loop through your images and use .load() to check if loaded, example below...
Detect image load
I have run into numerous sites that use a delay in loading images one after the other and am wondering how to do the same.
So i have a portfolio page with a number of images 3 rows of 4, what i want to happen is for the page to load,except for the images in img tags. Once the page has loaded i want images 1 of each row to load then say 0.5 seconds later the next image in the row(s) and so no. I'm going to have a loading gif in each image box prior to the actual image being displayed.
I know its doable but cant seem to find the term for doing this. This is purely for looks as it is a design site.
Thanks for the help.
This is very easy to do in jQuery
$('img').each(function(i) {
$(this).delay((i + 1) * 500).fadeIn();
});
Fiddle: http://jsfiddle.net/garreh/Svs7p/3
For fading in rows one after the other in a table it just means changing the selector slightly. Remember to change from div to img -- I just used div for testing
$('tr').each(function(i) {
$('td div', this).delay((i + 1) * 500).fadeIn();
});
Fiddle: http://jsfiddle.net/garreh/2Fg8S/
Here is what you can do, you can load the image tags with out the src and using a custom property:
<img alt='The image' path='image/path.jpg' />
then you can use javascript to load the images when the site is loaded or whenever you please;
// simplified
window.onload = function () {
var images = document.getElementsByTagName('img');
// loop and assign the correct
for (var i =0; i < images.length;i++){
var path = images[i].getAttribute('path');
images[i].src = path;
}
}
I hope you get the concept of how the images are delayed
**please note the path attribute is not a standard one.
The easiest way I can think to do this is to have a table set up that will eventually hold the image tags, but have none on load. Javascript can loop through an array of image urls, and insert those image tags into random locations on the table.
If you want to have the delay, setInterval is the perfect tool. http://www.w3schools.com/jsref/met_win_setinterval.asp
// You can hard-code your image url's here, or better still, write
// a server-side script that will read a directory and return them
// so it is fully dynamic and you can add images without changing code
unpickedImages = array();
// Start loading
loadAllImages = setInterval( insertImage, 600 );
function insertImage() {
if( unpickedImages.length > 0 ) {
var imageUrl = unpickedImages.shift();
// pick empty x, y on your table
// Insert the image tag im that <td></td>
} else {
clearInterval( loadAllImages );
}
}
You really don't need javascript to do this. If you specify the image sizes in the HTML or CSS, the browser will layout and display the page while loading the images, which will likely be loaded in parallel. It will then display them as soon as it can.
That way if users re-visit your site and have the images cached, they all show up immediately. If you have a script to load the images after a delay, you are making visitors wait for content unnecessarily and all their efforts to have a faster browser and pay for a fast internet connection has gone to waste.
i have certain links, on mouse over of those links I am changing <div> background image
jQuery I have used is-
function imgchange()
{
$('.smenu li').mouseover( function(){
var src = $(this).find('a').attr('href');
$('.hbg').css('background-image', 'url(' + src + ')');
$(this).find('hbg').attr('title', 'my tootip info');
});
}
It is working fine but the problem is when I running it on server images takes 3-4 sec to be changed on change, but the second time I do mouse over images are getting changed instantly, I think this is because of browser stored images in cache. So I added one javascript to preload images on page onLoad() ivent -
<script language = "JavaScript">
function preloader()
{
heavyImage = new Image();
heavyImage.src = "images/soluinfo1.jpg";
heavyImage.src = "images/soluinfo2.jpg";
heavyImage.src = "images/soluinfo3.jpg";
heavyImage.src = "images/soluinfo4.jpg";
heavyImage.src = "images/soluinfo5.jpg";
heavyImage.src = "images/soluinfo6.jpg";
heavyImage.src = "images/soluinfo7.jpg";
}
</script>
<body onLoad="javascript:preloader()">
but this script has not solved my problem.what should I do?
#Richard's answer (sprites) is probably the best one for what you are after, but the reason your code is not working is that in most browsers, only the last heavyImage.src="" is given enough time to actually register with the browser as an actual request. You're creating only one Image object setting and resetting the .src attribute faster than the browser can request the files (I think modern JavaScript engines take the added step of removing all the intermediate .src statements specifically because of this).
There are a couple of ways to fix this. The easiest is to create multiple Image objects, one for each image. And the easiest way to do that is through something like this:
<script type="text/javascript">
function preloader()
{
function doPreload(strImagePath)
{
var heavyImage = new Image();
heavyImage.src = strImagePath;
}
var arrImages = ["images/soluinfo1.jpg","images/soluinfo2.jpg","images/soluinfo3.jpg","images/soluinfo4.jpg","images/soluinfo5.jpg","images/soluinfo6.jpg","images/soluinfo7.jpg"];
for (var i = 0; i < arrImages.length; i++) {
doPreload(arrImages[i]);
}
}
</script>
By putting the heavyImage variable inside its own function (remember to use the var keyword), you're ensuring that the Image object exists inside its own dedicated scope.
Another way to do this is to attach a "load" event listener to a single heavyImage. Every time the image finishes loading, go fetch the next image. The disadvantage to this method is that your images will be loaded one at a time (bad for navigation images, but great for, say, and image gallery), whereas the first technique will fetch the images in parallel (typicallly four at a time).
You might find it easier to change your approach and use CSS sprites (and another article). Then you would just have one image referenced, and you use CSS to set which part of that image gets shown in which scenario.
This assumes that the images you're using are under your control and you can use an image editor to combine them into one large image.
I'm currently working on a web application which has a page which displays a single chart (a .png image). On another part of this page there are a set of links which, when clicked, the entire page reloads and looks exactly the same as before except for the chart in the middle of the page.
What I want to do is when a link is clicked on a page just the chart on the page is changed. This will speed things up tremendously as the page is roughly 100kb large, and don't really want to reload the entire page just to display this.
I've been doing this via JavaScript, which works so far, using the following code
document.getElementById('chart').src = '/charts/10.png';
The problem is that when the user clicks on the link, it may take a couple of seconds before the chart changes. This makes the user think that their click hasn't done anything, or that the system is slow to respond.
What I want to happen is display a spinner / throbber / status indicator, in place of where the image is while it is loading, so when the user clicks the link they know at least the system has taken their input and is doing something about it.
I've tried a few suggestions, even using a psudo time out to show a spinner, and then flick back to the image.
A good suggestion I've had is to use the following
<img src="/charts/10.png" lowsrc="/spinner.gif"/>
Which would be ideal, except the spinner is significantly smaller than the chart which is being displayed.
Any other ideas?
I've used something like this to preload an image and then automatically call back to my javascript when the image is finished loading. You want to check complete before you setup the callback because the image may already be cached and it may not call your callback.
function PreloadImage(imgSrc, callback){
var objImagePreloader = new Image();
objImagePreloader.src = imgSrc;
if(objImagePreloader.complete){
callback();
objImagePreloader.onload=function(){};
}
else{
objImagePreloader.onload = function() {
callback();
// clear onLoad, IE behaves irratically with animated gifs otherwise
objImagePreloader.onload=function(){};
}
}
}
You could show a static image that gives the optical illusion of a spinny-wheel, like these.
Using the load() method of jQuery, it is easily possible to do something as soon as an image is loaded:
$('img.example').load(function() {
$('#spinner').fadeOut();
});
See: http://api.jquery.com/load-event/
Use the power of the setTimeout() function (More info) - this allows you set a timer to trigger a function call in the future, and calling it won't block execution of the current / other functions (async.).
Position a div containing the spinner above the chart image, with it's css display attribute set to none:
<div> <img src="spinner.gif" id="spinnerImg" style="display: none;" /></div>
The nbsp stop the div collapsing when the spinner is hidden. Without it, when you toggle display of the spinner, your layout will "twitch"
function chartOnClick() {
//How long to show the spinner for in ms (eg 3 seconds)
var spinnerShowTime = 3000
//Show the spinner
document.getElementById('spinnerImg').style.display = "";
//Change the chart src
document.getElementById('chart').src = '/charts/10.png';
//Set the timeout on the spinner
setTimeout("hideSpinner()", spinnerShowTime);
}
function hideSpinner() {
document.getElementById('spinnerImg').style.display = "none";
}
Use CSS to set the loading animation as a centered background-image for the image's container.
Then when loading the new large image, first set the src to a preloaded transparent 1 pixel gif.
e.g.
document.getElementById('mainimg').src = '/images/1pix.gif';
document.getElementById('mainimg').src = '/images/large_image.jpg';
While the large_image.jpg is loading, the background will show through the 1pix transparent gif.
Building on Ed's answer, I would prefer to see something like:
function PreLoadImage( srcURL, callback, errorCallback ) {
var thePic = new Image();
thePic.onload = function() {
callback();
thePic.onload = function(){};
}
thePic.onerror = function() {
errorCallback();
}
thePic.src = srcURL;
}
Your callback can display the image in its proper place and dispose/hide of a spinner, and the errorCallback prevents your page from "beachballing". All event driven, no timers or polling, plus you don't have to add the additional if statements to check if the image completed loading while you where setting up your events - since they're set up beforehand they'll trigger regardless of how quickly the images loads.
Some time ago I have written a jQuery plugin which handles displaying a spinner automatically http://denysonique.github.com/imgPreload/
Looking in to its source code should help you with detecting when to display the spinner and with displaying it in the centre of the loaded image.
I like #duddle's jquery method but find that load() isn't always called (such as when the image is retrieved from cache in IE). I use this version instead:
$('img.example').one('load', function() {
$('#spinner').remove();
}).each(function() {
if(this.complete) {
$(this).trigger('load');
}
});
This calls load at most one time and immediately if it's already completed loading.
put the spinner in a div the same size as the chart, you know the height and width so you can use relative positioning to center it correctly.
Aside from the lowsrc option, I've also used a background-image on the img's container.
Be aware that the callback function is also called if the image src doesn't exist (http 404 error). To avoid this you can check the width of the image, like:
if(this.width == 0) return false;
#iAn's solution looks good to me. The only thing I'd change is instead of using setTimeout, I'd try and hook into the images 'Load' event. This way, if the image takes longer than 3 seconds to download, you'll still get the spinner.
On the other hand, if it takes less time to download, you'll get the spinner for less than 3 seconds.
I would add some random digits to avoid the browser cache.