In real life, things don’t just suddenly disappear from one place and appear in another. This isn’t Harry Potter1. We can’t apparate.
But chances are, you know that, and don’t need to be convinced of the wonder of animation. So, instead, I will tell you about the beginnings of SproutCore’s support for animation.
SproutCore’s animation support currently takes the form of a mixin for views: SC.Animatable. Here are some of the features:
- Relatively fast. It can animate 1000 or so views with reasonable performance on a fast machine. Oddly, the biggest performance hurdle may now be the rendering engine (unless you are on IE—the slow script speed will kill you first).
- Uses CSS transitions where possible. Oddly, CSS transitions do not appear to be significantly faster2 than JavaScript transitions (again, indicating the rendering engine could now be the bottleneck).
- Support for Layout. This almost goes without saying, as what animation framework would be worth anything if it didn’t allow you to animate the position of views?
- Support for Opacity. So you can fade things in and out.
- Support for display:none. You can add transitions to the display property, and they will simply be ignored (display gets applied immediately) except in the special case of display:none, which will only apply after the specified duration. See display:none notes
- Support for Timing Curves. You can specify curves to adjust the speed of the animation, and have them work in both JavaScript transitions and CSS transitions, or optionally, CSS transitions only.
Animating with SC.Animatable
It is quite simple. Here are the steps:
- Add “sproutcore/animation” to the required frameworks array in your Buildfile (in quotes and all).
- Mix in SC.Animatable to your view.
- Add transitions.
- Change layout, opacity, or display.
So, how about some code? First, let’s take a look at a Buildfile:
# The Contacts application Buildfile config :contacts, :required => [:sproutcore, :"sproutcore/animation", :forms, :pomona]
Now, how about a view?
myView: SC.View.design(SC.Animatable, { // mix it in transitions: { // and add transitions left: .25, top: {duration: .25}, width: { duration: .25, timing: SC.Animatable.TRANSITION_EASE_IN_OUT }, // with timing curve height: { duration: .5, timing: [0, 0, 0.58, 1.0] }, // with custom timing curve opacity: { duration: .5, timing: SC.Animatable.TRANSITION_CSS_EASE_IN_OUT }, // CSS-transition-only timing function (JavaScript gets linear) display: .75 // a bit longer than opacity } })
And finally, to animate!
myView.adjust("left", 250); myView.set("layout", {left: 100, top: 300, width: 250, height: 340}); // style manipulation: a feature of SC.Animatable myView.adjust("opacity", .5); myView.set("style", {opacity: .7}); myView.adjust("display", "none"); // applies after .75 seconds myView.adjust("display", "block"); // applies immediately // disable animation temporarily to change something directly myView.disableAnimation(); myView.adjust("opacity", 0).updateStyle(); // makes invisible and applies immediately. myView.enableAnimation(); myView.adjust("opacity", 1); // fades in to visibility (applying lazily).
Pretty simple!
display:none notes
When animating the display: none property, you should add a bit of extra time to its transition.
If everything was animated using JavaScript, there would be no issue. However, because SC.Animatable takes advantage of CSS transitions where possible, and CSS transitions don’t necessarily begin immediately, if you don’t add extra time to display’s transition it could set display:none before the other transitions end (in effect, cutting them short). In the most usual case—an opacity transition—the view will start to fade out and then suddenly disappear. Again, the easiest way to fix this is by simply adding a bit of time to the transition for the display property.
The Problem with Callbacks
Currently, SC.Animatable does not have callbacks for animation completion. In fact, unless the view is being animated using JavaScript (non-WebKit browsers and Firefox earlier than 3.6, I believe), it is even impossible to tell if a view is animating.
For JavaScript-based transitions, this should not be a terribly difficult feature to add in general; there is a question of, since animations are started and stopped automatically instead of explicitly by the developer, how those callbacks would be set: should it be one per property? One per the whole view?
For CSS transitions, however, this is trickier. There is an event fired in WebKit’s implementation, but I am unable to find any documentation on Mozilla’s support for it (or, for that matter, lack thereof).
Even if support was present, it may or may not be tricky to reconcile that with the actual animation library: what if one transition ends, but a new one starts immediately after? Will the event fire after the new one begins, tricking others into thinking it has already fired? It may be more reliable to “guesstimate,” and just set a timer for a callback to go off somewhere shortly after the target time (much like the way the “display” transition is implemented).
Demo
It is not “officially” released by any means—it still needs fixes, including at least one animation-related one—but a fancy demo of the animation (used in FormView, another project I am working on) can be found here.
The code is all online too at GitHub. I am slowly making it into a full sample app for SproutCore that demonstrates animation, FormView, and Comet—and hopefully multiple back-ends (I’m working on a wacky Python one right now, and I’d like to make a node.js-based one eventually, too).
-
It is tricky to tell, because I cannot measure the FPS of transitions objectively. Actually, the JavaScript transitions looked faster than the CSS transitions. ↩
-
I love footnotes too much. In some papers, I have filled almost half the page with footnotes. The thing about footnotes is that they allow you to add extra information (sometimes a lot of extra information) while not badly interrupting the flow of the original piece. ↩

[...] blog « SproutCore Animation: SC.Animatable [...]
Great article. What I don’t understand is why SC doesn’t work fine on my iPhone. I hardly succeed to click on names in the address book after trying several times, animations and fields filling are quite slow and I could’nt select any value with the radio buttons. Finally, Safari crashed when I was trying… Why don’t SC use standard HTML form elements ?
The basic reason is that touch events are much different than click events. SproutCore iPhone apps should be written using special SC controls for iPhone. I believe there is some work on getting this going, but it is far from complete from what I’m aware.
Can we use the mixin on panes? Not having much luck with that right now :(
Panes are slightly more complex to animate because they have no parent view to call their updateLayout function. There may be other issues as well, but it should help if, after calling .adjust, you call .updateLayout() to tell SproutCore to relayout the view (and as such animate it).
Hope that helps!