The React Easy Line chart

Introduction

A line chart or line graph is a type of chart which displays information as a series of data points called 'markers' connected by straight line segments.(ref)

Data

At the most basic the line chart can just take a single data file supplied in a JSON format and will render a simple line chart.

The format of the data is an array of arrays which allows multiple lines to be generated. The x field represents the x axis and the y the y axis. This is to unify the data across R2-D3 charts.


  <LineChart
    data={[
      [
        { x: 1, y: 20 },
        { x: 2, y: 10 },
        { x: 3, y: 25 }
      ]
    ]}
  />

If a second line is needed then this is easily added by adding a new data array to the existing array. The number of lines drawn is infinite but only coloured up to 4 lines.


  <LineChart
    data={[
      [
        { x: 1, y: 20 },
        { x: 2, y: 10 },
        { x: 3, y: 25 }
      ], [
        { x: 1, y: 10 },
        { x: 2, y: 12 },
        { x: 3, y: 4 }
      ]
    ]}
  />

Height and Width

The height and width can be easily set by passing in a numeric y in as a prop.


  <LineChart
    width={50}
    height={50}
    data={[
      [
        { x: 1, y: 20 },
        { x: 2, y: 10 },
        { x: 3, y: 25 }
      ], [
        { x: 1, y: 10 },
        { x: 2, y: 12 },
        { x: 3, y: 4 }
      ]
    ]}
  />

Margin

The Margin can be overridden by passing in a margin object. The margin object must define the following: top, right, bottom and left.

This can be particulary useful if a label is cut off.


  <LineChart
    margin={{top: 0, right: 0, bottom: 30, left: 100}}
    width={250}
    height={250}
    data={[
      [
        { x: 1, y: 20 },
        { x: 2, y: 10 },
        { x: 3, y: 25 }
      ], [
        { x: 1, y: 10 },
        { x: 2, y: 12 },
        { x: 3, y: 4 }
      ]
    ]}
  />

Axes

The axes can be turned on by simply passing a boolean flag to true for axes.


  <LineChart
    axes
    width={250}
    height={250}
    data={[
      [
        { x: 1, y: 20 },
        { x: 2, y: 10 },
        { x: 3, y: 25 }
      ], [
        { x: 1, y: 10 },
        { x: 2, y: 12 },
        { x: 3, y: 4 }
      ]
    ]}
  />
1.01.21.41.61.82.02.22.42.62.83.04681012141618202224

Axes labels

The axisLabels can be overridden by simply passing axisLabels object with both a x and y y.


  <LineChart
    axes
    margin={{top: 10, right: 10, bottom: 50, left: 50}}
    axisLabels={{x: 'My x Axis', y: 'My y Axis'}}
    width={250}
    height={250}
    data={[
      [
        { x: 1, y: 20 },
        { x: 2, y: 10 },
        { x: 3, y: 25 }
      ], [
        { x: 1, y: 10 },
        { x: 2, y: 12 },
        { x: 3, y: 4 }
      ]
    ]}
  />
1.01.21.41.61.82.02.22.42.62.83.0My x Axis4681012141618202224My y Axis

Y Axis orientation

The Y axis can be placed on the right hand side by passing a boolean flag to true for yAxisOrientRight.


  <LineChart
    axes
    axisLabels={{x: 'My x Axis', y: 'My y Axis'}}
    yAxisOrientRight
    width={450}
    height={250}
    data={[
      [
        { x: 1, y: 20 },
        { x: 2, y: 10 },
        { x: 3, y: 25 }
      ], [
        { x: 1, y: 10 },
        { x: 2, y: 12 },
        { x: 3, y: 4 }
      ]
    ]}
  />
1.01.21.41.61.82.02.22.42.62.83.0My x Axis4681012141618202224My y Axis

Interpolate (Making the lines smooth)

The Lines drawn can be set to be interpolated by passing in an interpolated param. By default this is set to linear. We can though override this for instance to make a cardinal line. The options that can be chosen can be foundhere under the interpolate section.


  <LineChart
    axes
    margin={{top: 10, right: 10, bottom: 50, left: 50}}
    axisLabels={{x: 'My x Axis', y: 'My y Axis'}}
    width={250}
    interpolate={'cardinal'}
    height={250}
    data={[
      [
        { x: 1, y: 20 },
        { x: 2, y: 10 },
        { x: 3, y: 25 }
      ], [
        { x: 1, y: 10 },
        { x: 2, y: 12 },
        { x: 3, y: 4 }
      ]
    ]}
  />
1.01.21.41.61.82.02.22.42.62.83.0My x Axis4681012141618202224My y Axis

xType & yType

The data passed associated to the particular axes can be in numeric, date (the default format is for example 1-Jan-15 but can be overridden) or textual formats (used for labelling).

For the example below the data for the x is text and so the xType needs to be changed to text.


  <LineChart
    xType={'text'}
    axes
    width={350}
    height={250}
    interpolate={'cardinal'}
    data={[
      [
        { x: 'Mon', y: 20 },
        { x: 'Tue', y: 10 },
        { x: 'Wed', y: 33 },
        { x: 'Thu', y: 45 },
        { x: 'Fri', y: 15 }
      ], [
        { x: 'Mon', y: 10 },
        { x: 'Tue', y: 15 },
        { x: 'Wed', y: 13 },
        { x: 'Thu', y: 15 },
        { x: 'Fri', y: 10 }
      ]
    ]}
  />
MonTueWedThuFri1015202530354045

Setting the xType to be time.


  <LineChart
    xType={'time'}
    axes
    interpolate={'cardinal'}
    width={750}
    height={250}
    data={[
      [
        { x: '1-Jan-15', y: 20 },
        { x: '1-Feb-15', y: 10 },
        { x: '1-Mar-15', y: 33 },
        { x: '1-Apr-15', y: 45 },
        { x: '1-May-15', y: 15 }
      ], [
        { x: '1-Jan-15', y: 10 },
        { x: '1-Feb-15', y: 15 },
        { x: '1-Mar-15', y: 13 },
        { x: '1-Apr-15', y: 15 },
        { x: '1-May-15', y: 10 }
      ]
    ]}
  />
Jan 04Jan 11Jan 18Jan 25FebruaryFeb 08Feb 15Feb 22MarchMar 08Mar 15Mar 22Mar 29Apr 05Apr 12Apr 19Apr 261015202530354045

Setting the yType to be text. (The yDomainRange has also been set to keep the range order.)


  <LineChart
    yType={'text'}
    xType={'text'}
    axes
    margin={{top: 0, right: 0, bottom: 100, left: 100}}
    yDomainRange={['Allot', 'Middle', 'Less']}
    interpolate={'cardinal'}
    width={350}
    height={250}
    data={[
      [
        { x: 'Mon', y: 'Little' },
        { x: 'Tue', y: 'Perfect' },
        { x: 'Wed', y: 'Allot' },
        { x: 'Thu', y: 'Little' },
        { x: 'Fri', y: 'Perfect' }
      ]
    ]}
  />
MonTueWedThuFriDayAllotPerfectLittleHow much did I eat

Setting the yType to be time


  <LineChart
    axisLabels={{x: 'Total Revenue', y: 'January'}}
    margin={{top: 10, right: 30, bottom: 50, left: 70}}
    yType={'time'}
    axes
    width={500}
    height={500}
    data={[
      [
        { x: 10, y: '1-Jan-15' },
        { x: 20, y: '10-Jan-15' },
        { x: 40, y: '21-Jan-15' },
        { x: 80, y: '31-Jan-15' }
      ], [
        { x: 0, y: '1-Jan-15' },
        { x: 15, y: '10-Jan-15' },
        { x: 20, y: '21-Jan-15' },
        { x: 25, y: '31-Jan-15' }
      ]
    ]}
  />
01020304050607080Total Revenue2015Sat 03Mon 05Wed 07Fri 09Jan 11Tue 13Thu 15Sat 17Mon 19Wed 21Fri 23Jan 25Tue 27Thu 29Sat 31January

Grid

A grid can be added to the graph by just passing in a boolean.


  <LineChart
    axisLabels={{x: 'Total Revenue', y: 'January'}}
    margin={{top: 10, right: 30, bottom: 50, left: 70}}
    yType={'time'}
    axes
    grid
    width={500}
    height={500}
    data={[
      [
        { x: 10, y: '1-Jan-15' },
        { x: 20, y: '10-Jan-15' },
        { x: 40, y: '21-Jan-15' },
        { x: 80, y: '31-Jan-15' }
      ], [
        { x: 0, y: '1-Jan-15' },
        { x: 15, y: '10-Jan-15' },
        { x: 20, y: '21-Jan-15' },
        { x: 25, y: '31-Jan-15' }
      ]
    ]}
  />
01020304050607080Total Revenue2015Sat 03Mon 05Wed 07Fri 09Jan 11Tue 13Thu 15Sat 17Mon 19Wed 21Fri 23Jan 25Tue 27Thu 29Sat 31January

Vertical Grid

A vertical grid can be added to the graph by just passing in a boolean for verticalGrid.


  <LineChart
    xType={'time'}
    axes
    grid
    verticalGrid
    interpolate={'cardinal'}
    width={750}
    height={250}
    data={[
      [
        { x: '1-Jan-15', y: 20 },
        { x: '1-Feb-15', y: 10 },
        { x: '1-Mar-15', y: 33 },
        { x: '1-Apr-15', y: 45 },
        { x: '1-May-15', y: 15 }
      ], [
        { x: '1-Jan-15', y: 10 },
        { x: '1-Feb-15', y: 15 },
        { x: '1-Mar-15', y: 13 },
        { x: '1-Apr-15', y: 15 },
        { x: '1-May-15', y: 10 }
      ]
    ]}
  />
Jan 04Jan 11Jan 18Jan 25FebruaryFeb 08Feb 15Feb 22MarchMar 08Mar 15Mar 22Mar 29Apr 05Apr 12Apr 19Apr 261015202530354045

Domain Range

By default the axis ranges are automatically calculated based on the smallest and the largest ys.

The range can be fixed by passing an array param of 2 numbers for the particular axis. The first number is the bottom of the range the second is the higher point of the range.


  <LineChart
    axes
    xDomainRange={[0, 100]}
    yDomainRange={[0, 100]}
    margin={{top: 0, right: 0, bottom: 100, left: 100}}
    width={250}
    height={250}
    interpolate={'cardinal'}
    data={[
      [
        { x: 10, y: 25 },
        { x: 20, y: 10 },
        { x: 30, y: 25 },
        { x: 40, y: 10 },
        { x: 50, y: 12 },
        { x: 60, y: 25 }
      ], [
        { x: 10, y: 40 },
        { x: 20, y: 30 },
        { x: 30, y: 25 },
        { x: 40, y: 60 },
        { x: 50, y: 22 },
        { x: 60, y: 9 }
      ]
    ]}
  />
01020304050607080901000102030405060708090100

Tick display format

If the x or y axis has an xType/yType of time then a display for the axis can be overridden by setting the tickTimeDisplayFormat.

The options are very flexible and can be seen hereTime Formatting.


  <LineChart
    axisLabels={{x: 'Total Revenue', y: 'January'}}
    margin={{top: 10, right: 30, bottom: 50, left: 70}}
    yType={'time'}
    axes
    interpolate={'cardinal'}
    tickTimeDisplayFormat={'%a'}
    width={500}
    height={500}
    data={[
      [
        { x: 10, y: '1-Jan-15' },
        { x: 20, y: '10-Jan-15' },
        { x: 40, y: '21-Jan-15' },
        { x: 80, y: '31-Jan-15' }
      ], [
        { x: 0, y: '1-Jan-15' },
        { x: 15, y: '10-Jan-15' },
        { x: 20, y: '21-Jan-15' },
        { x: 25, y: '31-Jan-15' }
      ]
    ]}
  />
01020304050607080Total RevenueThuSatMonWedFriSunTueThuSatMonWedFriSunTueThuSatJanuary

Number of Ticks

The number of ticks on the x and y axis can be set by passing in a number to xTicks or yTicks. This can make the axis easier to read.


  <LineChart
    axes
    xTicks={5}
    yTicks={5}
    xDomainRange={[0, 100]}
    yDomainRange={[0, 100]}
    width={500}
    height={250}
    interpolate={'cardinal'}
    data={[
      [
        { x: 10, y: 25 },
        { x: 20, y: 10 },
        { x: 30, y: 25 },
        { x: 40, y: 10 },
        { x: 50, y: 12 },
        { x: 60, y: 25 }
      ], [
        { x: 10, y: 40 },
        { x: 20, y: 30 },
        { x: 30, y: 25 },
        { x: 40, y: 60 },
        { x: 50, y: 22 },
        { x: 60, y: 9 }
      ]
    ]}
  />
020406080100020406080100

Line Colors

The colours of the lines can be overridden easily. To do this we can pass in a lineColors array as a prop.

The following example would be to change the color of the 2 lines.


  <LineChart
    xType={'time'}
    axes
    grid
    verticalGrid
    interpolate={'cardinal'}
    lineColors={['pink', 'cyan']}
    width={750}
    height={250}
    data={[
      [
        { x: '1-Jan-15', y: 20 },
        { x: '1-Feb-15', y: 10 },
        { x: '1-Mar-15', y: 33 },
        { x: '1-Apr-15', y: 45 },
        { x: '1-May-15', y: 15 }
      ], [
        { x: '1-Jan-15', y: 10 },
        { x: '1-Feb-15', y: 15 },
        { x: '1-Mar-15', y: 13 },
        { x: '1-Apr-15', y: 15 },
        { x: '1-May-15', y: 10 }
      ]
    ]}
  />;
Jan 04Jan 11Jan 18Jan 25FebruaryFeb 08Feb 15Feb 22MarchMar 08Mar 15Mar 22Mar 29Apr 05Apr 12Apr 19Apr 261015202530354045

Data Points

Data points can be added to the line chart by simply passing a dataPoints boolean.


  <LineChart
    axes
    dataPoints
    xDomainRange={[0, 100]}
    yDomainRange={[0, 100]}
    width={500}
    height={250}
    interpolate={'cardinal'}
    data={[
      [
        { x: 10, y: 25 },
        { x: 20, y: 10 },
        { x: 30, y: 25 },
        { x: 40, y: 10 },
        { x: 50, y: 12 },
        { x: 60, y: 25 }
      ], [
        { x: 10, y: 40 },
        { x: 20, y: 30 },
        { x: 30, y: 25 },
        { x: 40, y: 60 },
        { x: 50, y: 22 },
        { x: 60, y: 9 }
      ]
    ]}
  />
01020304050607080901000102030405060708090100

Mouse handlers

The chart will send out a mouseOver event, mouseMove and mouseOut event from the dataPoints (see above). The dataPoints will need to be set. This can be used by your react application in anyway you would require. The event handlers provides the mouse event and the point data. The mouse event can for instance provide the x and y coordinates which can be used for a tool tip. The data is related to the point currently moused over.


  mouseOverHandler(d, e) {
    this.setState({
      showToolTip: true,
      top: `${e.screenY - 10}px`,
      left: `${e.screenX + 10}px`,
      y: d.y,
      x: d.x});
  }

  mouseMoveHandler(e) {
    if (this.state.showToolTip) {
      this.setState({top: `${e.y - 10}px`, left: `${e.x + 10}px`});
    }
  }

  mouseOutHandler() {
    this.setState({showToolTip: false});
  }

  createTooltip() {
    if (this.state.showToolTip) {
      return (
        <ToolTip
          top={this.state.top}
          left={this.state.left}
        >
            The x value is {this.state.x} and the y value is {this.state.y}
        </ToolTip>
      );
    }
    return false;
  }

  <LineChart
    axes
    dataPoints
    grid
    xDomainRange={[0, 100]}
    yDomainRange={[0, 100]}
    mouseOverHandler={this.mouseOverHandler}
    mouseOutHandler={this.mouseOutHandler}
    mouseMoveHandler={this.mouseMoveHandler}
    width={700}
    height={350}
    interpolate={'cardinal'}
    data={[
      [
        { x: 10, y: 25 },
        { x: 20, y: 10 },
        { x: 30, y: 25 },
        { x: 40, y: 10 },
        { x: 50, y: 12 },
        { x: 60, y: 25 }
      ], [
        { x: 10, y: 40 },
        { x: 20, y: 30 },
        { x: 30, y: 25 },
        { x: 40, y: 60 },
        { x: 50, y: 22 },
        { x: 60, y: 9 }
      ]
    ]}
  />
01020304050607080901000102030405060708090100

Click Handler

The chart will send out a clickHandler event from the dataPoints (see above). The dataPoints will need to be set. This can be used by your react application in anyway you would require. The event handler provides the point data.

01020304050607080901000102030405060708090100
Click on a point to show the value

Updating the data

By selecting the button below to start the random data you can see a simulation of the performance if a data feed is passed in. React provides the functionality to only update the elements of the dom when required so should just change the line attributes. The data is passed in as a react param only and as soon as that data changes the chart will reflect that change automatically.


  // this is generated randomly and updated randomly within a range of -20 to + 20
  <LineChart
    data={this.data}
    datePattern={'%d-%b-%y %H:%M'}
    xType={'time'}
    width={this.state.componentWidth}
    height={this.state.componentWidth / 2}
    axisLabels={{x: 'Hour', y: 'Percentage'}}
    interpolate={'cardinal'}
    yDomainRange={[0, 100]}
    axes
    grid
    style={{
      '.line0': {
        stroke: 'green'
      }
    }}
  />
201501 AM02 AM03 AM04 AM05 AM06 AM07 AM08 AM09 AM10 AM11 AMHour0102030405060708090100Percentage

Fluid

Because the width and height of the chart can be passed in by a param then changes to the size of a window or container can change the chart dynamically. If you shrink your browser window width you will see the charts below change in a fluid manor. You can also introduce basic break points such as removing the axes if below a certain width.


  constructor(props) {
    const initialWidth = window.innerWidth > 0 ? window.innerWidth : 500;
    this.state = {showToolTip: false, windowWidth: initialWidth - 100};
  }

  componentDidMount() {
    window.addEventListener('resize', this.handleResize.bind(this));
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize);
  }

  handleResize() {
    this.setState({windowWidth: window.innerWidth - 100});
  }

  <LineChart
    xType={'time'}
    axes={(this.state.componentWidth) > 600 ? true : false}
    xTicks={5}
    yTicks={3}
    grid
    width={this.state.componentWidth}
    height={this.state.componentWidth / 2}
    tickTimeDisplayFormat={'%d %m'}
    interpolate={'cardinal'}
    data={[
      [
        { x: '1-Jan-13', y: 8 },
        { x: '1-Feb-13', y: 17 },
        { x: '1-Mar-13', y: 17 },
        { x: '1-Apr-13', y: 25 },
        { x: '1-May-13', y: 20 }
      ], [
        { x: '1-Jan-13', y: 5 },
        { x: '1-Feb-13', y: 13 },
        { x: '1-Mar-13', y: 10 },
        { x: '1-Apr-13', y: 25 },
        { x: '1-May-13', y: 30 }
      ]
    ]}
  />

2013

01 0101 0201 0301 0401 05102030