Image Slideshow with PreloadJS, JQuery and TweenMax

This is a tutorial about how to create a simple slideshow element with dynamicaly loaded images and some cool animations.
PreloadJS is a rather new JS library that aims to help with the loading of various assets, in our case it will provide us with the info of when the images are fully loaded and a value of percentage completion of this task.

DEMO


Download these libraries from here:
PreloadJS
Greensock TweenMax

Step 1 – The markup

We start of by declaring our libraries

<script type="text/javascript" src="libs/TweenMax.min.js"></script>
<script type="text/javascript" src="libs/preloadjs-0.2.0.min.js"></script>
<script type="text/javascript" src="libs/jquery-1.7.1.js"></script>
<script type="text/javascript" src="main.js"></script>

*main.js is our custom javascript file

Now we add some HTML as placeholder:

<div id="mainContainer">
       
        <div id="leftArrow">
           
        </div>
       
        <div id="rightArrow">
           
        </div>
       
        <div id="imageContainer">
            <div id="containerBG"> </div>
           
            <div id="innerContainer">

                <div class="loadingBar">
                    <div class="loading-progress-15" id="loadingFill"></div>
                </div>
            </div>
           
        </div>
    </div>

Here we defined the container for the Images, and the loading bar that is displayed in the beginning.

Step 3 – Preloading Images

Next step is to make use of the PreloadJS library and queue up some images.

var greenImgs = [
    "assets/image1.jpg",
    "assets/image2.jpg",
    "assets/image3.jpg",
    "assets/image4.jpg",
    "assets/image5.jpg",
    "assets/image6.jpg",
    "assets/image7.jpg",
    "assets/image8.jpg",
    "assets/image9.jpg",
    "assets/image10.jpg",
    "assets/image11.jpg"
];

function init() {

            $("#innerContainer").width((greenImgs.length*($("#mainContainer").width()+20)));
            reload();
            loadAll();
        }

        // Reset everything
        function reload() {
            // If there is an open preload queue, close it.
            if (preload != null) {
                preload.close();
            }

            // Push each item into our manifest
            manifest = greenImgs;

            // Create a preloader. There is no manfest added to it up-front, we will add items on-demand.
            preload = new createjs.PreloadJS();
            preload.onFileLoad = handleFileLoad;
            preload.onProgress = handleOverallProgress;
            preload.onFileProgress = handleFileProgress;
            preload.onError = handleFileError;
            preload.setMaxConnections(5);
        }

function loadAll() {
            while (manifest.length > 0) {
                loadAnother();
            }
           
        }

        function loadAnother() {
            // Get the next manifest item, and load it
            var item = manifest.shift();
            preload.loadFile(item);

        }

Here we call two functions reload(), and loadAll()
reload function is responsible for initiating the loading procedure, it defines the manifest array from which we pull urls for loading, and the preloadjs classes and handler functions.
loadAll function is responsibel for iterating through the manifest array and loading images one after the other.

So lets see those handler functions one by one.

// File complete handler
        function handleFileLoad(event) {
           
            // Get a reference to the loaded image (<img/>)
            var img = event.result;
           
            // getting the images and their index for later sorting
            map[map.length] = {'src':String(String(event.src).toLowerCase()).replace('assets/image','').replace('.jpg','').replace('.png',''),'data':img};
           
        }

        // File progress handler
        function handleFileProgress(event) {
       
        }

        // Overall progress handler
        function handleOverallProgress(event) {
            console.log('TOTAL: '+preload.progress);
            var perc = preload.progress*100;
            TweenMax.to($("#loadingFill"),0.2,{css:{'width':perc+'%'}});
        }

// An error happened on a file
        function handleFileError(event) {
            console.log('error');
        }

So here we have the handlers for the error, the file loaded, and the information on the total percentage of loading completion.
When we receive new info about the total percentage of completion we increase the width of the loading bar by a that percentage.

Step 4 – Creating DOM elements

Now that we have our assets loaded its time to push them into the DOM

// Overall progress handler
        // File complete handler
        function handleFileLoad(event) {
           
            // Get a reference to the loaded image (<img/>)
            var img = event.result;
           
            // getting the images and their index for later sorting
            map[map.length] = {'src':String(String(event.src).toLowerCase()).replace('assets/image','').replace('.jpg','').replace('.png',''),'data':img};
           
            // checking to see if all images have been loaded.
            // sometimes when images are cached preloadJS fires 100% but there are still some images missing
            console.log(map.length,greenImgs.length);
            if(map.length<greenImgs.length){
               
            }
            else{
                if(preload.progress==1){
                    stop();
                    TweenMax.delayedCall(0.5,function(){
                        map.sort(sortImages);
                       
                        var parent = $("#innerContainer");
                        // setting images to DOM
                        for(var i= 0;i<map.length;i++){
                            var item = $(map[i].data);
                            item.addClass('slideImages');
                            item.attr('id','img'+i);
                           
                            if(i==0){
                                item.addClass('selected');
                            }
                            else{
                                item.addClass('hidden');
                            }
                           
                            parent.append('<div id="slideImg'+i+'" class="slideImagesContainer"></div>');
                            $("#slideImg"+i).append(item);
                        }
                       
                        TweenMax.to($(".loadingBar"),0.1,{css:{autoAlpha:0},onComplete:function(){
                            $(".loadingBar").remove();
                        }});
                       
                        TweenMax.to($(".slideImagesContainer"),0.4,{css:{autoAlpha:1},onComplete:function(){
                           
                            TweenMax.to($("#leftArrow"),0.2,{css:{autoAlpha:1}});
                           
                        }});
                       
                       
                    });
                }
            }
        }

function sortImages(a, b){
         var nameA=Number(a.src.toLowerCase());
         var nameB=Number(b.src.toLowerCase());
         
         if (nameA < nameB) //sort string ascending
          return -1
         if (nameA > nameB)
          return 1
         return 0 //default return value (no sorting)
    }

What we have done now is that we checked when all the assets have loaded and we sorted the array based on their index (PreloadJS doesn’t sort the loaded results, or at least I haven’t found some easy way to do it through their API) so I wrote a simple sorting function that handles just that.
After we sort out the results we iterate through them and add the nececery html into the DOM.
At the end we fade-in the first image and remove the loading bar.

Step 4 – Adding Effects

Now its time to add some effects to our slideshow. First of all we declare a document ready function:

$(document).ready(function(){});

Next we add event listeners with JQuery for the left and right buttons.

$("#leftArrow").live('click',function(){
           
           
            var len = $("#innerContainer").children().length;
           
            if(selectedIndex<len-1){
               
               
                var item = $("#slideImg"+selectedIndex);
                //var img  = $("#img"+selectedIndex);
                var img = $(".slideImages");
               
                // we don't like fast clickers...
                var activeTweens = TweenMax.getAllTweens();
               
                if(activeTweens.length!==0){
                    return false;
                }
               
                img.removeClass("addShadow");
                TweenMax.to(img,
                    0.4,
                    {
                        css:{
                            scaleX:0.5,
                            scaleY:0.5,
                            className:"+=addShadow"
                           
                        },
                    overwrite:"all",
                    ease:Sine.easeOut,
                    onComplete:function(){
                   
                    $("#img"+selectedIndex).removeClass('hidden').addClass('selected');
                    /////////////////////////////////////// moving the whole inner
                       
                        // moving images to the left...
                        TweenMax.to($("#innerContainer"),0.4,{css:{'left':'-=620px'},overwrite:"all",delay:0.2,ease:Sine.easeOut,onComplete:function(){
                           
                            //getting images back on track
                            var img = $(".slideImages");
                            TweenMax.to(img,0.2,{css:{scaleX:1,scaleY:1},overwrite:"all",ease:Power3.easeInOut,onComplete:function(){
                               
                                $("#img"+(selectedIndex-1)).removeClass('selected').addClass('hidden');
                               
                            }});
                           
                            $("#rightArrow").show();
                           
                            if(selectedIndex == len-1){
                                $("#leftArrow").hide();
                            }
                            else{
                                $("#leftArrow").show();
                            }
                           
                        }});
                   
                    }
                });
               
                selectedIndex += 1;
            }
           
        });

Well this might look a bit much of a code but its really simple. What we are doing here is to check a variable to tell us which is the selectedIndex (the image that it is currently shown).
Next we take that image and we add some shadow behind it, and scalling it by -50% (0.5).
When the scalling effect ends we move the whole container that the images live inside by 620 pixels (600 is the width of the container, and 20 pixels is the left margin of each image). That way we have the next image shown, when that effect also ends we scale the new image to its original size (scale = 1).

We have also included some checks to see if we have reached the end or start of the slide show and thus we remove the right or left arrow.

* The code for the right arrow is exactly the same only that we move the container by -=620px in the opposite direction.
* Sometimes when images are cached PreloadJS throws 100% completion but there are still images loading, so it is wise to check the length of the loaded elements against our initial array or manifest.

DEMO

Tagged , , , , , , , . Bookmark the permalink.

10 Responses to Image Slideshow with PreloadJS, JQuery and TweenMax

  1. Carl Schooff says:

    Hi Michael,

    Excellent tutorial. Great use of TweenMax.
    I posted a link to this tutorial in the GreenSock forums.
    Keep them coming. Will do our best to spread the word about your work.

    -Carl
    Geek Ambassador of GreenSock

  2. coder says:

    Thank you Carl, I’m happy to provide the community with useful tools.

  3. Dez E says:

    For some reason this example does not work for me locally and the error I get has not information. Seems to be some loading error. Works fine when I upload to the web and view it. Why is this?

  4. coder says:

    Make sure you have set the relative paths for the images correctly. Other than that all libraries are local so make sure you download them. If you want to run this locally I would suggest that you set up some form of local server like Apache. Some IDEs also provide Apache Tomcat as their server, like Aptana IDE.

  5. Kathy says:

    Hi,
    Can we have this tutorial for beginners with step by step guide and information ? Or some video displaying the same ?

  6. Well sure I thought it was detailed enough but sometimes I get carried away writing the post. I’ll try and set up some video tutorial explaining each part.

  7. Tim says:

    Great tutorial my friend it was very helpful!!!!!

  8. Michael Kaufman says:

    Thanks very much for this. It took me some time to understand but glad I do now.

    Worth noting – this will not work if jQuery is above 1.7.1 because you’re using a deprecated live() function. You could write a listener or use ‘do’ or ‘on’ instead if you need > 1.7.1 though.

    Also, the demo includes 4 scripts but the demo page has several more and I found it didn’t work without all 11 scripts.

    What this thing does theoretically is simple: preload an image, dynamically add a hide/show class, move it etc… but this demo gets confusing because a. there are dynamic CSS classes applied via javascript, the amounts things move is hard coded and it’s a lot of code for what should be a simple thing. Why is there a sort function for example, when this runs fine without it? There’s also a ton of extra CSS in the demo that makes it confusing. Would rather just see a bare bones example of what I need to take and tweak on my own. Thanks and I mean that!!!

  9. Yes the JQuery version might be somewhat outdated.

    As for the sort function it wasn’t really getting me the images in the right order but rather as they loaded. For me preloadjs lacks a simple cache mechanism to handle strict-queues.
    Anyhow this tutorial simply shows how to create a simple gallery with preloadjs-and-tweenmax and I’m aware that this can be done with much simpler code and vanila-js too, although I wanted to create something with very little searching and digging into these libraries and quickly create something that works. In our line of work we rarely have enough time to search and comprehend the so-many different libraries that we come across, most of the time we want raw-ugly-results, it ain’t pretty but its a necessity I think.

  10. forex says:

    That is a good tip particularly to those fresh to the blogosphere.
    Brief but very accurate information… Thanks for sharing this one.

    A must read post!

Leave a Reply

Your email address will not be published. Required fields are marked *