How to Render A React Component To An Image

in #utopian-io9 years ago (edited)

A few days ago I was writing a paper and needed a way to visualize a data set. I knew that the data would change frequently and I did not want to update the charts manually. Furthermore, I needed a way to make screenshots of the graphs conveniently. Another obstacle was that the charts were higher than my screen. How do you make a screenshot with a height of 6000 pixels?

Well, you do it with some JavaScript magic.

In this tutorial, you will learn how to render a React component to an image in PNG format. You can convert the PNG to any other format with tools such as ImageMagick.

As an example, we will build a small application which renders the high and low price data series of the Steem cryptocurrency.

What Do You Need To Follow This Tutorial?

To build charts with JavaScript, you need

  • a computer running macOS, Linux, or Windows
  • basic knowledge of JavaScript and React
  • a terminal application
  • a few packages from the NPM registry
  • and, a bit of time

For this tutorial, I assume that you already have NPM or Yarn installed on your computer. If not … Google is your friend (at least in that case). Or ask me in the comments, I will point you in the right direction.

Use these two commands in the Terminal to check whether you have installed the packages:

node --version
npm --version

I have Node.js v8.9.1 and NPM version 5.6.0 on my computer.

Developing The Application

We will write two React components for this tutorial. An App component and a Chart component. Later I will show you a command line tool with which you can render each component to a PNG file.

But first things first.

We need to set up the project base where we can add our chart component. If you have worked with Webpack or other bundlers, you know that the configuration effort can kill you.

I have good news for you.

There is a new kid in JavaScript town, and it claims that it can bundle all of your JavaScript, HTML, and CSS files with zero configuration. This kid calls himself Parcel. It is awesome.

Let me show you how to install and use it.

Setting up The Project

We will create a folder bitcoin-chart where we will initialize a new JavaScript project and install some packages from the NPM registry.

mkdir steem-chart
cd bitcoin-chart

Now we need to initialize a new project. You can start a new JavaScript project with the yarn command. The command will prompt you with a few questions. You can just press return on each of the questions. What you answer to those questions does not matter as we do not want to publish our little project to an NPM registry. We only want to create the package.json file which is needed to keep track of the packages we are installing (and a little more).

yarn init

When you have answered all questions, you should have a new package.json file. It should look something like this:

{
  "name": "test",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT"
}

As we want to utilize React we need to install the Parcel, React, and Babel packages from the NPM registry:

yarn add --dev parcel-bundler babel-preset-env babel-preset-react
yarn add react react-dom

For Babel to work correctly, we need to have a .babelrc file in the project root. It should have the following contents:

{
  "presets": ["env", "react"]
}

We also need some files the bundler, Parcel, can bundle for us.
Let's add an HTML file index.html to the project.
This file will be the entry point into our app.

<!DOCTYPE html>
<html>
  <head>
      <title>Chart Tutorial</title>
  </head>
  <body>
      <div id="app"></div>
      <script src="index.js"></script>
  </body>
</html>

As you can see, we will link to a JavaScript file from our HTML file. The index.js file looks like this:

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

let element = document.getElementById("app")
ReactDOM.render(<App />, element)

From the HTML file, we will load a JavaScript file named index.js.

As you can see in the index.js file, we are loading the App component from a file called ./App.js. When you import a file with the import statement you do not have to give the extension .js. The module system will look for a file with the proper extension.

The App.js file is also in the project root. The content of the file looks like this:

import React from 'react'

const App = () => [
  <h1>Chart Tutorial</h1>
]

export default App

Nothing special going on here. The code above is a stateless functional React component. It will just render an h1 tag with the title.

Great, now we are at a point where we can run the bundler for the first time. We want to have a convenient way to start our application. Therefore add these three lines to the package.json file:

"scripts": {
  "start": "parcel index.html"
},

Do not miss the trainling comma.

The complete package.json file looks something like this:

{
  "name": "test",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "parcel index.html"
  },
  "devDependencies": {
    "babel-preset-env": "^1.6.1",
    "babel-preset-react": "^6.24.1",
    "parcel-bundler": "^1.4.1"
  },
  "dependencies": {
    "react": "^16.2.0",
    "react-dom": "^16.2.0"
  }
}

And now, for the first time, run your new app:

yarn start

If you need to run the application on a different port you can do it like this:

yarn start -- -p 3000

This command will start the script we added to the package.json file. This script will just invoke the parcel command. Parcel will bundle all of our source files and will start a local development server on port 1234.

Now point your browser to localhost:1234.

If you see the text Chart Tutorial you will know that everything works as intended.

Drawing The Steem Chart

Time to add a chart to our site. For this, we will install a package from the NPM registry called Recharts. If the local development server is still running, you can stop it with control-c. In our project root folder issue the following command to install Recharts.

yarn add recharts

Now we need some data and the code to draw a chart using the data. We will do this in a React component named Chart. This is the code to add to the file:

import React from 'react'
import { AreaChart, Area, XAxis, YAxis, CartesianGrid } from 'recharts'

const steemData = [
  { date: '12-12', open: 1.770000, high: 1.860000, low: 1.710000, close: 1.840000, volume: 3533147 },
  { date: '12-13', open: 1.750000, high: 1.770000, low: 1.660000, close: 1.750000, volume: 3232018 },
  { date: '12-14', open: 1.770000, high: 2.080000, low: 1.760000, close: 2.030000, volume: 6322185 },
  { date: '12-15', open: 2.170000, high: 2.170000, low: 1.800000, close: 1.960000, volume: 4783358 },
  { date: '12-16', open: 2.160000, high: 2.550000, low: 2.080000, close: 2.110000, volume: 5231100 },
  { date: '12-17', open: 2.070000, high: 2.380000, low: 2.060000, close: 2.310000, volume: 7287144 },
  { date: '12-18', open: 2.300000, high: 3.000000, low: 2.270000, close: 2.880000, volume: 11504803 },
  { date: '12-19', open: 2.660000, high: 3.150000, low: 2.500000, close: 2.850000, volume: 15684844 },
  { date: '12-20', open: 2.670000, high: 3.670000, low: 2.450000, close: 3.400000, volume: 22749889 },
  { date: '12-21', open: 3.240000, high: 3.920000, low: 3.120000, close: 3.660000, volume: 22059265 },
  { date: '12-22', open: 3.190000, high: 3.350000, low: 2.440000, close: 2.940000, volume: 14334895 },
  { date: '12-23', open: 3.110000, high: 3.370000, low: 2.920000, close: 3.160000, volume: 10613106 },
  { date: '12-24', open: 3.030000, high: 3.650000, low: 3.010000, close: 3.330000, volume: 11903095 },
  { date: '12-25', open: 3.340000, high: 3.450000, low: 3.160000, close: 3.370000, volume: 7384309 }
]

class Chart extends React.Component {
  render () {
    return (
      <AreaChart
        style={{marginLeft: 'auto', marginRight: 'auto'}} width={800} height={400} data={steemData}
        margin={{top: 10, right: 30, left: 0, bottom: 0}}
      >
        <XAxis dataKey='date'/>
        <YAxis/>
        <CartesianGrid strokeDasharray="3 3"/>
        <Area type='monotone' dataKey='high' stroke='lime' fill='lime' />
        <Area type='monotone' dataKey='low' stroke='pink' fill='pink' />
      </AreaChart>
    )
  }
}

export default Chart

The data is taken from the cryptocurrencies screener at Yahoo Finance.
It is a price series from December 2017 for the Steem cryptocurrency. In this component, we only get the AreaChart component from the Recharts package and feed our data into it. We use the date, high, and low fields from the data.

Now we need to link to our new Chart component. We will do this in our App component. Open App.js in your editor and change it to the following:

import React from 'react'
import Chart from './Chart'

const App = () => [
  <h1>Chart Tutorial</h1>,
  <Chart />
]

export default App

You can see that we only import the new component and render it after the h1 tag.

Save your changes and launch the app with yarn start. You should see the following:

Steem Chart December 2017

Easy, wasn't it. Let's celebrate: 🙌

Making Screenshots Of React Components

One final thing. I promised that it would be easy to make screenshots of your charts. For this you only need to install another package from NPM: Repng

yarn global add repng

… which is the same as …

npm install --global repng

You can use it to make screenshots of any React component in your project. In our example, we could make screenshots of App.js and Chart.s like this:

repng App.js --width 1024 --height 1800
repng Chart.js --width 800 --height 400

Previous Tutorials

If you liked this tutorial, you might also be interested in the tutorial which I have written about GatsbyJS. Gatsby is a fantastic static site builder.

Conclusion

Drawing charts with React is fun. Making screenshots of your React components and data visualizations is only one command away.

I'm looking forward to your feedback and comments.

Best,
Jo (@cutemachine)



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

'Javascript Magic' is all you need for anything 🙌 💯 Nice write-up Jo.

Thanks, Sam. Yes, JS has improved so much in the recent years. The only​ complaint I have is that the ecosystem is moving too fast. I'm a slow learner :)

Hey @cutemachine I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • This is your first accepted contribution here in Utopian. Welcome!

Suggestions

  • Contribute more often to get higher and higher rewards. I wish to see you often!
  • Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!

Get Noticed!

  • Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

Greetings friend you have my vote I hope yours, thanks

Coin Marketplace

STEEM 0.04
TRX 0.32
JST 0.099
BTC 64552.29
ETH 1917.05
USDT 1.00
SBD 0.38