6
\$\begingroup\$

I have a number of jQuery animation effects applied to certain elements on the page:

jQuery("#bgd_balance").animate({
        backgroundPositionY: "0px",
        backgroundPositionX: "0px",
        'background-size':'100%'
},800,"swing");


jQuery(".balance_left_box").delay(2000).slideDown(200,"easeInCirc");

jQuery(".balance_left_box p.first-line").delay(2400).slideDown(600,"easeInCirc");

jQuery(".balance_left_box").delay(1000).animate({
    height:"270px",
    top:"64px"  
},100,"easeInCirc");

The problem I'm facing is that when I'm tweaking delay of a certain element, I have to go through everything and adjust all other delays accordingly.

Is it possible to have something like this instead (pseudocode):

queue.add(
       delay(2000),
       jQuery(".balance_left_box").slideDown(200,"easeInCirc"),
       delay(2000),
       jQuery(".balance_left_box p.first-line")X.slideDown(600,"easeInCirc");
       delay(1000),                         
       jQuery(".balance_left_box").animate({
            height:"270px",
            top:"64px"  
        },100,"easeInCirc");
).run();

I know I can achieve this "queuing" by adding callback function to animate() call but then resulting code will be really bulky and hard to read, in my opinion.

\$\endgroup\$

migrated from stackoverflow.com Jul 10 '12 at 18:06

This question came from our site for professional and enthusiast programmers.

4
\$\begingroup\$

The way I see it, you have 2 options; either use Deferreds, or store your delay in a variable:

var delay = 0,
    $left_box = $(".balance_left_box");

$("#bgd_balance").animate({
    backgroundPositionY: "0px",
    backgroundPositionX: "0px",
    'background-size':'100%'
}, 800, "swing");

$left_box.delay(delay += 2000).slideDown(200, "easeInCirc");

$left_box.find("p.first-line").delay(delay += 2400).slideDown(600, "easeInCirc");

$left_box.delay(delay += 1000).animate({
    height:"270px",
    top:"64px"  
}, 100, "easeInCirc");
\$\endgroup\$
2
\$\begingroup\$

You could create your own queue by creating a temporary element and adding methods to it's queue using promise objects

var queueEl = $("<div></div>");
queueEl.delay(2000).queue(function(next){
    jQuery(".balance_left_box").slideDown(200,"easeInCirc").promise().done(next);
}).delay(2000).queue(function(next){
    jQuery(".balance_left_box p.first-line").slideDown(600,"easeInCirc").promise().done(next);
}).delay(1000).queue(function(next){
    jQuery(".balance_left_box").animate({
        height:"270px",
        top:"64px"  
    },100,"easeInCirc").promise().done(next);
});

Though it might as well just be nested callbacks.

\$\endgroup\$
2
\$\begingroup\$

I created this function a little while ago:

function queue(start) {
    var rest = [].splice.call(arguments, 1),
        promise = $.Deferred();

    if (start) {
        $.when(start()).then(function () {
            queue.apply(window, rest);
        });
    } else {
        promise.resolve();
    }
    return promise;
}

I think you could do exactly what you are doing like this:

queue(function () {
   return jQuery(".balance_left_box").delay(2000).slideDown(200,"easeInCirc");
}, function () {
   return jQuery(".balance_left_box p.first-line").delay(2000).slideDown(600,"easeInCirc");
}, function () {
   return jQuery(".balance_left_box").delay(1000).animate({
        height:"270px",
        top:"64px"  
    },100,"easeInCirc");
});

While that doesn't look so great (I think you should be naming your animations), with an added delay utility function:

function delay(msec) {
    return function () {
        var promise = $.Deferred();
        window.setTimeout(function () { promise.resolve(); }, msec);
        return promise;
    };
}

you could write it like this:

(function ($) {
    function showMessageBox($message) {
        return function () {
            return $message.slideDown(200,"easeInCirc");
        };
    }

    function showMessageTitle($title) {
        return function () {
            return $title.slideDown(600,"easeInCirc");
        };
    }

    function resizeMessage($message) {
        return function () {
            return $message.animate({
                height:"270px",
                top:"64px"  
            },100,"easeInCirc");
        };
    }

    //and then, it is just one more animation ...
    function showMessage($message, $title) {
        return function () {
            return queue(
                delay(2000),
                showMessageBox($message),
                delay(2000),
                showMessageTitle($title),
                delay(1000),
                resizeMessage($message)
            );
        };
    }

    $(function () {
        var $message = $(".balance_left_box"),
            $title = $message.find("p.first-line"),
            animation = showMessage($message, $title);
        animation(); 
        //you could have saved some code by not returning a function 
        //but I think it is better to follow a convention wherein 
        //all animations are functions that you must call to have them execute
        //because then reusing them is easier later
    });
}(jQuery));
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.