Building Time-lapse Visualizations with React Hooks and D3 (part 1)

John Bellizzi
4 min readMar 29, 2020

--

Note: This is part 1 in a 3-part series. The second part of this tutorial can be found here, and part 3 can be found here.

Interactive transitions in our visualizations add context to changing elements across different data states (see Mike Bostock’s article on object constancy). This can be especially powerful for changing events that occur in geographic space. Above, we have an example of a visualization we are working on that demonstrates the growth of COVID-19 cases over time across the US. The timeline at the top automatically plays through a daily series of events, and can be clicked to act as a selection filter.

The charts are built using React Hooks to control the time functionality, and D3 to plot the line and map. In this article (part 1 of the series) we are going to go over how the timer hook is built, and how we can use it to display time and control play state. Later pieces in this series will show how we use the time along with data to plot cases on the map, as well as adding more control to the timer.

With React Hooks, we can compose hooks together to create our own custom hooks that internally keep and update state. Our timer hook initializes with a start and end date, a step period, and an update frequency. What we get back is the current time state, and functions that allow us to play, stop, and update the time.

Our custom hook takes in the following properties

  • startTime: Minimum time of timer
  • endTime: Maximum time of timer
  • step: Number of milliseconds the timer increases by on each tick. If we want our timer to increase by 1 day every tick, we will set our step to be 1 day * 24 hrs/day * 60 mins/hr * 60 secs/min * 1000 ms/sec = 86400000 ms
  • frequency: How many times per second the timer increases by the provided tick. A value of 1 with the above step will increase the timer value by 1 (86400000 ms) every second

From this, we get the current state of the timer that can be displayed, and functions that allow us to control the timer.

We can decrease our step to 60 * 60 * 1000 = 3600000 so that every tick increments the timer by 1 hour instead of 1 day

This is a pretty slow update though, so let’s see what happens when we also increase our frequency to 24 ticks per second

This looks great, but what’s going on within the hook? Let’s dive into the useTimer function.

The first thing we do is set up and initialize our time state using the useState hook with the startTime as the initial value. For ease of internally maintaining and updating time, we’ll store it’s value as a number in milliseconds. We also set up a state for whether the timer is playing.

With a useEffect hook, we can run a side effect every time the state of isPlaying changes. When it’s equal to true, we’ll run the interval at the frequency input and update the time by 1 step with every interval run. (Note: we cleanup the effect by clearing the interval every time the component un-mounts).

We also set up a play and stop function to control the isPlaying state. Stop is called internally when time’s value is equal or greater than the endTime. These functions are exposed so that a parent component can control the play state (as we see in the example above with Play and Stop buttons).

We now have a timer that gives us the state of an updating time, and control over the timer. Look out for the second part of this series, where we will see how to use the time returned from this timer to render the trend line and map charts using D3. To see the full code, check out the project on GitHub.

--

--