ground5hark
ground5hark

Reputation: 4514

JavaScript: Achieving precise animation end values?

I'm currently trying to write my own JavaScript library. I'm in the middle of writing an animation callback, but I'm having trouble getting precise end values, especially when animation duration times are smaller.

Right now, I'm only targeting positional animation (left, top, right, bottom). When my animations complete, they end up having an error margin of 5px~ on faster animations, and 0.5px~ on animations 1000+ ms or greater. Here's the bulk of the callback, with notes following.

var current = parseFloat( this[0].style[prop] || 0 )
    // If our target value is greater than the current
    , gt = !!( value > current )
    , delta = ( Math.abs(current - value) / (duration / 13) ) * (gt ? 1 : -1)
    , elem = this[0]
    , anim = setInterval( function(){
        elem.style[prop] = ( current + delta ) + 'px';
        current = parseFloat( elem.style[prop] );
        if ( gt && current >= value || !gt && current <= value ) clearInterval( anim );
     }, 13 );

this[0] and elem both reference the target DOM element.

prop references the property to animate, left, top, bottom, right, etc.

current is the current value of the DOM element's property.

value is the desired value to animate to.

duration is the specified duration (in ms) that the animation should last.

13 is the setInterval delay (which should roughly be the absolute minimal for all browsers).

gt is a var that is true if value exceeds the initial current, else it is false.

How can I resolve the error margin?

Upvotes: 0

Views: 263

Answers (2)

bobince
bobince

Reputation: 536399

In addition to what Alex says, you're usually better off using time-based calculation rather than trying to make discrete steps. This ensures accuracy and allows the animation to run at a reasonable speed when the browser's not fast enough to reliably call you back every n microseconds.

function animate(element, prop, period, value) {
    var v0= parseFloat(element.style[prop] || 0); // assume pre-set in px
    var dv= value-v0;
    var t0= new Date().getTime();
    var anim= setInterval(function() {
        var dt= (new Date().getTime()-t0)/period;
        if (dt>=1) {
            dt= 1;
            clearInterval(anim);
        }
        element.style[prop]= v0+dv*dt+'px';
    }, 16);
}

Upvotes: 1

Alex Sexton
Alex Sexton

Reputation: 10451

You can run into rounding errors that will end up adding up to a different value than you expected. You might take a look at a really simple animation library and see the method they use to overcome this (as well as some easing techniques). Here is Thomas Fuchs' Emile which is about 50 lines of code:

http://github.com/madrobby/emile/blob/master/emile.js

Upvotes: 1

Related Questions