using react-chartjs-2 , How can I save my chart as png using a download button

6.3k views Asked by At

I'm trying to download my chart.js charts as png using a button Onclick, but I have no idea how I'm going to achieve this , I've went through this answer React-chartjs-2 Doughnut chart export to png but it wasn't quite clear enough for me as I'm quite new in chart.js don't know how I'm going to connect those variables with my button.

import React from 'react';
import { Component, useRef } from 'react';
import { Bar } from 'react-chartjs-2';
import 'chartjs-plugin-datalabels';

const data = {
  labels: ['Finance & Business', 'Mining', 'Community Services', 'Electricity', 'Agriculture', 'Construction', 'Manufacture', "Trade & Tourism", "Transport & Logistics"],
  datasets: [
    {
      label: 'My First dataset',
      backgroundColor: ["#3283FC", "", "", "#00C0C8", "#C0BD00", "#3A46B1", "#00A150", "#FEB200", "#9302a1"],
      borderWidth: 1,
      hoverBackgroundColor: 'rgba(255,99,132,0.4)',
      hoverBorderColor: 'rgba(255,99,132,1)',
      data: [0.6, 0.0, 0.0, -0.1, -0.1, -0.3, -0.3, -0.6, -1.0],
    }
  ]
};


class StackedBar extends Component {

  render() {

    return (
      <div>
        <h2>Bar Example (custom size)</h2>
        <Bar

          data={data}
          options={{
            plugins: {
              datalabels: {
                display: true,
                color: '#fff'
              }
            },
            title: {
              display: true,
              text: 'Contribution Percentage',
              position: 'left'
            },
            maintainAspectRatio: true,
            scales: {
              xAxes: [{

                stacked: true,
                gridLines: {
                  borderDash: [2, 6],
                  color: "black"
                },
                scales: {
                }
              }],
              yAxes: [{
                ticks: {
                  beginAtZero: true,
                  steps: 0.5,
                  stepSize: 0.5,
                  max: 1.5,
                  min: -1.0

                },
              }]

            },

          }}
        />
      </div>
    );
  }
}
export default StackedBar;

2

There are 2 answers

0
Phakamani Xulu On BEST ANSWER

So I installed a plugin called FileSave.js //

  1. npm install npm i file-saver
  2. import the plugin import { saveAs } from 'file-saver';
  3. than just write this blob function
   class StackedBar extends Component {
   saveCanvas() {
       //save to png
       const canvasSave = document.getElementById('stackD');
       canvasSave.toBlob(function (blob) {
           saveAs(blob, "testing.png")
       })
   }

   render() {

       return (
           <div>
               <a onClick={this.saveCanvas}>Download as PNG</a>
      
               <Bar id="stackD" data={data} options={options} />
           </div>
       );
   }
}
export default StackedBar; 



0
pgee70 On

another option is to use the chart ref, and then use the chart.js toBase64Image function. save this out as base64, convert to blob and save as a file using the file-saver package.

import { saveAs } from 'file-saver';

/**
 * @param b64Data
 * @param contentType
 * @param sliceSize
 * @returns {Blob}
 * @link https://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript
 */
const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => {
  const byteCharacters = atob(b64Data);
  const byteArrays = [];

  for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
    const slice = byteCharacters.slice(offset, offset + sliceSize);

    const byteNumbers = new Array(slice.length);
    // eslint-disable-next-line no-plusplus
    for (let i = 0; i < slice.length; i += 1) {
      byteNumbers[i] = slice.charCodeAt(i);
    }

    const byteArray = new Uint8Array(byteNumbers);
    byteArrays.push(byteArray);
  }

  return new Blob(byteArrays, { type: contentType });
};

... in component
  const chartRef = useRef(null);
... in jsx...


<Button
   onClick={() => {
   const b64 = chartRef.current.toBase64Image().replace('data:image/png;base64,', '');
   const content = b64toBlob(b64);
   const file = new File([content], 'Revenue_chart.png', { type: 'image/png' });
   saveAs(file);
  }}
  >
    img
</Button>
<Line data={data} options={options} ref={chartRef} />