Constructing a Price Chart SVG

Constructing an SVG chart component is a three-step process:

The shape and density of the price chart is the first thing to be considered — coinciding with your data set that determines the SVG dimensions to be used. Once determined, we can go ahead and template out an SVG as a React component, wrapping it in a styled component to cater for its size and colours. Finally, the price coordinates can be embedded within the SVG via props and plotted as points within the SVG elements.

Determining SVG size

Planning the dimensions of your SVG is very important. Most price charts are plotted within a rectangle-shaped area, which is no coincidence. This is why:

The width of the SVG usually coincides with how many prices will be plotted. For example, 1 point per pixel for five-minute intervals give us a total of 288 plots for a 24-hour period. The width of the SVG in this case will be 287px (as the first point will sit at x position 0).

usually coincides with how many prices will be plotted. For example, 1 point per pixel for five-minute intervals give us a total of 288 plots for a 24-hour period. The width of the SVG in this case will be 287px (as the first point will sit at x position 0). The height of the SVG needs to be normalisation friendly. In other words, once we normalise our prices into values between 0 and 1, they need to be multiplied again to fit the dimensions of the SVG (the SVG won’t just be 1px in height). We can add another calculation to multiply these normalised values by 100, for example, that’ll then give us a range between 0 and 100. Now this we can work with.

We’ll discuss this normalisation process in more detail in the second half of the article once our React price chart component is constructed and ready to take coordinates.

With the above in mind, we’re going to display price movements for the past 24 hours within our chart.

For this time frame, plotting points in intervals of five minutes is more than acceptable, providing enough detail to display accurate movements of the prices — a total of 288 price points to play with:

// price points with 5 minute intervals 86,400 (seconds in a day) / 300 (seconds in 5 minutes) = 288

What we end up with is a suitable SVG area of 287px by 100px . This area is great for embedding price charts in lists or in widgets:

Some things to consider when determining your price interval: How big are your planned graphs going to be? Could you get away with less points and therefore decrease your app bandwidth requirements? What is the shortest interval your data source allows? You may need to design your UI around this or other constraints.

Our SVG size can now act as a basis for further manipulation depending on your UI goals. So if your price chart needed to stretch across an entire page, you could plot each point every four pixels instead of every pixel, which would be a total width of 1151px for the same five-minute interval — or whichever shape fits your needs.

Now the SVG viewBox dimensions have been determined, we can safely define our svg element (albeit with nothing inside it yet):

// defining the price chart viewBox dimensions

xmlns="

viewBox="0 0 287 100"

>

...

</svg> http://www.w3.org/2000/svg ...

Now, let’s move onto defining the elements that’ll make the line graph itself and the shaded area below this line.

SVG elements: polyline and polygon

The line of our price chart is a compulsory element and is achieved with the polyline SVG element. A polyline is a basic shape that creates straight lines by connecting several coordinates via a points attribute:

// polyline drawing a zig-zag line <svg ...>

<polyline points="0,0 25,50 50,0 75,50 100,0" />

</svg>

The shaded area below the polyline is achieved with the polygon element. A polygon defines a closed shape consisting of a set of connected straight-line segments. Like polyline , polygon also accepts a range of points that define the shape:

// polygon drawing a square <svg ...>

<polygon points="0,0 100,0 100,100 0,100" />

</svg>

Combining these shapes together is all that is needed for an aesthetically pleasing price chart. Consider the following illustration to see how polyline and polygon work together to give the price chart some personality:

SVG consists of two elements: a <polyline /> and <polygon />

We only need to worry about the stroke colour of the polyline and only a fill colour of the polygon . This can all be achieved with CSS, which will be addressed further down.

You can think of the polygon as a box that has a whole bunch of points lying on top of it ready to conform to the same movements as the line itself:

Only the top line of our <polygon /> is manipulated

With this in mind, we can now update our svg a little from the last section, adding these two elements:



xmlns="

viewBox="0 0 287 100"

>

<polygon

points={`${...} 287,100 0,100}

/>

<polyline

points={`${...}}

/>

</svg> http://www.w3.org/2000/svg viewBox="0 0 287 100"

Now we’re getting somewhere, but the points props now need to be provided to define the shape.

For now, I’ve added empty string literals, with the addition of the bottom points of the polygon element — remember, we only need to define the top line of that shape to match the polyline movement.

SVG as a React component

The final part of the puzzle is to implement a React component that’ll take a points prop — an array of coordinates — and place them as points in the SVG elements.

Firstly, let’s consider how these coordinates will be formatted. They’ll be arrays, with each point providing an x and y value. Let’s not assume any formatting rules here, like the commas that separate the x and y coordinates of each point in the polyline and polygon elements — we’ll deal with formatting in the component itself.

Let’s just import the plain values with dummy data at this point. This is how that might be done:

import { PriceChart } from './PriceChart'; const MyComponent = () => (

<PriceChart

points={[[0,50],[1,51],[2, 50.5],[3,56],[4,50] ... [287,78]]}

/>

);

We’re providing an array of arrays, each with an x and y coordinate. The x value starts at 0 — the left side of the chart — and works its way across point by point. The y values are our normalised prices between 0 and 100 , the range of which we ascertained earlier.

At the API level, the x coordinate is very simple to calculate. You could just loop through your y coordinates and increment a counter that initialises at 0, before returning the completed coordinate sequence. Another solution would be to simply return the normalised prices and increment the x coordinate on the front end.

That just leaves our <PriceChart /> component to plot these points. Lets map them out and format them in a way our SVG elements understand:

export const PriceChart = (props) => (

<svg...>

<polygon

points={`${props.points.map(p =>

' ' + p[0] + ',' + p[1]

)} 287,100 0,100`

}

/>

<polyline

points={`${props.points.map(p =>

' ' + p[0] + ',' + p[1]

)}`

}

/>

</svg>

);

Our <PriceChart /> functional component now returns the completed SVG. It maps out the points prop at the JSX level, taking each point as p and returning a formatted coordinate in the format of x,y , while also adding a space between each point. Index 0 of each p point is our x coordinate, whereas index 1 is our y coordinate.

After adding some CSS via styled components, our completed component resembles the following Github Gist. Here’s the full implementation:

In terms of styling, we have wrapped the SVG itself in a styled div we’ve termed Wrapper .

We’ve ensured the containing svg element maintains Wrapper ’s full width and have also defined stroke and fill properties for polyline and polygon , respectively. Wrapper itself adheres to its containing element’s dimensions; it’s likely that we’ll be embedding <PriceChart /> within another containing component, so we’ll want to fall back to those dimensions.

OK, with our component now out of the way, let’s finally explore the price normalisation process in JavaScript.