JavaScript Animations

Posted in: javascript

Advanced DOM manipulation

Ajax

Animations

Defining an Animation Class

The duration of the animation (in milliseconds)

The frames per second of the animation

var options = { duration : 1000 , fps : 40 , onStep : function ( delta ) {}, onComplete : function () {} };

Implementing the Animation class

var fx = new Effect ({ duration : 1000 , fps : 40 , onStep : function ( delta ) { /* do stuff */ }, onComplete : function () { alert ( 'done!' ); } }); //start the animation fx . start ();

//define the class constructor function Effect ( opt ) { this . opt = { duration : opt . duration || 1000 , fps : opt . fps || 40 , onStep : opt . onStep || function (){}, onComplete : opt . onComplete || function (){} }; } Effect . prototype = { //define how the animation starts start : function () { //return if we're currently performing an animation if ( this . timer ) return ; //trigger the animation var that = this , fps = this . opt . fps ; this . time = + new Date ; this . timer = setInterval ( function () { that . step (); }, Math . round ( 1000 / fps )); }, //triggered at each interval step step : function () { var currentTime = + new Date , time = this . time , opt = this . opt ; //check if the time interval already exceeds the duration if ( currentTime < time + opt . duration ) { //if not, calculate our animation progress var delta = ( currentTime - time ) / opt . duration ; opt . onStep ( delta ); } else { //we already exceeded the duration, stop the effect //and call the onComplete callback this . timer = clearInterval ( this . timer ); opt . onStep ( 1 ); opt . onComplete (); } } };

Effect . compute = function ( from , to , delta ) { return from + ( to - from ) * delta ; };

var elem = document . getElementById ( "myElementId" ), style = elem . style ; var fx = new Effect ({ duration : 500 , onStep : function ( delta ) { style . width = Effect . compute ( 0 , 10 , delta ) + 'px' ; } }); fx . start ();

Extending the Effect class

var elem = document . getElementById ( "myElementId" ); var fx = new Effect ({ element : elem , duration : 1000 }); fx . start ({ 'width' : [ 0 , 20 , 'px' ], 'height' : [ 0 , 5 , 'em' ] });

//define the class constructor function Effect ( opt ) { this . opt = { element : opt . element , duration : opt . duration || 1000 , fps : opt . fps || 40 , onComplete : opt . onComplete || function (){} }; } Effect . prototype = { //props contains a hash with style properties start : function ( props ) { if ( this . timer ) return ; var that = this , fps = this . opt . fps ; this . time = + new Date ; this . timer = setInterval ( function () { that . step ( props ); }, Math . round ( 1000 / fps )); }, //triggered at each interval step step : function ( props ) { var currentTime = + new Date , time = this . time , opt = this . opt ; if ( currentTime < time + opt . duration ) { var delta = ( currentTime - time ) / opt . duration ; //set the element style properties this . setProps ( opt . element , props , delta ); } else { this . timer = clearInterval ( this . timer ); this . setProps ( opt . element , props , 1 ); opt . onComplete (); } }, //set style properties. Properties must be //in camelcase format. setProps : function ( elem , props , delta ) { var style = elem . style ; for ( var prop in props ) { var values = props [ prop ]; style [ prop ] = Effect . compute ( values [ 0 ], values [ 1 ], delta ) + ( values [ 2 ] || '' ); } } };

Please enable JavaScript to view the comments powered by Disqus.

Disqus

JavaScript animations are a key aspect of dynamic Web Sites and Application development. Moreover, most JavaScript Frameworks or Libraries provide APIs for dealing with at least three main things:When developing Web Sites most JavaScript effects involve rendered DOM Elements, but sometimes JavaScript animations are used in other contexts, like when using the Canvas. In the JavaScript InfoVis Toolkit the main target of my animations are Graphs, and in the next version also Nodes and Edges as separate entities. Today I'd like to describe how to create a generic animation class that can be used or extended for any purpose. I'll try to be minimalistic and to present only the needed code for making animations. Then you might find useful to add some code to perform specific animation tasks targeting for example specific style properties of a DOM Element.Before creating an Animation class we might want to consider what to expose as options to the user. The options I thought of are:Additionally we'd like to add a couple of controllers, one when a step of the animation is executed and one when the animation has completed:delta gives us an idea of the progress of the animation. When the animation starts delta will be equal to zero. When the animation ends it'll be equal to one. We will also need a start method to trigger the animation and a step method that will compute delta at each step. Now that we defined our options we can start thinking about our implementation.Our Animation class will be a class constructor that sets all the options and properties that we defined before and a prototype with the methods start and step. The class could be used like this:Here's the code I came up with, inspired by the MooTools Framework:One very common operation to do with delta is to change the interval [0, 1] of delta to our desired from and to values that we want to compute for our element. A clever thing to do would be to declare this method as a class method for Effect. We'll call it compute:Now If we wanted for example to animate an element's width style from 0 to 10px we could do:The animation code defined above could be extended in different ways. For example, this class could be slightly modified to accept a DOM element in its constructor and modify style properties of that element when performing an animation. The code could look like this:The code would now look more or less like this:Other extensions might involve normalizing style keywords, adding effect transitions, adding pause resume methods, and/or using more OO JS idioms when coding these classes. I hope you got to know a little bit more about animation internals and please if you have any advice on this code, which as I told before is just for demonstration, I'll be pleased to hear you!