Blog

Building D3 Components with React: Part 2

Part 2: Adding Animation 

In Part 1, we created a basic D3 component with React that responds to updates. We can take this a step further if we want. Animation is one of the things D3 does really well, but the details can be a bit challenging at first. We can abstract these away in our component and provide an easy way for anyone to reuse our work.

We’ll start by altering the setForeground() function.

setForeground(context) {
    return context.append('path')
    .datum({ endAngle: 0 }) // 

Initially we want our endAngle property of the foreground path to be at 0 and transition to the final percentage. Next we’ll modify ourdrawArc() function. We’re going to add updatePercent() to our function list, which we’ll define below.

...
drawArc() {
  ...
  this.updatePercent(context);
}
...
updatePercent(context) {
  return this.setForeground(context).transition()
   .duration(this.props.duration)
   .call(this.arcTween, this.tau * this.props.percentComplete, this.arc());
}
...

We’re calling setForeground() as we did before with our endAngle being set to tau * percent, but we’re adding a transition over a duration (based in milliseconds, which we’re passing in as a prop). We’re then calling another function, arcTween(), which we’ll define below.

arcTween(transition, newAngle, arc) {
  transition.attrTween('d', (d) => {
   const interpolate = d3.interpolate(d.endAngle, newAngle);
   const newArc = d;
   return (t) => {
     newArc.endAngle = interpolate(t);
     return arc(newArc);
   };
  });
}

arcTween() is using D3’s interpolate function under the hood to return a new D3 arc. After we add the duration prop to ProgressArc in App.js, we should see the animation working properly as we click the toggle button.

...

If everything went well, you should have something that looks like this:

 

d3-components-with-react

Conclusion

I prefer this implementation to using an external lib, because it allows me to precisely define the details of the visualization, and I’m not stuck fighting built-in styles or loading assets I don’t need. While it’s a little more work up front, the result is a lightweight solution that delivers exactly what I want.

Abstracting the implementation details of D3 into React components and using the component lifecycle allows us to create custom visualizations that are easily reusable throughout our application. Hope this was helpful! Thanks for reading!


Also published on Medium.