views:

50

answers:

2

I'm using this script to animate some images inside anchors:

$('#locations a').each(function() {
        // set opacity 0 take initial position
        $(this).css('opacity', '0');
        var left = $(this).css('left');
        var top = $(this).css('top');

        // reset position and animate
        $(this).css({'left' : '0', 'top' : '0'});
        $(this).animate({left: left, top: top, opacity: 1});
    });

I need to use the jquery each() function to take the initial position. However, I want to animate the returned elements in order. Is that possible?

A: 

You can setup your own custom queue in jQuery.

http://api.jquery.com/queue/

  1. Populate your queue with all the functions you want to execute.
    1. Each function in the queue is a single animation.
    2. Use your each() loop to populate the queue.
  2. Start the queue to kickoff the first animation.
  3. In the callback for each animation function, call the dequeue() function to start up the next animation.

Example based on your comment

I created a custom queue named "MyCustomQueue" and I arbitrarily put it on the body tag. I used a JavaScript closure to animate a specific element in each function of the queue by setting a variable named "this$".

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <title>Queues Me</title> 
    <style> 
        a { 
            position:relative;
            top:0;
            left:0;
        }
    </style> 
    <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js"&gt;&lt;/script&gt; 
    <script type="text/javascript"> 

        $(function () {

            $('#locations a').each(function () {

                var this$ = $(this);

                // set opacity 0 and take initial position 
                this$.css('opacity', '0');
                var left = this$.css('left');
                var top = this$.css('top');


                // reset position and populate the queue with animations 
                this$.css({ 'left': '420px', 'top': '1820px' });

                $('body').queue("MyCustomQueue", function () {
                    this$.animate({ left: left, top: top, opacity: 1 }, 500, function () {
                        $('body').dequeue("MyCustomQueue");
                    });
                });
            });

            $('body').dequeue("MyCustomQueue");

        });

    </script> 
</head> 
<body> 
    <div> 
        <div id="locations"> 
            <ul> 
                <li><a href="#">Foo</a></li> 
                <li><a href="#">Moo</a></li> 
                <li><a href="#">Poo</a></li> 
                <li><a href="#">Woo</a></li> 
                <li><a href="#">Zoo</a></li> 
            </ul> 
        </div> 
    </div> 
</body> 
</html> 
AndrewDotHay
$('#locations a').each(function() { // set opacity 0 and take initial position $(this).css('opacity', '0'); var left = $(this).css('left'); var top = $(this).css('top'); // reset position and populate the queue with animations $(this).css({'left' : '420px', 'top' : '1820px'}); $(this).queue(function() { $(this).animate({left: left, top: top, opacity: 1}, 500, function() {$(this).dequeue()}); }); });I populated the queue and called dequeue() on each one. How do I start now the queue?
Sergiu
Thanks ... I got it working!
Sergiu
A: 

You can do this in a not-so-complicated way, like this:

$('#locations a').each(function(i) {
    var left = $(this).css('left'),
        top = $(this).css('top');

    $(this).css({opacity: 0, left: 0, top: 0})
           .delay(400 * i)
           .animate({left: left, top: top, opacity: 1});
});

You can test it here. It's mostly simplification, the only important additions are .delay(400 * i) and the i to function(i) {.

This just uses the i provided as the first parameter to .each()'s callback and multiplies the .delay() (delay before starting animation on this element) times that amount for each element. The 400 is for the default duration of .animate() being 400ms. So the first element starts immediately, the next in 400ms, the next in 800ms, and so on...right when the animation prior to it should be finishing.

You can of course make a custom queue, etc...but this seems a bit simpler :)


Edit: since you're interested in building the queue, it'd look like this:

$('#locations a').each(function(i) {
    var left = $(this).css('left'),
        top = $(this).css('top'),
        a = $(this).css({opacity: 0, left: 0, top: 0});

    $(document).queue('myQueue', function(n) {
      a.animate({left: left, top: top, opacity: 1}, n);
    });
});
$(document).dequeue('myQueue');

You can test it here, we're using .queue() to queue the functions in a custom queue up on document then kicking it off with a .dequeue(). The n is the next function in the queue, we're calling that when the .animate() finishes by providing it as the callback function to run. ​

Nick Craver
Thanks for the idea. I knew about function(index) {} and .delay() but multiplying <duration> * i is a nice trick . I still want to know how to build the custom queue inside each() and then run it
Sergiu
@NGAGE - I added how to do this since you're interested in that route :)
Nick Craver
Thank you very much for taking the time! In Firefox it's working okay but I get a weird error on IE8 after the second animation (very weird). You can see a live example here: http://bit.ly/cuhWIG
Sergiu
@NGAGE - It's because `#romania` has a `right:` position...in other browsers getting `left` works, but in IE it returns `"auto"` which you can't animate. You'll need to add a check for right/left being auto, animate only if they're not, something like this: http://jsfiddle.net/7QTUL/
Nick Craver
I also had some locations with position: absolute; bottom. So I changed everything to left and top and it's working. Thanks again! Have you noticed the fuzzy / black edges of the pngs in IE8 (when the animation occurs)? Do you know if it can be fixed?
Sergiu
@Sergiu - IE + PNGs suck, all versions up until 9 to varying degrees. You can use a `.gif` since your images are simple/few colors, that's probably the easiest/quickest fix here.
Nick Craver