Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery animate delay issues with self -queued looping of steps

I have a timeline definition which lists selectors and a list of delays and animations to apply to that object. You can specify that the steps for a particular object be looped.

Here is the function that's used to queue the animations:

function animateWithQueue(e, obj) {
    if ($.queue(e[0]).length == 0) {
        e.queue(function doNext(next) {
            $.each(obj.steps, function(i, step) {
                e.delay(step.pause).animate(step.anim, step.options);
            });
            if (obj.loop) {
                e.queue(doNext);
            }
            next();
        });
    }
}​

Here is the timeline information

var timeline = {
    '.square': {
        loop: true,
        steps: [
            { pause: 800, anim: { right: '+=200' }, options: { duration: 400} },
            { pause: 1000, anim: { right: '-=200' }, options: { duration: 400} }
        ]
    },
    '.circle': {
        loop: true,
        steps: [
            { pause: 1200, anim: { top: '+=200' }, options: { duration: 400} },
            { pause: 1200, anim: { top: '-=200' }, options: { duration: 400} }
        ]
    }
};

And here is the function that puts the timeline into the above animate function:

$.each(timeline, function(selector, obj) {
    animateWithQueue($(selector), obj);
});

Here is a full example. http://jsfiddle.net/sprintstar/Tdads/

This code appears to work fine, the animations loop and the stop button can be clicked to stop the animations, clear the queues etc. However the issue we're facing can be triggered by hitting stop and start over and over (say 10 times). Then notice that the delays are not functioning correctly any more, and the shapes move about much faster.

Why is this, and how can it be fixed?

like image 313
Sprintstar Avatar asked Sep 06 '12 12:09

Sprintstar


1 Answers

Something is not working quite right with delay...

As a work around, I've replaced it with doTimeout in this fiddle, so the following:

  e.delay(step.pause).animate(step.anim, step.options);

Becomes:

    var timerName = e[0].className + $.now();
    timeouts.push(timerName);
    e.queue(function(next) {
      e.doTimeout(timerName, step.pause, function() {
          this.animate(step.anim, step.options);
          next();
        });
    });

timeouts is an array of unique timeout ids - each of which is cleared when the stop button is pressed.

As I've said, more of a workaround than a fix, as you'll also need to reset the position of the elements on stop too. (notice I've removed the += and -= from the top/right definitions)

like image 86
RYFN Avatar answered Nov 19 '22 06:11

RYFN