I have a photo gallery web page where a single <img src="XXX" /> element's src is changed (on a click) with JavaScript to show the next image—a poor man's ajax I guess. Works great on faster connections when the new image appears almost immediately. Even if it takes a few seconds to load, every browser I've tested it on keeps the old image in place until the new one is completely loaded.
It's a little confusing waiting those few seconds on a slow connection, though, and I'm wondering if there's some JavaScript event that fires when the new image is done loading, allowing me to put a little working... animated gif or something up in the meantime.
I know I could use AJAX for real (I'm using jQuery already), but this is such a nice and simple solution. Besides this lag, is there any other reason I should stay away from this approach to changing images?
You can set up a handler on the "load" event.
$('img.whatever')
.load(function() { /* do stuff */ })
.attr('src', newURL);
Actually I guess you'd want to do this with "live()":
$('img.reloadable').live('load', function() { $(this).show(); });
// ...
$('img#someId').hide().attr('src', newURL);
edit — whoa, where did that year go? Well, it turns out that one problem with that "live" approach I typed in way back when is that the "load" event does not bubble. Now what you can do, however, is leverage the way that "Image" objects (as opposed to <img> DOM elements) behave. Basically, the function that changes the URL can use an "Image" element as the place to keep the handler. The code that changes the actual "src" attribute of the real <img> tag would then also update the "src" of the "Image" object instance. The browser will only really load the image once (assuming cache control is all cool), but the browser will still call the "onload" handler of the "Image":
(function() {
var imageObj = new Image();
imageObj.onload = function() {
// code to run when image loads from server
};
$('#hypotheticalButton').click(function() {
$('#imgToUpdate').attr('src', newURL);
imageObj.src = newURL;
});
})();
You just just preload the images with jQuery so that way when the user clicks, the next image is already loaded and there shouldn't be a delay...that is unless the user goes to your page, and starts clicking on the image before they are loaded.
http://engineeredweb.com/blog/09/12/preloading-images-jquery-and-javascript
var slideimg = $('#slideimage');
slideimg.click(function(){
var img = new Image();
var url = 'url_to_next_image.jpg';
$(img).bind('load',function(){
$('#loading').hide();
slideimg.attr('src',url);
}).attr('src',url);
$('#loading').show();
});
This should work even with IE's crazy cache handling.
Related
I have a function where I get the img src value as the parameter, what I want to do is check to see if that image loads with a 200 ok or 404/some other error. If it gets a 200 ok, then I want to inject an img tag with that src into the DOM(I reason that during checking,it also gets loaded into the browser cache and injecting that img tag into the DOM loads it from the cache ). I tried with a simple snippet of code as follows :
function checkImage(src)
{
var img = new Image(),
tag = '<img src="'+src+'" />',
alt = '<span>sorry,image broken</span>';
img.onload = function(){
$('.some-container').html(tag);
};
img.onerror = function(){
$('.some-container').html(alt);
};
img.src = src;
}
It worked fine in chrome, but went havok in firefox and ie(both of them are firing only the error event no matter whether the image loaded fine or broke). Instead of using onload and onerror, I tried it using jquery like :
$(img).load(...).error(...).attr('src',url);
$(img).on('load',...).on('error',...).attr('src',url);
$('<img />').load(...).error(...).attr('src',url);
$('<img />').on('load',...).on('error',...).attr('src',url);
and even tried the jquery.imagesLoaded plugin by desandro(https://github.com/desandro/imagesloaded) like :
$(img).imagesLoaded().done(...).fail(...);
$(img).imagesLoaded().progress(function(instance,image){
image.isLoaded?alert('loaded'):alert('broken');
});
$('<img />').imagesLoaded().done(...).fail(...).attr('src',url);
$('<img />').imagesLoaded().progress(function(instance,image){
image.isLoaded?alert('loaded'):alert('broken');
});
I also tried the solutions from :
jQuery callback on image load (even when the image is cached)
https://groups.google.com/forum/#!topic/jquery-dev/7uarey2lDh8
but as it turns out, works in chrome, but not in FF or IE, is there any solution where I can check for an image which is present in memory but not in the "DOM" ? Thanks in advance.
You have to check for image onload after setting a source to it.
var img = new Image();
//set source to the image
img.src = "set/image/source/path"
img.onload = function(){
//if image load is successful
//create an jQuery object out of this image
var jQimage = $(this);
$('.myContainer').html(jQimage);
}
Also note that jQuery load function cannot guarantee you a cross browser check for image loading as mentioned in jQuery docs
So, the best approach is to check onload with native javascript and create an jQuery object if necessary to make use of jQuery methods.
Have a look at what w3schools has to say about the Image() javascript object.
http://www.w3schools.com/jsref/dom_obj_image.asp
onabort - Loading of an image is interrupted, W3C YES
onerror - An error occurs when loading an image, W3C YES
onload - An image is finished loading, W3C YES
also the complete property of the Image() object, determines if the browser is finished loading an image, Unfortunately this particular property is not W3c
hope that helps a little
PS: After having a little Google search I found this Q/A from Stack overflow.
Cross-browser image onload event handling
Is there any way without AJAX of changing the loading order of images on a page? Or even a way to completely halt or pause loading of images already present?
The use case is simple - I have a long list of images down a page, and visitors will be landing on different spots of the page using URL anchors (/images#middle-of-page) that refer to actual containers for those images.
I'd like in the least to load the images inside the requested container FIRST, then continue loading the rest of the images.
The challenge is that there is no way to know the image paths of the requested container image before loading the page DOM.
I've tried getting the container img contents on load, then using the Javascript new Image() technique, but it doesn't change the fact that that image on the page will still be waiting for all previous images to load.
I've also tried immediately prepending a div in the body with a background image (CSS) of said img path, but this also does not prioritize the image load.
Any other ideas?
You need to have a DOM with empty img placeholders, i.e.
<img src="" mysrc="[real image url here]" />
Or you can make images to display "Loading..." image by default. You can even cache real image url in some custom tag, mysrc for example. Then once you know what exactly images you want to show (and in what order) you need to build a sequence of image loading
var images = [];//array of images to show from start and in proper order
function step(i){
var img = images[i++];
img.onload = function(){
step(i);
}
img.src = "[some url here]"
}
Hope this helps.
For interest, this is the function I ended up implementing based on the answers here (I made it an on-demand loading function for optimum speed):
function loadImage(img) { // NEED ALTERNATE METHOD FOR USERS w/o JAVASCRIPT! Otherwise, they won't see any images.
//var img = new Image(); // Use only if constructing new <img> element
var src = img.attr('alt'); // Find stored img path in 'alt' element
if(src != 'loaded') {
img
.load(function() {
$(this).css('visibility','visible').hide().fadeIn(200); // Hide image until loaded, then fade in
$(this).parents('div:first').css('background','none'); // Remove background ajax spinner
$(this).attr('alt', 'loaded'); // Skip this function next time
// alert('Done loading!');
})
.error(function() {
alert("Couldn't load image! Please contact an administrator.");
$(this).parents('div:first').find("a").prepend("<p>We couldn't find the image, but you can try clicking here to view the image(s).</p>");
$(this).parents('div:first').css('background','none');
})
.attr('src', src);
}
}
The img loading="lazy" attribute now provides a great way to implement this.
With it, images load automatically only when on the viewport. But you can also force them to load by setting in the JavaScript:
document.getElementById('myimg').loading = 'eager';
I have provided a full runnable example at: How do you make images load lazily only when they are in the viewport?
One really cool thing about this method is that it is fully SEO friendly, since the src= attribute contains the image source as usual, see also: Lazy image loading with semantic markup
I'm loading an image onto a texture map with GLGE (sorta like webGl). However for the sake of loading speed I'm loading a low resolution image first (which would be quicker) and then want to change the src to the high resolution image once the large image is loaded. This is what I'm doing now
var texture = new GLGE.texture();
function updateTexture(){
var image=new Image();
image.src = "models/testLargeMap_map0.jpg"; // load image
image.onload = function(){
texture.image("models/testLargeMap_map0.jpg"); // supposedly swap image on load (not working as I thought)
}
}
However, when during this period of changing the src, the model and all its functions freeze. How do I make it load the image asynchronously and on load swap it to the higher texture for a smooth instantaneous texture change?
You can set an image.onload event handler like this:
var big_image = new Image();
big_image.onload = function () {
texture.image("models/testLargeMap_map0.jpg");
}
big_image.src = "models/testLargeMap_map0.jpg";
(Note that I set the onload handler first, then set the src attribute. If I do it the other way around, it fails in IE).
This will preload the image before calling texture.image. I don't know anything about this library though, so I can't be certain it will use the pre-loaded image.
The image.src will be requesting the image from the server and it will initiate the onload event, and again u are requesting the image to be swapped so it is getting freezed. Why do you need this approach. You can have better way of doing this like, allow the low resolution image to be loaded first then assign the onmouseover or onclick event for the image on that time u can show a popup like shown on google images and then in it just display the high resolution images. On that time u will be requesting a single image the process will be quicker.
Hope this helps you
I'm not familiar with "GLGE" but it looks like the problem is that the method .image() loads the image again (kind regardless if that happens in the load event handler for the same image).
So unless you can set the image reference directly, like
texture = this; // within the load handler
there is no way to accomplish it with this library.
I was wondering, is there a way to detect if a certain image / div is loaded?
For example when i am loading two heavy images and showing a loading sign at the two places the images will later occupy, is there a way to already display the first image when it's loaded while still loading the second one?
myImage.addEventListener('load', function() { ... }, false);
Code inside the above function will be called when the image is finished loading.
If you are using new Image to preload images, then you can do the following to be notified of then it is loaded
var img = new Image();
img.onload = function() {
//display the image
document.getElementById("myDiv").innerHTML = "%3Cimg src='myimg.jpg' alt=''/%3E";
};
img.src = "myimg.jpg";
Remember to set the src after the onload.
if an image is done loading, its .complete property switches to true.
I'm trying to preload about 150 images and I want to be able to be able to do two things...
1) The images are being preloaded using a list of file names. Not every single file name in the list has a file to match up to it.
eg) pic04.jpg may not exist, even if it is in the list.
So when I'm preloading, i would like to be able to figure out whether or not the image exists, if possible.
2) Right now the function is simply preloading all 150 images using
pictures[i] = new Image();
pictures[i].src = "path/to/my/images/" + imageName[i] + ".jpg";
The function executes extremely fast, but the images don't seem to have been preloaded. Do I need to do something to make the site wait til the images have loaded before continuing?
Any ideas?
The function executes extremely fast, but the images don't seem to have been preloaded.
the images are being loaded asynchronously. The function finishes its execution but the browser continues loading the images in background
So when I'm preloading, i would like to be able to figure out whether or not the image exists, if possible.
yes, it is possible. You can use onerror event handler on the Image object
var img = new Image();
img.onerror=function(){alert('error: '+this.src);}
img.onload=function(){alert('image loaded: '+this.src);}
img.src='path/to/image.jpg';