Full Speed Ahead

First Things First

So we have our client’s data, now let’s begin initializing our React components in their most basic form. We’ll work between two separate components, <Chart/> and <Graph/> . What we’re trying to accomplish through this parent-child relationship is a separation of concerns. The parent <Chart/> will directly handle the data and user interaction, while the child <Graph/> will simply receive the appropriate data, perhaps perform some additional logic, and then render the results accordingly. As our two components increase in complexity throughout the next two parts in this series, our initial foresight here will prove to be quite rewarding.

The Chart

Since this will need to make use of the component lifecycle (and in part two, internal state), we will write it as a class-based (smart) component. This should look very familiar if you’ve ever worked with React to any degree:

import React, { Component } from 'react'; import Graph from './Graph'; class Chart extends Component {

render() {

return (

<div className="chart-body">

<Graph />

</div>

)

}

} export default Chart;

As you can see we’ve went ahead and added in some initial JSX (JavaScript XML) markup, just so that we have a DOM (Document Object Model) to work with. Notice how we’ve place-held the <Graph /> child component — let’s go ahead and initialize this before we move on as well.

The Graph

Since this component doesn’t perform any additional logic (yet), and since it doesn’t need access to the component lifecycle (yet), we can simply build it out as a functional (dumb) component:

import React from 'react'; const Graph = (props) => {

return (

<svg>

<polyline />

<circle />

</svg>

)

} export default Graph;

Note that this particular component is solely responsible for the SVG markup.

Connecting the Dots (Literally)

The Data

Since we’ll be representing our data using a line graph, we need to generate a single <polyline> with many <circle> elements within our <svg> node. An important rule to note here is that the points in a line graph can vary vertically, but will remain constant horizontally. This wouldn’t be true if we allowed for the scale of the line graph to be adjusted, but we’re not. This means that the client’s random, subject-to-change array will control the vertical Y plane, while a predefined, constant array will control the horizontal X plane. We already have the former (see “The Premise” above), so let’s go ahead create the latter:

If we assume a viewBox width of 1000 pixels and distribute 21 points evenly within this width, we’re left with:

0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000

So now that we’ve got ourselves two datasets, the varying array and the constant array, we can finally make use of them in our component. To do so, we’ll first assign them to a variable within the constructor of the <Chart/> component with the names arrayX and arrayY , and then we’ll pass them through to our <Graph/> via props of the same name:

import React, { Component } from 'react'; import Graph from './Graph'; import './index.css'; class Chart extends Component {

constructor(props) {

super(props);

this.arrayX = [0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000];

this.arrayY = [5, 30, -5, -10, 15, -15, 20, 5, 8, -12, -20, 2, 3, -5, 8, -2, 22, -30, -15, -35, -20];

} render() {

return (

<div className="chart-body">

<Graph

arrayX={this.arrayX}

arrayY={this.arrayY}

/>

</div>

)

}

} export default Chart;

The Polyline

In order to put this data to use in our <Graph> component and build out our <polyline> , we first need to understand how the <polyline> coordinate system works. Every <polyline> consists of a comma-seperated list of X and Y values, relative to the viewbox . This is how each point of the line is positioned within the SVG node.

We’ve done the work to get both the X and Y values in their own array of the equal lengths, so now we just need to create a function to smash these values together in the format described above. Let’s also be sure to run this function immediately when the component is mounted:

componentWillMount() {

this.generatePolylineArray();

} generatePolylineArray() {

let polyline = '';

this.arrayX.map((coordX, i) => {

return polyline += `${coordX}, ${this.arrayY[i]} `;

})

this.polyline = polyline;

}

output:

0,5 50,30 100,-5 150,-10 200,15 250,-15 300,20 350,5 400,8 450,-12 500,-20 550,2 600,3 650,-5 700,8 750,-2 800,22 850,-30 900,-15 950,-35 1000,-20

Now we just need to plug this string into the points attribute of the <polyline> element. To do so, we’ll simply pass it to the <Graph/> component alongside our original arrays via a polyline prop:

<Graph

arrayX={this.arrayX}

arrayY={this.arrayY}

polyline={this.polyline}

/>

The Circles

Let’s now finally hop over to our <Graph/> component to populate our <polyline> with these points and while we’re at it, generate our <circle> elements. The <circle> element requires only a single cx and cy attribute for each X and Y coordinate, respectively:

import React from 'react'; const Graph = (props) => {

return (

<svg x="0px" y="0px" viewBox="0 0 1000 2">

<polyline points={props.polyline} />

{props.arrayX.map((coordX, i) => {

return (

<circle

key={i}

cx={coordX}

cy={props.arrayY[i]}

r={4}

/>

)

})}

</svg>

)

} export default Graph;