⚠️ This lesson is retired and might contain outdated information.

Make an Interactive Bitcoin Price Chart with React, D3, and VX

Jason Brown
InstructorJason Brown
Share this video with your friends

Social Share Links

Send Tweet
Published 6 years ago
Updated 6 years ago

In this lesson we'll walk through building an interactive bitcoin price chart. We'll use React combined with VX to render our chart and tooltips. D3 will power all of the data processing to ensure everything is rendered where it should be. We'll also walk through explaining what scales, ranges, domains and bisectors are and how to use them.

Instructor: [00:00] The first thing in our app that we're going to do is set up some data fetching from CoinDesk. We're going to load the historical data from the past 30 days. The data that it returns is an object with the key that is a date and that key's value as the price.

[00:19] This is a little bit less than ideal for dealing with things that require functional calls like map. We're going to transform them into an array of objects with the date as well as the price so that we can work with it a little easier.

[00:36] Now that that is all set up, let's take a look at our package.JSON. We've already installed some dependencies from VX as well as some dependencies from D3 that we can use.

[00:47] We need to set up our SVG. We need it to be the width and the height of the screen. Typically, you would give it some sort of width and height. Because we don't have any constraints, it'll just be the width and the height of the screen. We're going to set up const width is equal to window.inner width as well as height is equal to window.inner height.

[01:13] Inside of our render, we'll also need to set up a few more values. We're going to define a padding which we'll just say is 100. Then we'll define our X max, which will be the width minus our padding, as well as a Y max value, which will be our height minus our padding.

[01:38] Now inside of our div here, we'll open that up. We will add our SVG. We're going to say SVG width is equal to our width. Our height is equal to our height. We'll close this.

[01:58] Then additionally, just so that we have something in here, we have a background that we can render against. We're going to create a rectangle which we're going to position at the top left corner to start.

[02:08] Rect takes an X which we'll set to zero and Y which will also be zero. That will push it in the top left corner. We'll then supply it with a width, which will just be our width, and our height, which will be our height.

[02:26] Unlike normal DOM elements, we need to provide it with a fill rather than a background color. We're getting to prep it with a fill. We're going to give it the color 32DEAA. If we take a look at how this is shaping up in the browser, we can see that we have a square that's a green square that covers the entire screen.

[02:53] Now that we have data and an SVG to work with, we need to set up our data selectors. The first thing we need to do is set up our X selector. This will take a single data point and then return a new date. We're going to say new date. Our data looks like this, d.date. Then we're also going to set up our Y selector which will take a data point and just return d.price.

[03:25] Now we'll need to import two functions from VX. These are wrappers around D3 anyway. This is basically like using D3 but a little easier to use. We're going to say at VX slash scale. The two that we're going to pull in, the first one is scale time and then scale linear. This will be used for X axis because we're dealing with dates and times. This one will be used for our Y axis because we're dealing with numbers.

[04:00] In order to use these, we need to have access to our data as well as the dimensions that we've defined as the X and Y max. That means we need to define these in our render function. We're going to create scales. What scales will do is they're going to translate from a pixel coordinate to a value or a value to a pixel coordinate.

[04:24] For our X scale, we'll say const X scale is equal to scale time. This will take an object. We're going to first define a range which will be an array as well as a domain. Domain will also be an array.

[04:45] But we're going to use some D3 functions from D3 array to help us out. We're going to import extent and max from D3 array. Come back down to our render. We can use our extent and pass in our data. Then we'll also pass in our X selector.

[05:08] What that's going to do is it's going to find the low end of the dates and the high end of the dates and return a array of two items, one with a low and one with a high.

[05:18] For our range, we need to define the range of the dimensions that we want to render into. In our case, we want to render into the padding as the absolute minimum X. Then the X max will be the absolute maximum on the X axis that we can render.

[05:39] What that means is, rather than rendering zero at the very edge of the screen, when we ask to translate a value -- for example, we ask X scale to translate a value -- rather than rendering at the zero point, it will render at the 100 pixel point and then also only go to the Y max which is 100 pixels in from this side. It might be confusing with time. But it's a little more clear with values like the price.

[06:13] We're going to set up our const Y scale. That's going to be a scale linear. The first thing that we need to do is get our maximum data. What our maximum data is going to be, call it data max, we'll use our max, pass in our data, and our Y selector which will loop through all these data, ask the Y selector with the data point which will return the price, and we'll get our maximum price.

[06:43] Now we'll then define the range. Just like before, we're going to do a slight reverse and say Y max in padding. The domain will be zero to the data max plus the data max divided by three. What this scale linear is doing is creating a proportional link that is based upon the width and height that we have to render into and is able to map these values and anything in between zero and our data max.

[07:19] Any price in between zero and our maximum price plus a third of our maximum price just for some padding up top. It will map it to the actual coordinate because zero and our data max are not actually coordinates on the rendering system of the SVG DOM.

[07:40] If we take a look here, when we say Y max of zero, what's actually happening is Y max will be down here because it starts at coordinate zero-zero. When we say value of zero, it's actually going to start and render here. However, if we go to our data max, it'll render to the padding. Our padding would be 100 which is actually for the SVG coordinates system up here.

[08:13] When asked for, say, 10,000, then it will say, "That's our data max. Then with some padding, we've put it down here." But basically, this scale linear is a way to take a value of your data and then map it to a coordinate system that will actually render SVG correctly.

[08:36] Then there's also the other ability to take a coordinate point, like a mouse movement and a mouse event, X and Y, and then translate it back into a value.

[08:48] Now that we have everything we need to render a line path, we're going to now import line path from at VX slash shape. The line path takes a few different properties. We're going to walk through this. We're going to take the line path. We're going to provide it our data. That data is an array of dates and prices. It's going to loop over each of those.

[09:18] It's going to pass in the X selector and Y selector. That will then return each individual data point which will then call the X scale and Y scale functions and take those values and then translate them to the screen at their appropriate coordinates. We're then also going to give it a stroke with a five stroke color. We're not going to fill it with anything. We're also going to have a stroke line cap of round.

[09:47] If we go take a look at what happened, we can see that we're now rendering our line path on the screen. If we inspect our elements, you can see that it is not rendering something that says 10,000. But it's actually translating a coordinate value of whatever to 100 and 305. These are the X and Y coordinates. It says move and then start drawing from 100 and 305.

[10:22] Now that we have our line rendering, we need to capture a mouse event so that we can figure out exactly what data points we need to highlight. We're going to import a new shape called bar. With our bar, we're going to render it at X zero and Y zero, so top corner, and then width and height, so we can capture all of the mouse events.

[10:49] If we don't actually render that bar and we take a look and we try to get mouse events on our line path, it would only work if our mouse passed within that blue box. Now if we save this and go take a look, if we look at our bar, we can see that our rectangle is covering the entire thing. We'll actually capture all of the mouse events and configure out.

[11:19] We don't have to pass directly over this line path to actually trigger our mouse events. We're going to do that with the on mouse move and the on mouse leave. This'll determine when we hide and show our tooltip.

[11:45] Before we set that up, we need to import some stuff from VX. The import will be the width tooltip higher order component as well as our tooltip. We'll pull that in from at VX slash tooltip. We'll also pull in from our D3 array bisector. We'll explain what that does in a second. Also, from VX, we're going to import local point from at VX slash event.

[12:26] We're going to set up another function from D3. We're going to call it bisect date and say bisector. We're going to pass in a selector. We're going to be operating on the dates. We're going to say X selector. We're going to say left.

[12:49] Our method to handle the tooltip will look something like this. We're going to take our show tooltip that is from the higher order component which we can apply now. We're going to say with tooltip. That will inject some properties like show tooltip. When this function is called, we're going to take the event and get the X coordinate. We're going to use our X scale and do an invert.

[13:18] What the invert does is it takes this scale that we have set up here. Rather than taking a value like a date and turning it into a coordinate that we can render, we take a coordinate and then turn it into a date. Then we'll use bisect date to pass in the data, the date, and the lowest we can go which we'll just say an index of one is the lowest we can go. This will determine where that date is.

[13:52] If I move my mouse left and right, it will produce an X coordinate. We want to translate that X coordinate back into a date and then subsequently back into an index that we can determine what data point we're actually dealing with.

[14:10] This bisect is typically used for insertion. The dot left is referring to if you were to want to insert a value. Say you have an array of one, two, three, four and you wanted to insert three. There's already a three in that array. You say that the value you want returned to be on the left side of the three that already exists there.

[14:38] For us with the date, it's just returning the left-sided index if it happens to return a date that matches a date in our array of data exactly. We'll get our two data points, one for the index before and our current index. Then if we have a future, a next index, then we'll see which one our mouse is closer to.

[15:07] If we take the coordinate and then use our X selector, which is X selector, will return a date which then will have get time called on it. We're using some JavaScript coercion here. It will return whichever one is larger. Whichever one happens to be larger will then take the inverse of that.

[15:31] Once we have our data point selected, we'll then do a tooltip data which is a piece of data for show tooltip as well as tooltip left and tooltip top. This function expects these properties.

[15:45] We take our data point and pass it through X selector and Y selector and then X scale and Y scale. This will then translate it from a date value and a price value which we'll select and then pass into our X and Y scale which will then turn it back into a coordinate that we know we're able to render at.

[16:08] In order to call this function, we need to come down here and replace our on mouse move and on mouse leave with a function that returns a function. Basically, VX is calling on mouse move with data which then expects an event handler function to be returned which we can then call with our X selector, Y scale, and X scale and our data as well as the event of the mouse coordinate.

[16:37] The reason we need to pass those in is because they're defined here and not up here. Otherwise, we'd have to define these outside of the scope or somehow. It's just easier to call a function with some functions that handle tools that we can use.

[16:55] To provide access to these, this hide tooltip, we're going to destructure some data. These are passed in from the higher order component, so you don't have to necessarily control them when you are doing set...You don't have to use a set state. You can just use a show tooltip. They'll be injected into the component that you want.

[17:22] Nothing should be different here. Now we can render our tooltip because we have all of the necessary data that we need.

[17:31] We need to import and set up one more thing. We're going to pull in the line from our VX shape as well as importing time format from D3 time format. We need to set up a formatter for our data so that we can render it in our tooltip. We're just going to render in a time format function that we can call it with a date and have it render and have it format correctly.

[18:01] Now we can apply our tooltip code. We're going to paste this code in here. What this code is going to do is going to look at if we have any tooltip data. Hide tooltip once we leave will actually remove our tooltip data. We'll then render a line. This line will go from the tooltip left that we have defined as our X coordinate and then run from the top of the screen all the way down to the bottom of the screen.

[18:32] We'll also apply a circle and place it at the tooltip left and tooltip top. It'll actually be on the data point that we want.

[18:42] Outside of the SVG, we can see here that we're rendering our other tooltips. These will be the values that we're rendering. We will use our Y selector and grab our tooltip data. Our Y selector will be our price. We'll render it at the top and left minus a little bit of offset, so we're not actually covering the dot that is at the data point.

[19:08] Then we'll do a tooltip. We'll use our X selector, pass in the tooltip data to select our date, and then pass to our format date. This will then center it on the line and will render at the Y max with a little bit of offset at the particular data point. We'll need to finish off with our closing div tag that accidentally got deleted.

[19:31] Now if we go and take a look at our app, we can see that we are rendering a line as well as the data point here. Then our two tooltips are rendering with the monetary value and our centered date.

egghead
egghead
~ an hour ago

Member comments are a way for members to communicate, interact, and ask questions about a lesson.

The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io

Be on-Topic

Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.

Avoid meta-discussion

  • This was great!
  • This was horrible!
  • I didn't like this because it didn't match my skill level.
  • +1 It will likely be deleted as spam.

Code Problems?

Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context

Details and Context

Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!

Markdown supported.
Become a member to join the discussionEnroll Today