Here's part 2 of Kiran B's challenge from last week 👉 animating our drilldown piechart.
You can watch the whole stream or keep reading. This was fun to figure out. I'm loving the flexibility of this hybrid approach to animation.
Yelling at my computer when it got too slow to run CodeSandbox was A+ 👌
And if you prefer to jump straight into messing around with code, here's the CodeSandbox
Wtf is hybrid animation?
Hybrid animation is a merger of two approaches to animation I teach in React for Data Visualization. Also a brand new chapter I just added ✌️
- Change state 60 times per second, trigger re-renders, components look animated
- Give control to D3, use a transition, move back to React
Both those approaches work great.
You get heaps of control with the state-based approach, it's fast, the animations look sick, and you spend a lot of brain cycles thinking about details.
Transitions are easier, look great, and you mess with the DOM just a little. React doesn't like that but will tolerate your shenanigans if you're nice about it.
But transitions fail when you have complex scenarios with animations spanning multiple components.
And that's where hybrid animation comes in 👉 ease of transitions, full render control.
Cleaning up our piechart
We're working off of the drilldown piechart from last week. So we've got the basics
- Hierarchical data where each slice has multiple children
<Arc>
component that renders individual slices<DrilldownPie>
that uses ad3.pie()
generator and renders slices in a loop
We cleaned up state management and added the drill-up feature.
useDrillableData
is a custom hook that takes our data and sets up a reducer so we can tie different state changes together.
When you drilldown
we
- change
renderData
to the children array; this creates the drilldown effect - add current data to the
stack
; this will help us know how to drill back up - update
startAngle
so pie animations look connected to what you clicked
When you drilldown
we
- pop the previous data from the
stack
and updaterenderData
- drop the last element in our
stack
- keep the same
startAngle
If you're at the highest level already, we do nothing.
To use this new state management mechanism we replaced the previous useState
code with useDrillableData
and called dispatch
on click events instead of setState
.
Now <DrilldownPie>
can go in both directions. That was a problem before 😅
Adding hybrid animation
Hybrid animation is all about leveraging both React and D3 for what they do best: React manages rendering and events, D3 calculates the tricky stuff for smooth animations.
Here's the recipe:
- trigger a React effect
- start a D3 transition
- create a custom tween
- use the tween to drive state
useEffect
runs its method when renderData
changes. That's every time you drilldown or drillup.
The effect runs a D3 transition on an empty selection. Sets duration to 3 seconds, an easing function to look pretty, and fires off a custom tween.
Tweens are meant to manipulate DOM attributes, but when you think about it, they're just functions that run on every step of the transition. They can do whatever you want to do on every keyframe. 🤔
We start with an interpolator from 0
to 100
. Interpolators translate the time parameter, t
, into a smooth transition from start to end. Easing functions manipulate that t
parameter to create fun effects.
Interpolator in hand, we return a parametrized function that updates state with setPercentVisible
using the interpolator.
percentVisible state
Using that state change to animate our piechart looks like this:
percentVisible
and setPercentVisible
come from a useState
hook. Getter and setter :)
D3 pie generators take a startAngle
and endAngle
config and fit the entire piechart between those angles. If we keep changing the endAngle
to be closer and closer to a full circle based on percentVisible
, we get an animation that looks like a piechart revealing itself.
Neat 🤘
Wat gives
The trick here is that React hooks are magic and the tree diffing algorithm is fast as hell.
On each step of the transition, our tween changes state and triggers a re-render. When the piechart re-renders, it uses the updated angle.
The updated angle creates a bigger piechart. The arc components adjust and make themselves fit inside.
Crucially, React doesn't re-run the effect. Nothing that our effect relies on changed, so it keeps running uninterrupted.
The result is a powerful new animation technique ✌️
Cheers,
~Swizec
Continue reading about How to drive React state with D3 transitions for complex animation
Semantically similar articles hand-picked by GPT-4
- A Drilldown Piechart with React and D3
- Silky smooth Piechart transitions with React and D3.js
- Livecoding #19: It’s hard to package a library
- Behind the curve ... of my bar donut chart 🤨
- Livecoding #34: A Map of Global Migrations, Part 3
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below 👇
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️