In the introduction of this venture into animations and functions, the animation was simply fading in one element (linearly). Enough for an example, but not really fitting if we talk animating multiple elements, or multiple properties.
We’d want to run multiple animations at the same time, maybe with specific timings, perhaps also control how the progress flows (easing, revert…).
Focus on the animation functions rather than the sources.
Let’s see how we can express that with little functions to compose into a bigger animation.
Progress, with a time source at least, flows linearly. It’s simple, but doesn’t give the animation a natural feel. In the real world, objects don’t start moving at their cruise speed straight away. If they ever move at a constant speed anyway. And equally, they don’t stop instantly once they’ve finished moving.
To mimic that in animations, we need something to alter how progress… well… progresses. That’s the role of easing functions. This is not only important for things to look natural, but easings also allow to play on the feelings conveyed by the animation: make something hurry out of the screen, or instead enter with a sluggish, heavy feel.
Easing functions have been around for a while, the most used being the list by Robert Penner, though you can define custom bezier curves or even use spring physics. So let’s focus on how we can use them with our animation. For that, we can write a wrapper function that will apply the easing before delegating the rest to the animation.
And with that, we can control how progress flows. On the same principle, we can write a function that will revert the animations.
These two simple examples show the general pattern we’ll be applying for the rest of the article and go towards coordinating the animation of multiple elements.
So far, we’re still stuck with running just one animation at a time. To animate the 3 dots, we need 3 sources of times.
It works, but if we could run it with only one source of time, it would make things a bit more reusable. With the same pattern as before (creating a new function that wraps the various animations we want to play) we can write this little function for playing them all in one go:
There we go! We can now play several animations from the same source of progress. One little issue though, they all run for the full duration. Let’s see how we can tackle that.
So let’s see how we can coordinate the movements of the 3 dots. Maybe make the second wait a little before it goes and quickly reaches the end so that the 3rd still have some time left to make its way back.
For this, we need to transform the progress that each animation receives. Each will need to go from 0
to 1 while the progress of the
parallel animation goes over smaller intervals.
Sounds a bit like easing, but it’s a very specific one. It sticks the progress to 0 while the progress hasn’t been enough, then ramps to 1 until the animation is done and from there sticks to one. It’s not so big to write on its own as:
We got there! Composing functions we managed to animate different things on their own timing.
Of course, like the rest of this adventure, this is just a base to get started. On this topic especially, reasoning in percentages quickly becomes tricky if we want to create complex animations, for example. Reasoning in absolute units, like milliseconds would be much easier.
And of course around the areas for making animations with functions. I’ve started to gather some code on the tinymation project on Github. If you have thoughts on the topic, maybe specific use case, I’d be really happy to head about them. Feel free to look at the code and add issues (or comment on the existing ones).