Kirk Strobeck
Kirk Strobeck

Reputation: 18619

jQuery image crossfade with pre-loader

I want a simple image crossfade, similar to http://malsup.com/jquery/cycle/, but with a pre-loader. Is there a good jQuery plugin that does both? Also, I'm not looking for a load bar.

This question is close, but not the same => jQuery Crossfade Plugin

It would be great if it was a solution that defaulted to CSS3, but would otherwise fall back to JS to keep the processing native as possible.

Looking for something that..

Upvotes: 12

Views: 3826

Answers (4)

Brian Nickel
Brian Nickel

Reputation: 27560

UPDATE Added the ability to load everything asynchronously.

A wrapper for the jQuery cycle plugin should suffice. You really just need something that monitors if the images loaded and then calls $(elem).cycle(/* options */). Here's my take:

$.fn.cycleWhenLoaded = function(options) {
    var target = this,
        images = options.images,
        loaded = 0,
        total  = 0,
        i;

    if(images) {
        for(i = 0; i < images.length; i ++) {
            $('<img/>').attr('src', images[i]).appendTo(target);
        }
    }

    this.find('> img').each(function(index) {
        var img = new Image(),
            source = this;

        total ++;

        if(index > 1)
            $(this).hide();

        img.onload = function() {
            loaded ++;
            if(loaded == total) {
                target.trigger('preloadcomplete');
                target.cycle(options);
            }
        };

        setTimeout(function() {img.src = source.src}, 1);
    });

    return this;
};

This allows you to either do a simple delay load:

$('.slideshow').cycleWhenLoaded({
    fx: 'fade'
});

Or you can do something more complicated and load your images in the script and capture the preload complete event:

$('.slideshow2').hide().cycleWhenLoaded({
    fx: 'fade',
    images: [
        "http://cloud.github.com/downloads/malsup/cycle/beach1.jpg",
        "http://cloud.github.com/downloads/malsup/cycle/beach2.jpg",
        "http://cloud.github.com/downloads/malsup/cycle/beach3.jpg",
        "http://cloud.github.com/downloads/malsup/cycle/beach4.jpg",
        "http://cloud.github.com/downloads/malsup/cycle/beach5.jpg"
    ]
}).bind('preloadcomplete', function() { $(this).show(); });

You can see it in action here: http://fiddle.jshell.net/vmAEW/1/

Upvotes: 1

Joshua Conner
Joshua Conner

Reputation: 912

I think you can still do this with the jQuery cycle plugin; other than image preloading, even the jQuery cycle lite version does everything you want by default out-of-the-box.

And if you look here, you'll see that it's pretty simple to add a little Javascript that will add images (after the first two) as they load. You would need to modify the code a little (instead of stack.push(this), you'd want something like stack.push("<div style="background-image:url("+img.src+")"></div>"), for example) but I think it's totally doable.

Edit: here's a link to a SO question about how to make a div into a clickable link.

Edit 2: I liked Joseph's idea to just move the elements to a hidden DIV, so I updated my code a bit. It now also preserves the links each div points to as well: http://jsfiddle.net/g4Hmh/9/

Edit 3: Last update! http://jsfiddle.net/g4Hmh/12/

Upvotes: 2

Joseph Marikle
Joseph Marikle

Reputation: 78560

Well, here's my poke at it. The preloader is in vanilla js and the slideshow loop is in jQuery. It's very simple to implement and the concept is even simpler.

Demo

a very simple Demo that illustrates the DOM manipulation approach


HTML

<!-- not much here... just a container -->
<div id="content"></div>

CSS

/* just the important stuff here.  The demo has example styling. */
#content
{
    position:relative;
}
#content img
{
    position:absolute;
}

javascript/jQuery

// simple array
var images = [
    "http://imaging.nikon.com/lineup/dslr/d90/img/sample/pic_003t.jpg",
    "http://imaging.nikon.com/lineup/dslr/d90/img/sample/pic_005t.jpg",
    "http://imaging.nikon.com/lineup/dslr/d90/img/sample/pic_001t.jpg"
];

// some adjustable variables
var delay = 2000;
var transition = 1000;

// the preloader
for(var i in images)
{
    var img = document.createElement("img");
    img.src = images[i];
    img.onload = function(){
        var parent = document.getElementById("content");
        parent.insertBefore(this,parent.childNodes[0]);
        if(i == images.length - 1)
        {
            i = 0;
            startSlides();
        }
    }
}

// and the actual loop
function startSlides()
{
    $("#content img:last").delay(delay).fadeTo(transition,0,function(){
        $(this).insertBefore($(this).siblings(":first")).fadeTo(0,1);
        startSlides();
    });
}

The concept in brief is to fade the first image in a container, once complete change it's position in the DOM (effectively hiding it behind equal tree level siblings), and call the function again. The reason why this works is because it only fades the first child of the container, but on callback it changes what node that is constantly looping the nodes. This makes for a very small source file that is quite effective.

EDIT 1:


and 32 minutes tweaking later...

Demo 2

EDIT 2:


My oh so simple script is now very complicated :P I added in some scaling features that only work on modern browsers but are there if needed. This one also has a loading bar as it preloads the images (may or may not be desirable :P)

small images demo

large images demo

Upvotes: 6

watzon
watzon

Reputation: 2549

I don't know how close this is to what you are looking for, but I figured since no one else did I would at least try to help. http://galleria.aino.se/

It at least has a preloader and a fade transition.

Upvotes: 0

Related Questions