hh54188
hh54188

Reputation: 15626

Confuse about using javascript setInterval to do animate job

I try to use setInterval to achieve animate effect in javascript, I want a div's width increase 200px(the box's origin width is 100px) in 1000ms:

var MAX = 300, duration = 1000;
var inc = parseFloat( MAX / duration );

var div = $('div')[0];
var width = parseInt(div.style.width, 10);

function animate (id) {
    width += inc;
    if (width >= MAX) {
        clearInterval(id);
        console.timeEnd("animate");
    }
    div.style.width = width + "px";
}

console.time("animate");
var timer = setInterval(function () {
    animate(timer);
}, 0)

and I use the console.time to calculate how much time it take, however, it always take 3 second and more, not 1 second.

So what's wrong with my code?

the Demo is here

but when I use jquery animate, it just as the same time as I pointed:

console.time("animate");
$('div').animate({
    width: '300px'
}, { 
    duration: 1000,
    complete: function () {
        console.timeEnd("animate");
    }
})

Here is the Demo

So why jquery could achieve it?What's the secret?

Upvotes: 0

Views: 545

Answers (2)

user1693593
user1693593

Reputation:

The "secret" is to calculate the steps you need to take per frame.

Here is an updated example (with some optimizations):
http://jsfiddle.net/AbdiasSoftware/nVgTj/7/

//init some values
var div = $('div')[0].style;
var height = parseInt(div.height, 10);
var seconds = 1;

//calc distance we need to move per frame over a time
var max = 300;
var steps = (max- height) / seconds / 16.7;

//16.7ms is approx one frame (1000/60)

//loop
function animate (id) {
    height += steps; //use calculated steps
    div.height = height + "px";

    if (height < max) {
        requestAnimationFrame(animate);
    }
}

animate();

Note that as hh54188 points out, requestAnimationFrame is not available in all browsers yet (Chrome and Firefox supports it with prefixes).

You can use this polyfill which allow you to use the call no matter, but fall backs gracefully to setTimeout if requestAnimationFrame shouldn't be available.

http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/

Upvotes: 1

hh54188
hh54188

Reputation: 15626

The solution @Ken said is an available one, but the browser don't support requestAnimationFrame, it could't work;

The mistake I made in my code is, what I calculate the increasement is increased per 1ms, but the timer execute my animate function per 4ms (according to the minimum delay).

So for some insurance,we better set the timer delay by hand, like 13ms (the interval in jquery animation), and the increasement should be:

var inc = parseFloat( MAX / duration ) * 13;

use the 13 * perOneMillisecond as the increasement for matching the 13ms interval

Here is the Demo, then you can check time cost almost as the jquery(but still slower some, why?)

Upvotes: 0

Related Questions