If you’ve ever built a graph from scratch before, you know it might not exactly be a walk in the park. At Smartcar, we wanted to create a graph that would showcase our users' API usage over time and give them insights into the requests they've made, so we confronted this issue head-on.
And here's how you can do it too:
Getting set up 👩🏫
To kick things off, you’ll want to create a React component for your line chart with a few familiar lifecycle methods:
componentWillUnmount, and of course
- First, let’s add an
<svg>element, specify its dimensions, and give it a name. This will let React add our line chart to the DOM and make it easily accessible to D3. Since we’ll want it to be responsive, let’s have it fill the 100% of the available width. Now would also be a good time to start a
d3Config.jsfile where you can keep track of various graph configuration options, like the height of your line chart.
- At Smartcar, we use Redux to pass shared state into our connected components, so in this example we'll assume that your
timeSeriesDatais fetched from another component and passed into
<LineChart>as props. In
componentDidMount, we'll want to build the framework for our chart, so let's create
d3Utils.jsand plan to add a method called
initializeChartthere to handle this. This function will be called with your time series data and the time frame over which you'd like to initially graph your data, like
oneYear. For simplicity, we'll assume this is
Now you'll have something like this:
Building with D3 📈
Now we're ready to start building out
d3Utils.js and actually put the pieces of our line chart together. Since we're building a time series graph, we'll be working a lot with dates and timestamps. At Smartcar, we wrap a library that can handle this, like moment.js or date-fns, in something we'll refer to as
dateUtils. Alright, let's get started by creating the most fundamental part of the graph — the scales and axes.
- For our x- and y-scales, we'll need to set the domain (the set of possible input values) and the range (the set of possible output values). We'll also need functions that will be able to place our data points appropriately on the axes with these scales.
- For our x- and y-axes, we'll need to specify the orientation — top, left, bottom, or right — and the number and format of ticks on the axes.
- As we're building a time series graph, our x-axis will handle dates and our y-axis will handle numbers.
Now that we've set up these elements for our line chart, we'll also need to use D3 to specify their place on the DOM. Adding the axes and line to our graph will look something like this:
Awesome! Now we're ready to put it all together. Let's attach our axes and line to their designated DOM elements. Finally, let's write the method we mentioned a bit earlier:
Dynamically graphing data 🤓
In the previous two sections, we set up a basic time series line chart and rendered it in our React component. Now, let's enhance the dynamic capabilities of our graph and enable it to update when new data comes in. As you might have guessed, this starts with the lifecycle methods of
<LineChart> , specifically
componentDidUpdate. In this function, we'll watch for changes in our data and trigger readjustments when necessary.
Now that we have the React side of things ready to go, let's write our
d3Utils.handleNewData method to make the necessary adjustments to the graph itself. When new data comes in, we'll mainly want to check for two things:
- If the time frame of the data changes, we'll need to make a change to the x-scale. The start and end values which we initially set to span the domain of our x-axis will no longer fit our new data, so we'll want to write an
adjustXScalemethod to handle this.
- If the possible domain of values on the y-axis changes, we'll need to make a change to the y-scale. The maximum that we previously set for our y-scale's domain may no longer be appropriate to best display our new data, so we'll want to write an
adjustYScalemethod to handle this.
Here's an example of how you might want to do that:
Finally, we can write our
handleNewData method with the functions above. We'll have to re-draw the elements of our graph to render the changes on our line chart.
Voilà! Now your time series line chart can dynamically update to showcase the most recent data available.
Making your line chart responsive across browsers 📱
The final optimization we'll detail today is how to make your graph responsive across browsers. Because the scale of our x-axis is determined by the width of the graph, we'll need to adjust this accordingly for different screen sizes. To handle this functionality, let's first make our final changes to
<LineChart>. We'll need to add an event listener to our component in order to detect changes in screen size (and remove it when the component unmounts) as well as write a method to set the new width. After all these changes have been made, our component will look something like this:
And last but not least, let's write
d3Utils.setWidth. In order to get the current width of our line chart, we'll simply find the SVG on the DOM, measure its width, and adjust the range of our x-scale accordingly.
And there you go! Now you have a dynamic, responsive time series line chart built in React and D3. 👏👏👏
Bonus features ✨
At Smartcar, we've added a few extra bells and whistles to our usage graph to spice it up a bit. Give them a go yourself or try adding something totally new to your shiny new line chart! Here's a short list of ideas that we've tried out, to name a few:
- Draw the line with a gradient stroke to make the edges fade
- Add a filter to give your line a drop shadow
- Dynamically render ticks on your x-axis based on how long your time frame spans and how wide your graph is
- Style elements of your graph using CSS
We hope this helps all you developers out there next time you create an awesome time series line chart with D3 and React. Thanks for reading and happy building!
P.S.: Interested in what else we're up to? Here's a secret: We're hiring! 🤫