I've been working on an image gallery program in
jQuery for a little while. The biggest problem I ran into was trying to preload the first two images before the show started. I experimented with a few different methods, but couldn't find something that worked well across all browsers.
I was looking through
mootools one day and found out they have a built in image preloader using
Asset.images. It works well enough, but I'm not a big fan of mootools. Plus I wanted something that could plug into any library. After a bit of testing I came up with something that has worked really well across Safari 1.x & 2.x, Firefox 1.x & 2.x, IE 6, 7 & 8 and Opera.
It's a class built with objects instead of prototypes. I prefer objects now because it keeps everything in a nice neat package instead of having variables and functions scattered all over the place. I based a lot of the script on the
Images Asset of mootools and the New Wave style John Resig talks about in
Pro Javascript Techniques.
preloadImages =
{
count: 0 /* keep track of the number of images */
,loaded: 0 /* keeps track of how many images have loaded */
,onComplete: function(){} /* fires when all images have finished loadng */
,onLoaded: function(){} /*fires when an image finishes loading*/
,loaded_image: "" /*access what has just been loaded*/
,images: [] /*keeps an array of images that are loaded*/
,incoming:[] /*this is for the process queue.*/
/* this will pass the list of images to the loader*/
,queue_images: function(images)
{
//make sure to reset the counters
this.loaded = 0;
//reset the images array also
this.images = [];
//record the number of images
this.count = images.length;
//store the image names
this.incoming = images;
//start processing the images one by one
this.process_queue();
}
,process_queue: function()
{
//pull the next image off the top and load it
this.load_image(this.incoming.shift());
}
/* this will load the images through the browser */
,load_image: function(image)
{
var this_ref = this;
var preload_image = new Image;
preload_image.onload = function()
{
//store the loaded image so we can access the new info
this_ref.loaded_image = preload_image;
//push images onto the stack
this_ref.images.push(preload_image);
//note that the image loaded
this_ref.loaded +=1;
//fire the onloaded
(this_ref.onLoaded)();
//if all images have been loaded launch the call back
if(this_ref.count == this_ref.loaded)
{
(this_ref.onComplete)();
}
//load the next image
else
{
this_ref.process_queue();
}
}
preload_image.src = image;
}
}
Everything is stored in the preloadImages object. There is only one namespace so it shouldn't interfere with any of your other code. You can store this in any script you write, or include it from an external file.
The one thing I really like about this script is the image loading is sequential. One big problem I ran into was images loading out of order. Firefox would grab the images in the order listed by the array. Internet Explorer would grab everything, but not return it in the right order. This script grabs one image at a time and makes sure the order is preserved. This is important for scripts like slide shows with labels for each image.
To begin preloading images use the method
preloadImages.queue_images([IMAGES]) where
[IMAGES] is an array of images. Everything will be processed internally. There are two methods you can use:
onLoaded and
onComplete.
onLoaded will fire whenever an image has finished loading. All the properties of the loaded image are available in the variable
loaded_image. For example if you want to find the width of the image that just finished loading your code would look like this.
preloadImages.onLoaded = function()
{
alert(preloadImages.loaded_image.width);
}
preloadImages.queue_images(['new_404.jpg']);
A pop up window would appear and display the width of the image that just loaded. All the properties of and image will be available through the variable. onLoaded must appear before queue_images to fire properly.
When an image is loaded a reference is stored in an array named
images. This is useful if you want to load all your images at once, then loop back through them for past information.
onComplete will fire when all the images have loaded. I tried to use the onerror method, but it doesn't work well across all browsers and caused more frustration then it was worth. Like onLoaded, onComplete must come before queue_images to fire properly. Here as an example of how to use onComplete.
preloadImages.onComplete = function()
{
alert('All Done');
}
preloadImages.queue_images(['new_404.jpg']);
It's a pretty simple script. It can be used in combination with lots of other scripts. There are a lot of comments in the script so it's pretty easy to follow. If you have any questions about it feel free to email me.