Useful Platitudes

Notes on programming by Daniel Mendel

New Compound Animations in glitz.js

glitz.js support for defining animations is pretty flexible, but it is designed for fairly simple interactive behaviors and has, until now, lacked a good method for building complex animations from component parts. I’ve wanted to add a good API for to do this for a while and this week I finally got a chance to do so, while pairing with Zach Allaun at Hacker School. I’m really excited about what we came up. First, I’ll explain the state of affairs before our changes.

Good, but not great

The animation API that glitz implements is very straightforward, if you’ve ever animated DOM elements with jQuery.animate then the syntax should be pretty familiar. All of the following animations are equivalent.

1
2
3
4
5
6
7
8
9
10
// transform ( duration defaults to 250ms )
box.animate({ x: 100 });
// transform, duration
box.animate({ x: 100 }, 5000 );
// transform, callback
box.animate({ x: 100 }, function(){ ... });
// transform, duration, callback
box.animate({ x: 100 }, 5000, function(){ ... });
// transform, options
box.animate({ x: 100 }, { duration: 5000, done: function(){ ... }});

If animate is invoked on an object while that object is still performing a previous animation, the current animation is immediately canceled and the new one begins. This is the default behavior because interactivity requires an immediate response from objects. If you want to build a complex series of animations, you can do so using nested callbacks.

1
2
3
4
5
6
// move left, then down, then fade the color
box.animate({ x: 100 }, 5000, function(){
    box.animate({ y: 100 }, 5000, function(){
        box.animate({ strokeColor: '#f00' }, 5000 );
    })
})

As you can imagine, this gets to be pretty ugly pretty quickly if you want even fairly simple sets of actions. Futhermore, it’s difficult to store animation routines and run them more dynamically – users would have to implement their own methodology which would, at the most simple, look something like this…

1
2
3
4
5
6
7
8
9
var anims = {
    left:    { x: 100 }
  , down:    { y: 100 }
  , turnRed: { strokeColor: '#f00' }
}
function run( series ){
    box.animate.call( box, anims[series.shift()], function(){ run( series ) } )
};
runSeries([ 'left', 'down', 'turnRed' ]);

Gross – we figured we could definitely do better than that.

Enter Compositions

First we thought it would be good if you could compose a series of animations like this:

1
2
// move left, then down, then fade the color
box.animate([{ x: 100 }, { y: 100 }, { strokeColor: '#f00' }]);

This is already clearly better than the alternative, but then we decided we had to include support to create parallel animations as well, something that was not possible in any way shape or form before.

1
2
// move left and down simultaniously but with different end times
box.animate([[{ x: 100, duration: 500 }, { y: 50, duration: 1000 }]]);

By combining these you can compose a series of parallel animations:

1
box.animate([[{ x: 100 }, { y: 100 }],[{ x: 0 }, { strokeColor: '#f00' }]]);

Or parallel series:

1
box.animate([[[{ x: 100 }, { y: 100 }],[{ strokeColor: '#f00'}, { y: 0 }]]]);

Or any combination thereof:

1
box.animate([{ x: 100 }, { y: 100 }, [{ y: 0 }, { strokeColor: '#f00' }, [{ x: 0 }, { strokeColor: '#0f0' }]]]);

That’s it! You can fork glitz.js and try them out for yourself.