Making PDF files from ChartJs charts in a React App

Harder than one might think

2019/01/27 2019/02/20    react butterscotch banan jesus buddy

While it’s not an ideal solution, sometimes you just need to be able to export some charts from your React App into a PDF file because… reasons. And it’s possible! While it is perhaps a somewhat ugly solution, it works and that is the most important thing.

Having an app using react-chartjs2, the most widely used ChartJs bindings for React, we will also have yo use react-pdf. They both provide all the dependencies that we need.

React-PDF allows PDFs to be made using react components. It comes with predefined components for PDF layout (like page breaks). HTML tags and elements cannot be used. It also does not support canvas, which is the way chartJS render its charts, so we need to find a solution around this.

Since we cannot use the components we have on the page we want to export in React-PDF, we will have to rebuild it using react-pdf components. We have the <Page> that defines a page, we have <View> that is used as a wrapper (like div in HTML), we have <Text> that we wrap around text and we have <Image> that we can use to render an image. All these can be styled with CSS using CSS-in-JS.

ChartJS have a method that will export a canvas object into a PNG file and render it as a base64 string. All you have to do is call the toBase64() method on your chart instance. And this would be all fine and dandy, except the fact that our chart instance is buried somewhere in the react-chartjs2 wrapper.

To get around this problem we need to use some of the more scarier parts of react: refs. Refs are references to DOM-objects and shall not be used lightly, but, in this instance we have no other choice. To make refs we instance them in the constructor like this this.refName = React.createRef();, and on the react-chartjs2 component we add ref={this.refName} as a prop.

This can be done dynamically, and in such a case, the easiest solution is to make this.refName into an array and map over the assignment. Then, when you map over the components you can add refs using the index ref={this.refName[index]}.

Basically, first and foremost, we need to put refs on the charts to be able to access their underlying instance. They can, however, only be accessed once the component is fully mounted, so we must use the methods of the instances in componentDidMount(). There, we access the method toBase64 on the ref, and save the data it gives in a URL.

Now it’s time to rebuild the entire page, because we can’t use what we already have, as react-pdf only support its own components. So, we’ll rebuild the page, and use the base64 urls as the value on src in the component. Now, wee need to store the page we’ve built, so we’ll put it in the components state.

To get the PDF, we use a function that renders an exportable PDF. It cannot be mounted before the logic making the PDF is made, so we need to put it behind a bolean that we toggle in the state after the above logic is done. And voilĂ .