jqueryruby-on-railsloopsslideshowfadeto

jQuery how to loop a function after itself?


I have done a ton of googling but can't seem to find the answer to this obvious question!

I have 5 images stacked on top of eachother. I am using .fadeTo(1000,0) to fadeout the 1st image in 1000ms and show the 2nd underneath. Then fade out the 2nd to show the 3rd, until it reaches the 5th. Then I .fadeIn(0,1) all the images so I can repeat this function.

$(document).ready(function(){
    setInterval(function (){
            $('.map1').delay(1000).fadeTo(1000, 0);
            $('.map2').delay(2000).fadeTo(1000, 0);
            $('.map3').delay(3000).fadeTo(1000, 0);
            $('.map4').delay(4000).fadeTo(1000, 0);
            $('.map4').fadeTo(0, 1);
            $('.map3').fadeTo(0, 1);
            $('.map2').fadeTo(0, 1);
            $('.map1').fadeTo(0, 1);
        },5000)
});

The problem is that the slideshow/animation doesn't correctly loop in order! It will jump from map1 to map2 and back to map1, then continue to map3..etc I know there is probably a better way to do this, but so far my attempts at .animate and .slideshow (plugin) have failed.

Can someone please help me order this code correctly? I am using jQuery with Ruby on Rails (Ruby 2.1.5, Rails 4.2)


Solution

  • Here's a different approach that uses one loop and iterates through a list of objects on each iteration of the loop and uses animation completion functions to know when an animation is done:

    $(document).ready(function(){
        var items = $(".map1, .map2, .map3, .map4");
        var visibleIndex = 0;
    
        // establish initial opacity for only one of them visible
        items.css("opacity", 0);
        items.eq(0).css("opacity", 1);
    
        function next() {
            // fade out the currently visible item
            items.eq(visibleIndex).fadeTo(1000, 0);
    
            // at the same time, fade in the next item
            visibleIndex = ++visibleIndex % items.length;
            items.eq(visibleIndex).fadeTo(1000, 1, function() {
                // do a one second delay until the next loop is started
                setTimeout(next, 1000);
            });
        }
    
        // start the cycle
        next();
    });
    

    Working demo: http://jsfiddle.net/jfriend00/mLn0kznp/

    The above code does a cross fade (one item fading out while another item fading in).


    If you want one item to fade out and only when that is done will the next item start fading in (no simultaneous fading), then you can do that like this:

    $(document).ready(function(){
        var items = $(".map");
        var visibleIndex = 0;
    
        // establish initial opacity for only one of them visible
        items.css("opacity", 0);
        items.eq(0).css("opacity", 1);
    
        function next() {
            // fade out the currently visible item
            items.eq(visibleIndex).fadeTo(1000, 0, function() {
                // when done fading out, fade in the next item
                visibleIndex = ++visibleIndex % items.length;
                items.eq(visibleIndex).fadeTo(1000, 1, function() {
                    // do a one second delay until the next loop is started
                     setTimeout(next, 1000);
                });
            });
        }
    
        next();
    });
    

    Working demo: http://jsfiddle.net/jfriend00/q26c72rz/