Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does jquery consistently execute animation functions in (nearly) exact time?

I tried writing my own animation function to animate the counting up and down of a number using loops and the setInterval function. In Chrome, it seems to run very well, but on Firefox, it seems laggy, and to take much longer than the prescribed required completion time.

I assume the difference lies in the two browsers' abilities to execute Javascript quickly, but after encountering this problem, I was more curious than anything as to how jQuery is able be so consistent on the timing, since it apparently doesn't use the process that I thought it would.

Edit: Here's my code since it was requested:

function tallyPrices(){

var current_total = parseFloat( $('.budget span').text() );
var new_total = 0;  
var animation_options = {
    iterationTime : 10,
    totalTime : 500
}

$('#chosen-items li').each( function(){
    if( $(this).attr('data_price') !== 'n/a' ){
        new_total += parseFloat( $(this).attr('data_price') );
    }
});

animation_options.difference = current_total - new_total;
animation_options.delta = Math.round( Math.abs( animation_options.difference / ( animation_options.totalTime / animation_options.iterationTime ) ) * 100 ) / 100;

var timesIterated = 0;
var limit = parseFloat( $('.budget span').attr('data_high') );

var animation = setInterval( function(){
    timesIterated = priceAnimate( timesIterated, animation_options, $('.budget span'), limit);

    if(timesIterated === 'done'){
        clearInterval(animation);
        $('.budget span').text( parseFloat( Math.round( new_total * 100 ) / 100 ).toFixed(2) );
    }
}, animation_options.iterationTime );
}

function priceAnimate( count, options, el, limit ){
if( count < ( options.totalTime / options.iterationTime ) && options.difference !== 0){
    var current = parseFloat( el.text() );
    current = Math.round( current * 100 ) / 100;

    if( options.difference < 0 ){
        el.text( parseFloat( Math.round( (current + options.delta) * 100 ) / 100 ).toFixed(2) );
    } else if( options.difference > 0 ){
        el.text( parseFloat( Math.round( (current - options.delta) * 100 ) / 100 ).toFixed(2) );
    }

    if( parseFloat( el.text() ) > limit ){
        el.parent().addClass('over');
    } else {
        el.parent().removeClass('over');
    }

    count++;

    return count; 
} else {
    return 'done';
}
}
like image 500
dclowd9901 Avatar asked Oct 20 '11 20:10

dclowd9901


1 Answers

I don't see anything in your code checking for time differences. In most libraries (jQuery, MooTools, etc) animations adjust based on time.

jQuery uses a method step which is used to determine the next value for an effect. To look at that function open the development (non-compressed) version of jQuery and search for jQuery.fx.prototype. This block of code with contain the step method.

Let's say you want to tell an element to move from one position to another. It looks like your code will iterate until is complete with a fixed number of animations. So you are being strict in the number of iterations rather than time. Browsers often lag. Someone could be running all sorts of junk on their machine, which will slow down your execution. And then the total execution of your animation will be longer than intended and the animation itself will be 'jerky.'

So, what you should do instead is be strict with time, and not try to enforce even steps. Each time you 'step' through the animation you should take into account the time the animation started, the total time the animation has to complete and how much time has lapsed. With that you can tell where the animation should be. So if you want to move an element (linearlly) from position 100 to 200 in 10 seconds, and we are at 7.5 seconds you know that the position is to be 175. Then once the time is at or over the completed 10 seconds you set it to 200 and kill the loop.

The jQuery code will be a bit difficult to read through due to the easing effects it uses and all the inner-hooks and callbacks. But the idea is pretty straight-forward.

like image 158
Marshall Avatar answered Oct 27 '22 01:10

Marshall