[Chartjs]-Drawing images on top of graph doesn't work with ChartJS

4👍

The issue is that chartJs constantly updates the canvas by clearing it and re-rendering the whole thing, like on hovering and mouse movement to add the labels and do some animations, so anything you add to the canvas will be lost.

The workaround in the github discussion regarding the same issue is the way to go. You just need to create a new chart type extending the existing chart type you want to use where you can override the draw method of the new chart type to do the extra stuff you want, the syntax for extending the charts has changed since the github discussion, so we’ll use the new one:

Chart.defaults.pieWithExtraStuff = Chart.defaults.pie;                // the name of the new chart type is "pieWithExtraStuff"

Chart.controllers.pieWithExtraStuff = Chart.controllers.pie.extend({  // creating the controller for our "pieWithExtraStuff" chart by extending from the default pie chart controller
  draw: function(ease) {                                              // override the draw method to add the extra stuff
    Chart.controllers.pie.prototype.draw.call(this, ease);            // call the parent draw method (inheritance in javascript, whatcha gonna do?)

    var ctx = this.chart.ctx;                                         // get the context
    if (this.labelIconImage) {                                        // if the image is loaded
      ctx.drawImage(this.labelIconImage, 0, 0, 100, 100);             // draw it
    }
  },
  initialize: function(chart, datasetIndex) {                         // override initialize too to preload the image, the image doesn't need to be outside as it is only used by this chart
    Chart.controllers.pie.prototype.initialize.call(this, chart, datasetIndex);

    var image = new Image();
    image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAA1BMVEX/AAAZ4gk3AAAASElEQVR4nO3BgQAAAADDoPlTX+AIVQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwDcaiAAFXD1ujAAAAAElFTkSuQmCC';
    image.onload = () => {                                            // when the image loads
      this.labelIconImage = image;                                    // save it as a property so it can be accessed from the draw method
      chart.render();                                                 // and force re-render to include it
    };
  }
});



var config = {
  type: "pieWithExtraStuff",                                          // use our own chart type, otherwise what's the point?
  data: { /* ... */ }
};

var ctx = document.getElementById('Chart1').getContext('2d');
var myChart = new Chart(ctx, config);

Now whenever the pieWithExtraStuff chart re-renders, it will also draw the image.

Demo:

Chart.defaults.pieWithExtraStuff = Chart.defaults.pie;

Chart.controllers.pieWithExtraStuff = Chart.controllers.pie.extend({
  draw: function(ease) {
    Chart.controllers.pie.prototype.draw.call(this, ease);

    var ctx = this.chart.ctx;
    if (this.labelIconImage) {
      ctx.drawImage(this.labelIconImage, 0, 0, 100, 100);
    }
  },
  initialize: function(chart, datasetIndex) {
    Chart.controllers.pie.prototype.initialize.call(this, chart, datasetIndex);

    var image = new Image();
    image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAA1BMVEX/AAAZ4gk3AAAASElEQVR4nO3BgQAAAADDoPlTX+AIVQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwDcaiAAFXD1ujAAAAAElFTkSuQmCC';
    image.onload = () => {
      this.labelIconImage = image;
      chart.render();
    };
  }
});



var config = {
  type: "pieWithExtraStuff",
  data: {
    datasets: [{
      data: [
        "1",
        "2"
      ]
    }],
    labels: [
      "1",
      "2"
    ]
  }
};

var ctx = document.getElementById('Chart1').getContext('2d');
var myChart = new Chart(ctx, config);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="Chart1"></canvas>

Leave a comment