Saturday, January 18, 2014

Day 1000: Animated SVG in Polymer

For an ostensibly UI facing library, I have done almost no UI work while researching Patterns in Polymer. I think that speaks to the hidden power of coding with the library. Even so, it is a web based, UI library, so I ought to do some UI-like things. Enter last night's <x-pizza> tag—the SVG based pizza builder:

The pizza SVG in this Polymer is built by passing a “maker” function, which makes individual toppings (e.g. pepperoni), into add-topping methods:

It is a little hard to randomly distribute things in a circle, but happily there is Stack Overflow, which is the source for most of that.

It is nice to see the pizza built and all, but I would like to give hungry buyers more of a sense of building their own pizzas. Animating the toppings coming in from the side and dropping onto the pizza should do that nicely. I have no idea if that is possible with SVG, but there is one way to find out...

I start by grouping the toppings in an SVG <g> element. It turns out that you cannot set cx and cy attributes on group elements. Instead you have to translate them in a transform (that's gonna be easy to remember):

I have my toppings grouped and can position them together. How about animating?

Unfortunately, the <animate*> tags do not seem to work too well when trying to dynamically start animations. The <animateMotion> tag almost works… some of the time… when you don't hit reload too fast or stare at the page funny:

For whatever reason, that does not seem reliable and fails to work at all on Firefox. So it seems that I need to revisit my old friend requestAnimationFrame(). I have honestly been missing this since 3D Game Programming for Kids went to press, so I may be reaching for a golden hammer here. But I don't care, animation frames, which are functions that get called when the browser signals it is ready to paint, are cool.

It seems that Dart has a future-based take on animation frames. Given an animate() function, I can ask the browser to call it with window.animationFrame.then(animate). The function that animates pizza toppings sliding in from the side over the course of 1.5 seconds is then:

That does the trick. Just as with the JavaScript requestAnimationFrame(), I have to request the animate() function once and then recursively call it from within animate() afterwards to keep the animation running. The effect is a nice, smooth animation that starts with the toppings floating in from the side:

And settling down nicely:

For completeness' sake, I animate the toppings falling gently, like a mother putting a babe down to rest, at the end of the left-to-right animation: