June 24, 2017

Make Your Own Charts in React Without a Charting Library

edit

Occasionally I see someone ask, “What’s the best way to make bar charts with React? Are there any great libraries?” I often respond with, “Why not build it with React yourself?”

React’s one-way data binding model is perfect for creating simple data visualizations from scratch and I want to show you how.

Why shouldn’t I use a charting library?

Charting libraries are great! I’m not going to stop you. But bringing in a whole library for a simple data viz might be a bit of overkill in some situations. If you go the route of adding a charting library to your application, you now have to understand two APIs versus one. React’s API is well suited to creating these visualizations, so I’m encouraging you to use what you already know.

A Simple Bar Chart

We are going to build is a bar chart. These are really easy to build with React. Once you understand the concepts, I’m sure you’ll be jumping ahead and making even more complex visualizations in no time. Let’s get started.

To make our bar chart, we’re going to first need some data. Because I lack creativity, I’m going to create a data set based on the number of repos a few of my favorite Github users own (and mine for good measure):

const data = [
  {
    name: 'kentcdodds',
    repos: 371,
  },
  {
    name: 'sindresorhus',
    repos: 909,
  },
  {
    name: 'developit',
    repos: 222,
  },
  {
    name: 'getify',
    repos: 43,
  },
  {
    name: 'btholt',
    repos: 56,
  },
  {
    name: 'kyleshevlin',
    repos: 82,
  },
]

Next, we need to build a few basic components to represent this data. We’ll start with a Chart component and a Bar component.

const Chart = ({ children, width, height }) => (
  <svg viewBox={`0 0 ${width} ${height}`} width={width} height={height}>
    {children}
  </svg>
)

const Bar = ({ x, y, width, height }) => (
  <rect x={x} y={y} width={width} height={height} />
)

These are really simple components. Our Chart component creates an svg based upon the width and height we pass in as props. Then, the Bar component creates a rect element that we will pass as a child of the Chart component.

Putting this together (with some math to handle the discrepancy in repo totals), we can make our bar chart like so:

const BarChart = ({ data }) => {
  // Width of each bar
  const itemWidth = 20

  // Distance between each bar
  const itemMargin = 5

  const dataLength = data.length

  // Normalize data, we'll reduce all sizes to 25% of their original value
  const massagedData = data.map(datum =>
    Object.assign({}, datum, { repos: datum.repos * 0.25 }),
  )

  const mostRepos = massagedData.reduce((acc, cur) => {
    const { repos } = cur
    return repos > acc ? repos : acc
  }, 0)

  const chartHeight = mostRepos

  return (
    <Chart width={dataLength * (itemWidth + itemMargin)} height={chartHeight}>
      {massagedData.map((datum, index) => (
        <Bar
          key={datum.name}
          x={index * (itemWidth + itemMargin)}
          y={0}
          width={itemWidth}
          height={datum.repos}
        />
      ))}
    </Chart>
  )
}

ReactDOM.render(<BarChart data={data} />, document.getElementById('barchart'))

If you’ve followed along, you should now have a bar chart of 6 bars. Their heights should correspond with how many repos the user has. There is one small problem, though. The bars are upside down.

This is a typical problem with bar charts and is easily solved. I just wanted to show you how.

In our BarChart component, we need to change the y prop to place the rect such that they all line up on the bottom. To do this, we can set y equal to chartHeight minus that rect’s height. Let’s make some small changes to the component:

const BarChart = ({ data }) => {
  // all the same ...

  return (
    <Chart width={dataLength * (itemWidth + itemMargin)} height={chartHeight}>
      {massagedData.map((datum, index) => {
        const itemHeight = datum.repos

        return (
          <Bar
            x={index * (itemWidth + itemMargin)}
            y={chartHeight - itemHeight}
            width={itemWidth}
            height={itemHeight}
          />
        )
      })}
    </Chart>
  )
}

And there you have it, a very simple to make bar chart. Check out a rendering of our bar chart below:


Liked the post?
Give the author a dopamine boost with a few "beard strokes". Click the beard up to 50 times to show your appreciation.
Kyle Shevlin's face, which is mostly a beard with eyes

Kyle Shevlin is the founder & lead software engineer of Agathist, a software development firm with a mission to build good software with good people.

Logo for Introduction to State Machines and XState
Introduction to State Machines and XState
Check out my courses!
If you enjoy my posts, you might enjoy my courses, too. Click the button to view the course or go to Courses for more information.
Sign up for my newsletter
Let's chat some more about TypeScript, React, and frontend web development. Unsubscribe at any time.