Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add an images as labels to Canvas Charts using chart.js

I am generating a chart.js canvas bar chart. What I am trying to do is, inside of the labels array, add images that go with each label, as opposed to just the text label itself. Here is the code for the chart: The json object that I am getting data from has an image url that I want to use to display the picture:

$.ajax({
method: "get",
url: "http://localhost:3000/admin/stats/show",
dataType: "json",
error: function() {
  console.log("Sorry, something went wrong");
},
success: function(response) {
  console.log(response)
  var objectToUse = response.top_dogs
  var updateLabels = [];
  var updateData = [];
  for (var i = 0; i < objectToUse.length; i+=1) {
    updateData.push(objectToUse[i].win_percentage * 100);
    updateLabels.push(objectToUse[i].title);
  }
  var data = {
    labels: updateLabels,
    datasets: [
      {
        label: "Top Winners Overall",
        fillColor: get_random_color(),
        strokeColor: "rgba(220,220,220,0.8)",
        highlightFill: get_random_color(),
        highlightStroke: "rgba(220,220,220,1)",
        data: updateData
      }
    ]
  };

  var options = {
    //Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
    scaleBeginAtZero : true,

    //Boolean - Whether grid lines are shown across the chart
    scaleShowGridLines : true,

    //String - Colour of the grid lines
    scaleGridLineColor : "rgba(0,0,0,.05)",

    //Number - Width of the grid lines
    scaleGridLineWidth : 1,

    //Boolean - Whether to show horizontal lines (except X axis)
    scaleShowHorizontalLines: true,

    //Boolean - Whether to show vertical lines (except Y axis)
    scaleShowVerticalLines: true,

    //Boolean - If there is a stroke on each bar
    barShowStroke : true,

    //Number - Pixel width of the bar stroke
    barStrokeWidth : 2,

    //Number - Spacing between each of the X value sets
    barValueSpacing : 5,

    //Number - Spacing between data sets within X values
    barDatasetSpacing : 2,
  };

  var loadNewChart = new Chart(barChart).Bar(data, options);
  }    

});

If anyone has a solution it would be greatly appreciated!

like image 891
jared k Avatar asked May 14 '15 21:05

jared k


1 Answers

I'm aware that this is an old post but since it has been viewed so many times, I'll describe a solution that works with the current Chart.js version 2.9.3.

The Plugin Core API offers a range of hooks that may be used for performing custom code. You can use the afterDraw hook to draw images (icons) directly on the canvas using CanvasRenderingContext2D.

plugins: [{
  afterDraw: chart => {
    var ctx = chart.chart.ctx;
    var xAxis = chart.scales['x-axis-0'];
    var yAxis = chart.scales['y-axis-0'];
    xAxis.ticks.forEach((value, index) => {
      var x = xAxis.getPixelForTick(index);
      var image = new Image();
      image.src = images[index],
        ctx.drawImage(image, x - 12, yAxis.bottom + 10);
    });
  }
}],

The position of the labels will have to be defined through the xAxes.ticks.padding as follows:

xAxes: [{
  ticks: {
    padding: 30
  }   
}],

Please have a look at the following runnable code snippet.

const labels = ['Red Vans', 'Blue Vans', 'Green Vans', 'Gray Vans'];
const images = ['https://i.stack.imgur.com/2RAv2.png', 'https://i.stack.imgur.com/Tq5DA.png', 'https://i.stack.imgur.com/3KRtW.png', 'https://i.stack.imgur.com/iLyVi.png'];
const values = [48, 56, 33, 44];

new Chart(document.getElementById("myChart"), {
  type: "bar",
  plugins: [{
    afterDraw: chart => {      
      var ctx = chart.chart.ctx; 
      var xAxis = chart.scales['x-axis-0'];
      var yAxis = chart.scales['y-axis-0'];
      xAxis.ticks.forEach((value, index) => {  
        var x = xAxis.getPixelForTick(index);      
        var image = new Image();
        image.src = images[index],
        ctx.drawImage(image, x - 12, yAxis.bottom + 10);
      });      
    }
  }],
  data: {
    labels: labels,
    datasets: [{
      label: 'My Dataset',
      data: values,
      backgroundColor: ['red', 'blue', 'green', 'lightgray']
    }]
  },
  options: {
    responsive: true,
    legend: {
      display: false
    },    
    scales: {
      yAxes: [{ 
        ticks: {
          beginAtZero: true
        }
      }],
      xAxes: [{
        ticks: {
          padding: 30
        }   
      }],
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="90"></canvas>
like image 106
uminder Avatar answered Sep 30 '22 03:09

uminder