skip to Main Content

I’m using react-chartjs-2 but I need to get chart only as image, without rendering it.
I can’t render it because I need to print the image inside a PDF document (react-pdf); if I put the chart component inside Document component (from react-pdf) I receive errors.

I tried to create inside a constant but seems not to work (neither log inside onComplete callback is printed).

const options = {
...
animation: {
onComplete: function(data) {
console.log("complete")
}
}
...
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const chart = new Chart(ctx, {
    type: 'radar',
    options: options,
    data: data
});
console.log(chart.toBase64Image());

I search in Github repo and official website for a specific hook or something else but with no success.
Is there a way to get chart image with no render?

2

Answers


  1. I think you need to take this step by step.
    react-pdf might not support custom components like charts but it can render images.
    Try converting your chart into an image first.

        canvas = await html2canvas(chartRef),
        data = canvas.toDataURL('image/jpg')
    

    once you have a url for image, you can use it with react-pdf.

    Login or Signup to reply.
  2. You don’t get an image for the chart because the canvas has no width or height (check canvas.offsetWidth,
    canvas.offsetHeight), nor can it have one until you insert it into the DOM.

    To get an image without inserting the chart into the DOM, you may use an OffscreenCanvas.
    With that, set animation: false for the chart, and get the data url using the OffscreenCanvas procedure,
    not chart.toBase64Image.

    Demo snippet (image inserted into the DOM for verification)

    const canvas = new OffscreenCanvas(300, 300);
    const chart = new Chart(canvas.getContext('2d'), {
       type: 'radar',
       data: {
          labels: ['January', 'February', 'March', 'April', 'May', 'June'],
          datasets: [{
             label: 'Dataset 1',
             data: Array.from({length: 6}, () => Math.random() * 10 + 5),
             backgroundColor: 'rgba(221,84,112,0.4)',
             borderColor: 'rgb(221,84,112)',
          }, {
             label: 'Dataset 2',
             data: Array.from({length: 6}, () => Math.random() * 10 + 5),
             backgroundColor: 'rgba(84,112,221,0.4)',
             borderColor: 'rgb(84,112,221)',
          }]
          
       },
       options: {
          responsive: false,
          animation: false
       }
    });
    
    (async () => {
       const blob = await canvas.convertToBlob();
       const dataURL = await new Promise(resolve => {
          const fr = new FileReader();
          fr.onload = function(e){resolve(e.target.result);}
          fr.readAsDataURL(blob);
       });
       
       console.log(dataURL);
       // for verification
       const img = new Image();
       img.src = dataURL;
       document.body.appendChild(img)
    })();
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search