How I built an Interactive 30-Day Bitcoin Price Graph with React and an API

July 26, 2017 0 Comments

How I built an Interactive 30-Day Bitcoin Price Graph with React and an API




Don’t care about the back story? Here’s a live demo of the bitcoin price graph I’ll be walking through (note: It’s not mobile-friendly yet — PR’s welcome). The GitHub repository with all the code is linked at the bottom of the article.

Last week I published a tutorial on Simple Data Visualization with React JS. That tutorial walked you through building a simple line graph:

Yes, okay, it’s boring. But the point of that tutorial wasn’t to build something mind blowing, it was to learn the basics of SVG in React.

In the comments, Kris Morf asked how to add an area fill to the chart, showing me the graphs on CoinBase as an example. Here’s what those charts look like: — much better looking
Yeah, that’s much cooler than my lame line chart.

After walking Kris through how to Add Fill to a Line Chart, I thought Why don’t I just make a clone of this? So that’s what I did this weekend.

A live demo is available here if you want to play around with it. Note: It may take a second to load as it’s currently deployed on the free tier at

Side note: If tutorials like this interest you and you want to learn how to build more cool stuff with React, check out the 3 Best React JS Courses.

Here’s what my project structure looks like. There are four react components.

  • app.js — Parent component.
  • InfoBox.js —Renders our realtime Bitcoin prices and change since last month.
  • ToolTip.js — Renders the Tool Tip displaying the date and price of the hovered location
  • LineChart.js —Renders the actual line chart. Returns a single SVG element.

For this project, the best API I could find is the CoinDesk API. If you have a better bitcoin API, please tweet at me and let me know!

The CoinDesk API offers both real-time and historical bitcoin price data. For this project, I display the real-time bitcoin price in the top left corner (InfoBox.js). It updates every 90 seconds.

The historical price is what I use to provide data for the chart. The historical data endpoint is:

The API returns an object that looks like this:

“bpi”: {
“2017–06–24”: 2619.1188,
”2017–06–25": 2594.4538,
”2017–06–26": 2485.3588,
”2017–06–27": 2593.17,
”2017–06–28": 2584.5638,
// ...

Once I get the data back, I loop through it and format it into an array of objects:

for (let date in bitcoinData.bpi){
d: moment(date).format('MMM DD'),
p: bitcoinData.bpi[date].toLocaleString(),
x: count,
y: bitcoinData.bpi[date]
  • d: Formatted Date (ex: Jul 31)
  • p: Formatted Currency String (ex: $2,000.46)
  • x: Count (numerical, beginning with 0)
  • y: Unformatted Price (2000.46738 — used for graphing)

The data is then sent to a child component that builds the chart. Here’s a higher level overview of the data flow.

The Data flow of the project is pretty straight forward:

  1. app.js fetches historical data from the CoinDesk API and formats it into an array of objects.
  2. Data is passed to the LineChart.js component which renders the chart based on the data supplied from app.js.
  3. When the SVG component rendered in LineChart.js is hovered on, 3 things happen: LineChart.js draws a vertical line on the cursor coordinates. It determines the closest data point to the cursor and draws a circle to highlight that data point. Finally, data is passed back to app.js indicating the hover location, and closest point.
  4. app.js sends data to ToolTip.js so the tool tip can render in the correct location, and with the correct data.
  5. InfoBox.js runs independently of the other components and fetches real time data from the CoinDesk API every 90 seconds. The data is formatted and then displayed to the user.

The Graph is not just one shape being drawn to the screen. It’s a collection of shapes and lines within a single SVG element. If you look at LineChart.js, you’ll see there are up to eight function calls used to create our graph:

this.makeAxis()         Makes Graph Axis
this.makePath() Makes Graph Line
this.makeArea() Makes Shaded Graph Area (under line)
this.makeLabels() Makes Graph Labels
this.getCoords(e)       When Hovered Gets Coords of Hover
this.createLine() When Hovered Makes Vertical Line
this.makeActivePoint() When Hovered Finds Closest Point
this.stopHover()        Clears Line and Point When Hover Stops

Let’s look at an example. If we remove everything and only run makePath() we’re left with just an SVG line along our data points. Here’s what that looks like:

Just a path. Boring.

Likewise, we can remove everything except makeArea() and makeAxis(). This will draw our two Axis lines, and the shaded in shape. Here’s the result:

A little more interesting than above.

It isn’t until we start adding multiple shapes and lines together that our graph starts to look interesting. Withholding the hover effects, Here’s our graph with makeAxis(), makePath(), makeLabels(), and makeArea():


The fun stuff happens when the SVG element is hovered over. On hover I run a function that gets the coordinates of the mouse on the graph. In order to do this we need two pieces of information:

  1. The location of the SVG graph within the page
  2. The location of the mouse

Here’s what that code looks like:

I first get the svgLocation of the line chart within the page. Then, I adjust for any padding the chart may have. Finally I take the x location of the mouse and subtract the pixels that are to the left of the SVG chart. This gives me the location of the mouse relative to the line chart.

State is updated, and a vertical line is drawn on the graph at the mouse’s X coordinate:

Meanwhile, I can simply loop through the coordinates on our chart to determine which one has an X value closest to the mouse:

let {svgWidth} = this.props;
let closestPoint = {};
for(let i = 0, c = svgWidth; i < svgData.length; i++){
if ( Math.abs(svgData[i].svgX — this.state.hoverLoc) <= c ){
c = Math.abs(svgData[i].svgX — this.state.hoverLoc);
closestPoint = svgData[i];
Note: As Francesco Zuppichini pointed out in the comments, a binary search would be a better solution than simply looping through the array

After finding the closest X value, we draw an SVG circle at that point:

const {color, pointRadius} = this.props;
return (
style={{stroke: color}}

The result is this:

The final part of the equation is the Tool Tip. The Tool tip is in a completely different component, but works just like our vertical line does. The Tool Tip needs two pieces of information to work:

  1. The current mouse location
  2. The closest data point

Both of these pieces of information are received from LineChart.js. ToolTip.js then simply returns a <div> element centered above the mouse. with the formatted data from the closest data point.

let placementStyles = {};
let width = 100;
placementStyles.width = width + 'px';
placementStyles.left = hoverLoc + svgLocation.left - (width/2);
return (
<div className='hover' style={ placementStyles }>
<div className='date'>{ activePoint.d }</div>
<div className='price'>{activePoint.p }</div>

Glad you asked. All the code for this project is open source and available in my GitHub Repo. The live demo, once again, is here.

If the SVG elements of this project interest you, I go into more detail on the graph in my previous article: Simple Data Visualization with React JS. If you really want to dive into React and learn how to build cool things, check out my 3 Best React JS Courses.

I publish a few articles and tutorials each week, please consider entering your email here if you’d like to be added to my once-weekly email list.

Tag cloud