javascriptreactjscanvasrecharts

Recharts component to PNG


I currently have a Recharts component that I would like to export as a PNG file.

<LineChart
  id="currentChart"
  ref={(chart) => (this.currentChart = chart)}
  width={this.state.width}
  height={this.state.height}
  data={this.testData}
  margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
>
  <XAxis dataKey="name" />
  <YAxis />
  <CartesianGrid strokeDasharray="3 3" />
  <Tooltip />
  <Legend />
  <Line type="monotone" dataKey="pv" stroke="#8884d8" activeDot={{ r: 8 }} />
  <Line type="monotone" dataKey="uv" stroke="#82ca9d" />
</LineChart>;

but I'm unsure if this is directly supported by the library.

I have an idea that involves using a canvas and a 2D rendering context to get me close to a solution, as outlined on MDN

However, I'm not sure of a generic way to render an HTML element (or React Component) as a canvas to implement this solution.

I might be going about this all wrong, and I would appreciate the correction!


Solution

  • I was able to solve my problem by delving into the Recharts component. Recharts renders as an SVG under a wrapper so all I had to do was convert properly to save as both HTML or SVG

    // Exports the graph as embedded JS or PNG
    exportChart(asSVG) {
    
        // A Recharts component is rendered as a div that contains namely an SVG
        // which holds the chart. We can access this SVG by calling upon the first child/
        let chartSVG = ReactDOM.findDOMNode(this.currentChart).children[0];
    
        if (asSVG) {
            let svgURL = new XMLSerializer().serializeToString(chartSVG);
            let svgBlob = new Blob([svgURL], {type: "image/svg+xml;charset=utf-8"});
            FileSaver.saveAs(svgBlob, this.state.uuid + ".svg");
        } else {
            let svgBlob = new Blob([chartSVG.outerHTML], {type: "text/html;charset=utf-8"});
            FileSaver.saveAs(svgBlob, this.state.uuid + ".html");
        }
    }
    

    I am using FileSaver.js for the save prompt.