Daniel Attfield
Daniel Attfield

Reputation: 2072

ExtJs Animation - Show/Fade elements ad infinitum

I'm trying to create a never-ending looping animation using ExtJs, but am hitting the obvious barrier - calling a function recursively that potentially never ends tends to fill the stack pretty quickly. My (non-functioning) code is below; this function gets passed an array of strings which correspond to the divs to be shown and hidden. Without the callback, the code produces the desired show/fade effect, but obviously only the once.

// 'divArray' - a string array containing the IDs of the divs to cycle.
function cycleDivs (divArray) {
    var len, i, el;

    // Sanity check.
    if (divArray === null || !Ext.isArray(divArray) || divArray.length === 0) {
        return;
    }

    // Get the length of the array; we'll need this to loop the animation.
    len = divArray.length;

    for (i = 0; i < len; i++) {
        // Get the element.
        el = Ext.fly(divArray[i]);
        // Sanity check.
        if (el) {
            el.sequenceFx();
            el.fadeIn({
                endOpacity: 1,
                easing: 'easeOut',
                duration: 3
            });
            el.pause(2)
            el.fadeOut({
                endOpacity: 0,
                easing: 'easeOut',
                duration: 3
            });

            if (i === len - 1) {
                // Recursive call if this is the last element in the array.
                el.callback = cycleDivs(divArray);
            }
        }
    }
}

Caveat: I've achieved this sort of effect before with jQuery and its wide variety of plugins, but as it's a work project I can only use the library I've got, which is ExtJs.

Thanks in advance for any pointers.

Upvotes: 1

Views: 6690

Answers (2)

Daniel Attfield
Daniel Attfield

Reputation: 2072

I ended up porting parts of jquery.slideShow by Marcel Eichner, and the SO answer for execute a method on an existing object with window.setInterval for my requirements. Code below for any who might find a use for it. I also now pass the elements to be animated into the constructor, rather than just their IDs.

// Constructor function.
MyNamepsace.Slideshow = function (divArray) {

    // Persist the div array.
    this.divArray = divArray;

    // Internal vars
    this.numSlides = this.divArray.length;

    this.current = 0;

    if (this.current >= this.numSlides) {
        this.current = this.numSlides - 1;
    }

    this.last = false;
    this.interval = false;
};

Ext.apply(MyNamespace.Slideshow.prototype, {

    // Initialisation method.
    init: function() {
        this.gotoSlide(this.current);
        this.auto();
    },

    // This is a "toy" version of "bind".
    bind: function(object, method) {
        return function() {
            method.call(object);
        };
    },

    // Set up automatic slideshow.
    auto: function() {      
        this.interval = window.setInterval(this.bind(this, this.next), 3000);
    },

    // Stop automatic slideshow.
    stopAuto: function() {
        if (this.interval) {
            window.clearInterval(this.interval);
            this.interval = false;
        }
    },

    // Go to next slide.
    next: function() {
        this.gotoSlide(this.current + 1);
    },

    // Go to specific slide.            
    gotoSlide: function(index) {
        var oldSlide, newSlide;

        if (index < 0) {
            index = this.numSlides - 1;
        }

        if (index >= this.numSlides) {
            index = 0;
        }

        if (index === this.current) { 
            return;
        }

        // get slide elements
        oldSlide = this.divArray[this.current];
        newSlide = this.divArray[index];

        this.stopAuto();

        // Start transition
        oldSlide.fadeOut({
            easing: 'easeOut',
            duration: 3,
            callback: this.auto,
            useDisplay: true,
            scope: this
        });

        newSlide.fadeIn({
            easing: 'easeIn',
            duration: 3
        });

        this.last = this.current;
        this.current = index;
    }
});

Upvotes: 2

Drasill
Drasill

Reputation: 4016

I would do something like :

var cycleDivs = function(divs) {

   var i = 0;

   var fadeFn = function() {
      divs[i].sequenceFx().fadeIn({
         ...
      }).pause(2).fadeOut({
         ...,
         callback : fadeFn
      });
      i = (i+1)%divs.length;
   }

   fadeFn();

}

Of course I removed all sanity checks ;)

Upvotes: 1

Related Questions