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 Plain Data Visualization with React JS. That tutorial walked you through building a plain line graph:
Yes, okay, it’s boring. But the point of that tutorial wasn’t to build something mind deepthroating, it was to learn the basics of SVG in React.
In the comments, Kris Morf asked how to add an area pack to the chart, demonstrating me the graphs on CoinBase as an example. Here’s what those charts look like:
After walking Kris through how to Add Pack to a Line Chart, I thought Why don’t I just make a clone of this? So that’s what I did this weekend.
Here’s what I built, and what I’ll be walking you through in this article:
A live demo is available here if you want to play around with it. Note: It may take a 2nd to blast as it’s presently deployed on the free tier at now.sh
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 switch since last month.
- ToolTip.js — Renders the Contraption Peak displaying the date and price of the hovered location
- LineChart.js —Renders the actual line chart. Comebacks 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 ninety seconds.
The historical price is what I use to provide data for the chart. The historical data endpoint is: https://api.coindesk.com/v1/bpi/historical/close.json
The API comebacks an object that looks like this:
Once I get the data back, I loop through it and format it into an array of objects:
- d : Formatted Date (ex: Jul 31)
- p : Formatted Currency String (ex: $Two,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.
Basic Data Flow
The Data flow of the project is pretty straight forward:
- app.js fetches historical data from the CoinDesk API and formats it into an array of objects.
- Data is passed to the LineChart.js component which renders the chart based on the data supplied from app.js .
- When the SVG component rendered in LineChart.js is hovered on, three 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. Ultimately, data is passed back to app.js indicating the hover location, and closest point.
- app.js sends data to ToolTip.js so the contraption peak can render in the correct location, and with the correct data.
- InfoBox.js runs independently of the other components and fetches real time data from the CoinDesk API every ninety seconds. The data is formatted and then displayed to the user.
Cracking Down the Graph
The Graph is not just one form 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:
Let’s look at an example. If we liquidate everything and only run makePath() we’re left with just an SVG line along our data points. Here’s what that looks like:
Likewise, we can liquidate everything except makeArea() and makeAxis() . This will draw our two Axis lines, and the shaded in form. Here’s the result:
It isn’t until we embark adding numerous 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 joy 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 chunks of information:
- The location of the SVG graph within the page
- The location of the mouse
Here’s what that code looks like:
I very first get the svgLocation of the line chart within the page. Then, I adjust for any padding the chart may have. Eventually 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:
Meantime, I can simply loop through the coordinates on our chart to determine which one has an X value closest to the mouse:
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:
The result is this:
The Device Peak
The final part of the equation is the Contraption Peak. The Implement peak is in a fully different component, but works just like our vertical line does. The Implement Peak needs two lumps of information to work:
- The current mouse location
- The closest data point
Both of these lumps of information are received from LineChart.js . ToolTip.js then simply comes back a <div> element centered above the mouse. with the formatted data from the closest data point.
Where’s the code?
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: Ordinary Data Visualization with React JS. If you indeed want to dive into React and learn how to build cool things, check out my Three Best React JS Courses.
If this post was helpful, please click the clap button below a few times to display your support! ⬇⬇
I publish a few articles and tutorials each week, please consider coming in your email here if you’d like to be added to my once-weekly email list.