jlmmns
jlmmns

Reputation: 845

jQuery multiple delayed animations inside a loop, animation sometimes not executed

I'm making an animated timeline (see jsFiddle below), where the entries (left and right alternately) fade in after their specified delay. This with the help of a for-loop.

If opacity is supported, I'm fading in those entries using .animate({ opacity: 1 }). Else .fadeIn().

With both .animate() and .fadeIn(), it sometimes happens that the animation of one or more entries is skipped. Note: the chance of this happening seems small.

So my intention, was to check with a do-while, inside the main for-loop, if the entry is indeed visible, and if not, run the animation again.

However, this seems to cause an infinite loop. Is there maybe a better way to check this, and re-animate?

I've commented out the do-while part, in the below jsFiddle.

jsFiddle

Thanks in advance.

Updated jsFiddle, thanks to sweetamylase.

Update 2: I've noticed that another part of my code, a .hover() event on the entries, was making them not to appear if my cursor was on an entry when loading the timeline. This was due to the use of .stop(1, 1).animate() in that part of my code.

$('.timeline .entry').hover(function() {
    $(this).stop(1, 1).animate({backgroundColor: '#f3f3f3'}, 350);

}, function() {
    $(this).stop(1, 1).animate({backgroundColor: '#f8f8f8'}, 350);
});

How can I still use .stop(1, 1) in this part, so those hover animations won't build up, when fast-hovering?

Update 3: I just use a setTimeout() now, to allow the .hover event only after a specified time.

setTimeout(function() {
    $('.timeline .entry').hover(function() {
        $(this).stop(1, 1).animate({backgroundColor: '#f3f3f3'}, 350);
    }, function() {
        $(this).stop(1, 1).animate({backgroundColor: '#f8f8f8'}, 350);
    });
}, 6000);

Upvotes: 1

Views: 444

Answers (1)

Amy
Amy

Reputation: 7466

The problem might be because you make jQuery look for the entries within each iteration of the loop, this takes time, it might be the reason why it sometimes skips the animations on an entry:

$('.timeline .entry').eq(i).delay(delays[i]).animate({opacity: 1}, 'slow');

It is better to minimize the amount of querying because that is an expensive operation. So just find the elements once, and iterate through them using the index you already have:

var delays = [600, 950, 1200, 1550, 1750, 2300, 2600, 3100, 3750, 4200];
var entries = $('.timeline .entry');

for (var i = 0, numEntries = delays.length; i < numEntries; i++) {
    if (opacitySupport) {
        $(entries[i]).delay(delays[i]).animate({opacity: 1}, 'slow');
    } else {
        $(entries[i]).delay(delays[i]).fadeIn('slow');
    }
}

FYI, I used [] array literal notation instead of calling the Array constructor because I find it less confusion-prone: http://www.mattlunn.me.uk/blog/2012/04/the-use-of-literals-vs-constructors/

Upvotes: 2

Related Questions