I’d started out by picking two simple shapes from
Here’s what, eventually, I ended up with: (Direct link; view source for the implementation.)
Initially I’d figured using
should suffice and would be fairly straightforward – but that quickly (and
quite literally) went awry:
rotate didn’t suffice because line
lengths differ between the original and the target icon, yet applying
fix that resulted in a skewed projection. After learning that
- the order of transforms is significant (which makes perfect sense in hindsight… )
pxtranslate to user units when applied to SVG (as a pixel denialist, I was very wary of this)
I managed to create something a little closer to what I had in mind – but it still looked awkward and relied on magic numbers. This being me, eyeballing it was not an option. Neither was Pythagoras: Figuring out the math required to accurately transform the original shapes proved sufficiently annoying (also with respect to posterity) that eventually I went looking for a different approach – though not before descending down a rabbit hole of arduously refreshing my long neglected understanding of vector matrices.
Thus I arrived at
I had believed this to be deprecated, but turns out Google
have since relented.
And indeed, SMIL is about as straightforward as I had imagined:
allows specifying a before and after state with the same attributes used in the
actual shapes, the engine takes care of calculating the transition. Thus
both shapes are combined within a single
from redundancy is slightly irritating.)
In order to avoid excessive redundancies animating
y2, each of which would have required an
<animate> declaration), I manually converted them to
reducing the shape definition to a single
d attribute. Where with CSS before
<animate> element to kick off the animation on demand.
However, that still leaves reversing the animation and providing a fallback for browsers that don’t support SMIL. Both proved similarly straightforward, e.g. using a custom element:
It’s rather pleasing that our code here only has to know about
declarative instructions; note how the fallback reads the desired target state
<animate> and applies it directly to the corresponding shape element. So
this implementation isn’t tied to our particular icons.
Thanks to the various friends and colleagues who patiently assisted in figuring this out. (The actual, err, path was even more convoluted than described here.)
It appears this doesn't work for arbitrary shapes though: There needs to be some correlation between
from(e.g. equal number of points within the respective shape definition) for the animation to be calculated correctly. ↩