Create SVG line chart in React

Written by krissanawat | Published 2018/09/02
Tech Story Tags: react-svg-line-chart | react-svg-line | create-svg-line-chart | svg-line-chart | react

TLDRvia the TL;DR App

Today, we’ll create a very simple svg chart in React, without external libraries.

JavaScript knowledge is required, familiarity with react is expected. It is assumed that you have Node, create-react-app installed. If you don’t have the tools set up, I have gone through them in detail in another tutorial. Follow that and come back.

Here’s how our chart will look like at the end.

Create a react app with

create-react-app reactdev-svg-chart

Go to the directory with

cd reactdev-svg-chart

Start the app with

npm start

It should open a welcome screen on your default browser.

What SVG is?

We’re creating a SVG chart so you must know what SVG is.

SVG stands for Scalable Vector Graphics. It allows to create vector based shapes. Vector graphics are resoultion independent and created on mathematical rules such as line or circle. They load fast, are searchable and modular as well.

How to create a SVG?

Let’s look at a simple SVG:

<path d = "M 50 60 L 100 100 z">

path in the tag for creating svg

d contains list of path instructions

M means Move To.

50 60 is a coordinate. x =50 and y = 60

L means Line To

100 100 is another coordinate.

z means the end or closing

So <path d = "M 50 60 L 100 100 z"> can be explained in plain English as

move to (50, 60) and create a line to (100, 100) than close the SVG element.

This path is included inside the svg tag to render.

That was easy, right? There are more attributes that can be used, refer them at W3Schools.

So what we are doing with SVG on React?

We’ll use data from React to create SVG based chart.

Creating data on React

This is the first task, to create data that will be passed to svg element.

import React, { Component } from 'react'
import './App.css'

class App extends Component {
  randomArray = (total = 10) => {
    let data = []
    for (let element = 0; element < total; element++) {
      const y = Math.floor(Math.random() * 50) + 50
      const obj = {
        x: element,
        y,
      }
      data.push(obj)
    }
    return data
  }
  render() {
    return (
      <div className="App">
        {/*Render SVG Chart here!*/}
        {/**/}
      </div>
    )
  }
}
export default App

randomArray() creates random array of objects w=for our purpose.

We need data like: [{x:0, y:54}, {x:1, y:72}, ...]. The y-coordinates will lie between 50 and 100.

We could manually supply this data, but I chose to make it random. The number of random values can be required can be passed as a parameter or it’ll use the default value.

NOTE: The (0, 0) coordinate lies on the left top corner of your screen and (maxX, maxY) lies at the right bottom. Do not get confused!

Line Chart

In the ./src/ create another file LineChart.js. It will contain the LineChart component.

import React, { Component } from 'react'
import './LineChart.css'
class LineChart extends Component {
  render() {
    return <svg />
  }
}
LineChart.defaultProps = {
  data: [],
color: '#ff4500',
  svgHeight: 200,
  svgWidth: 600,
}
export default LineChart

The props:

data empty array, the data will be passed.

color defaults to orangered

svgHeight and svgWidth refer to the height and width of the svg element.

Where is the LineChart.css file?

It’s here, but if you get stuck all code is on this GitHub repository.

.linechart_path {
  stroke-width: 2;
  fill: none;
}

.linechart_axis {
  stroke: #000000;
}

Minimum and Maximum values for SVG!

Before we can graph the data, we need to know the minimum and maximum values in thee data.

getMinX and getMinY are the helper functions for this purpose.

getMinX() {
        const {data} = this.props 
       const  only_x = data.map(obj => obj.x)
        const min_x = Math.min.apply(null, only_x),
        return min_x
    }
    getMinY() {
        const { data } = this.props 
        const  only_y = data.map(obj => obj.y)
        const min_y = Math.min.apply(null, only_y),
        return min_y
    }
    getMaxX() {
        const {data} = this.props 
       const  only_x = data.map(obj => obj.x)
        const max_x = Math.max.apply(null, only_x),
        return max_x
    }
    getMaxY() {
        const { data } = this.props 
        const  only_y = data.map(obj => obj.y)
        const max_y = Math.max.apply(null, only_y),
        return max_y
    }

Now we have the minimum and maximum x and y coordinates, we also need the svg coordinates.

SVG Coordinate creator

It’ll create svg coordinates for each poinr corresponding to the point in our data.

We need the x and y coordinates so we use two functions.

getSvgX(x){
        const { svgWidth } = this.props;
        return (x / this.getMaxX() * svgWidth);
    }
    getSvgY(y) {
        const { svgHeight } = this.props;
        return svgHeight - (y / this.getMaxY() * svgHeight);
    }

x/MaxX * width divides the width of our svg element uniformly.

Creating a svg line graph

We need to make path for each element, we sue another function makePath() for this.

makePath() {
    const { data, color } = this.props
    let pathD = ` M  ${this.getSvgX(data[0].x)} ${this.getSvgY(data[0].y)} `

    pathD += data.map((point, i) => {
      return `L ${this.getSvgX(point.x)} ${this.getSvgY(point.y)}  `
    })

It gets data and color from props.

pathD makes it the path move to the first coordinate, this refers to d attribute in path.

For each value of the coordinate in data, the line from previous to current is returned.

This new line is appended to the previous one.

className is used for styling.

Creating Grids

The chart is created but it doesn’t have container, so the points in the graph make no sense.

To make sense out of the chart, there must be the axis. The axis is: vertical in the left and horizontal in the bottom.

We make use of another helper function makeAxis() for this.

makeAxis() {
    const minX = this.getMinX()
    const maxX = this.getMaxX()
    const minY = this.getMinY()
    const maxY = this.getMaxY()
    return (
      <g className="linechart_axis">
        <line
          x1={this.getSvgX(minX)}
          y1={this.getSvgY(minY)}
          x2={this.getSvgX(maxX)}
          y2={this.getSvgY(minY)}
        />
        <line
          x1={this.getSvgX(minX)}
          y1={this.getSvgY(minY)}
          x2={this.getSvgX(minX)}
          y2={this.getSvgY(maxY)}
        />
      </g>
    )
  }

We get both max and min.

We return two lines in g tag. It is a container tag for svg, like div for other tags.

getSvgX and getSvgY achieve coordinates for starting and ending.

Plotting Axis and Line Graph

We have everything we need… All we need to do is return makePath and makeAxis.

render() {
    const { svgHeight, svgWidth } = this.props

    return (
      <svg viewBox={`0 0 ${svgWidth} ${svgHeight}`}>
        {this.makePath()}
        {this.makeAxis()}
      </svg>
    )
  }

The viewbox starts from (0, 0) and goes up to the dimensions we defined.

The Main file

We did everything but update App.js.

import React, { Component } from 'react'
import './App.css'
import LineChart from './LineChart'

class App extends Component {
  randomArray = (total = 10) => {
    let data = []
    for (let element = 0; element < total; element++) {
      const y = Math.floor(Math.random() * 50) + 50
      const obj = {
        x: element,
        y,
      }
      data.push(obj)
    }
    return data
  }
  render() {
    return (
      <div className="App">
        <div className="App">
          <div className="header">ReactDev SVG Chart</div>
          <LineChart data={this.randomArray()} />
        </div>
      </div>
    )
  }
}
export default App

Import LineChart and return this component. The data is passed through props from randomArray()!

Your chart won’t look like above as it uses random data every time.

Originally published at React Ninja.

Featured React JS Courses

React 16 — The Complete Guide (incl. React Router 4 & Redux)

4.7/5 Stars || 33.5 Hours of Video || 61,597 Students

Learn React or dive deeper into it. Learn the theory, solve assignments, practice in demo projects and build one big application which is improved throughout the course: The Burger Builder! Learn More.

React 16 - The Complete Guide (incl. React Router 4 & Redux)

Full-Stack Web Development with React Specialization

Build Complete Web and Hybrid Mobile Solutions. Master front-end web, hybrid mobile app and server-side development in four comprehensive courses with Coursera Enroll to start your 7-day full access free trial.

Full-Stack Web Development with React | Coursera

Closing Notes:

I publish articles on React, React Native, and everything else related to web development on React Ninja. Be sure and follow me on Twitter.

Join our Newsletter to get the latest and greatest content to make you a better developer.

If this post was helpful, please click the clap 👏 button below a few times to show your support! ⬇⬇


Published by HackerNoon on 2018/09/02