html2canvas Chart.js chart not rendered

6.7k views Asked by At

I am trying to export a div that contains a Chart.js chart as an Iamge. All elements are displayed perfectly fine, however, the Chart.js canvas just doesn't get rendered.

I am calling my export function in the callback of the onAnimationComplete option in my chart, so the export can't happen before the chart is fully built.

Here is how my html2canvas and download functions look:

download() {
        this.dl.download = this.fileName;
        this.dl.click();
}

loadDataUrl($node) {
    this.hideUnwantedElements();
    html2canvas($node, {
        background: '#ffffff',
        scale: 4,
        proxy: 'proxy-for-cors-images',
        onrendered: (canvas) => {
            this.showElements();
            this.dl.href = canvas.toDataURL('image/jpeg');
        }});
}

Can anyone tell me if it is even possible to export Chart.js charts with html2canvas and if so, how? I also tried the toDataURL() function on the chart canvas but it only returns the data URL for a tranparent png.

3

There are 3 answers

6
ɢʀᴜɴᴛ On BEST ANSWER

Yes! It is possible to export (save as image) chart (created with ChartJS) using html2canvas.

HERE IS HOW :

var isChartRendered = false;

var chart = new Chart(ctx, {
   type: 'line',
   data: {
      labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
      datasets: [{
         label: 'LINE',
         data: [3, 1, 4, 2, 5],
         backgroundColor: 'rgba(0, 119, 290, 0.2)',
         borderColor: 'rgba(0, 119, 290, 0.6)',
         fill: false
      }]
   },
   options: {
      // setting following option is mandatory
      animation: {
         onComplete: function() {
            isChartRendered = true
         }
      }
   }
});

function download() {
   if (!isChartRendered) return; // return if chart not rendered
   html2canvas(document.getElementById('chart-container'), {
      onrendered: function(canvas) {
         var link = document.createElement('a');
         link.href = canvas.toDataURL('image/jpeg');
         link.download = 'myChart.jpeg';
         link.click();
      }
   })
}
#chart-container { background: white }
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
<button onclick="download()">save chart as...</button>
<div id="chart-container">
   <canvas id="ctx"></canvas>
</div>

PS: Needless to say but obviously, this is just an example, you need to adopt this accordingly to your project.

0
DavidH On

Just in case that anyone else has the same problem with the onComplete callback firing too early in Chart.js, here's how I was able to fix it without adding a setTimeout:

This is the correct way to load my export data after the animation is completed

animation: {
   onComplete: () => {
   this.loadExportElements();
   }
}

My first approach looked like this and did not work:

animation: {
                onComplete: this.loadExportElements()
}
0
Rajneesh Kumar Gobin On

onRendered is now deprecated

// we are targeting the legend and waiting for the promise to complete, you can skip this part if you dont want the legend to apear

html2canvas($("#yourChartID").find("ul")[0]).then(grid1Legend => {

   var pdf = new jsPDF('l', 'pt', 'a3');
  var chart1 = $("#yourChartID").get(0).toDataURL("image/png", 1.0);
  var grid1LegendtoUrl = grid1Legend.toDataURL("image/jpeg", 1.0);
  pdf.text(675, 275,"my chart");
  pdf.addImage(chart1, 'JPEG', 590, 325);
  pdf.addImage(grid1LegendtoUrl, 'JPEG', 465, 475);
  pdf.save("state_summary.pdf");



});

basically html2canvas will not save your canvas , what you can do is to point htmltocanvas to the canvas chart (chart.js) by using get(0) this will capture the chart then manually add the legend and the title as shown above and setting the correct cordinates.