Happysmithers Happysmithers - 5 months ago 27
Javascript Question

Chart.JS customization - how to debug?

I am creating a bar chart using Chart.JS. Working fine:

https://jsfiddle.net/uzat4y0c/

Now, I would like to add value labels to indicate the size of the individual bars. I did this with this code:

animation: {
onComplete: function(animation) {
var ctx = this.chart.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
ctx.fillStyle = "grey";
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
var dataset = this.data.datasets[1];
for (var i = 0; i < dataset.data.length; i++) {
for (var key in dataset._meta) {
var model = dataset._meta[key].data[i]._model;
ctx.fillText(dataset.data[i], model.x, model.y - 1);
} //for key
} //for i
} //onComplete
} //animation


Working fine, as well:
https://jsfiddle.net/uzat4y0c/1/

However, when I hover over the bar elements, my value labels will disappear for a moment while the animation updates, as you test in above fiddle.

In trying to improve this, I am seeking to find the piece of code which hides the numbers in the first place upon my mouseover. This is where I get stuck. I used dev tools and set an Event Listener breakpoint on "request animation frame", which eventually brought me to this piece of the Chart.JS code:

requestAnimationFrame: function() {
var me = this;
if (me.request === null) {
// Skip animation frame requests until the active one is executed.
// This can happen when processing mouse events, e.g. 'mousemove'
// and 'mouseout' events will trigger multiple renders.
me.request = helpers.requestAnimFrame.call(window, function() {
me.request = null;
me.startDigest();
});
}
},


After I first get here, I can loop through the "me.request = " part four times, then the value labels will disappear on stepping over the final curly closing brace.

Somehow I am missing where exactly is which command which "hides" my labels, or (more likely) repaints the canvas without labels.

How to get to the core of this by properly debugging? Thanks for reading!

Answer Source

Better draw the labels using a plugin, instead of drawing on animation compete (this is the culprit).

plugins: [{
   afterDatasetsDraw: function(chart) {
      var ctx = chart.ctx;
      ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
      ctx.fillStyle = "grey";
      ctx.textAlign = 'center';
      ctx.textBaseline = 'bottom';
      var dataset = chart.data.datasets[1];
      for (var i = 0; i < dataset.data.length; i++) {
         for (var key in dataset._meta) {
            var model = dataset._meta[key].data[i]._model;
            ctx.fillText(dataset.data[i], model.x, model.y - 1);
         } //for key
      } //for i
   }
}]

* add this followed by your chart options.

ᴡᴏʀᴋɪɴɢ ᴇxᴀᴍᴘʟᴇ

var ctx = document.getElementById("testChart").getContext("2d");
// ctx.canvas.width = 300;
// ctx.canvas.height = 300;

var data = {
   labels: ["uno", "dos", "tres", "quattro"],
   datasets: [{
         label: "Invisible",
         data: [0, 20, 60, 0],
         backgroundColor: "transparent",
      }, {
         label: "Dollar",
         data: [20, 40, 30, 90],
         backgroundColor: "lightgreen",
      }, ] //datasets
};

var options = {
   responsive: true,
   scales: {
      xAxes: [{
         display: true,
         stacked: true,
      }, ], //xAxes
      yAxes: [{
            display: true,
            stacked: true,
            ticks: {
               beginAtZero: true,
               min: 0,
               max: 120,
            } //ticks
         }, ] //yAxes
   }, //scales


   title: {
      display: true,
      text: "Waterfall chart",
   },
   legend: {
      display: false,
      labels: {
         boxWidth: 80,
         fontColor: 'green'
      }
   },

   tooltips: {
      enabled: false
   }, //tooltips
}; //options


var myBarChart = new Chart(ctx, {
   type: 'bar',
   data: data,
   options: options,
   plugins: [{
      afterDatasetsDraw: function(chart) {
         var ctx = chart.ctx;
         ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
         ctx.fillStyle = "grey";
         ctx.textAlign = 'center';
         ctx.textBaseline = 'bottom';
         var dataset = chart.data.datasets[1];
         for (var i = 0; i < dataset.data.length; i++) {
            for (var key in dataset._meta) {
               var model = dataset._meta[key].data[i]._model;
               ctx.fillText(dataset.data[i], model.x, model.y - 1);
            } //for key
         } //for i
      }
   }]
});
p,
canvas {
   border: 1px solid red;
}

#canvasWrapper {
   border: 1px solid green;
   padding: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.js"></script>
<p>Lorem</p>
<p>ipsum</p>
<div id="canvasWrapper">
   <canvas id="testChart"></canvas>
</div>
<p>Lorem</p>
<p>ipsum</p>

Refer here to learn more about ChartJS Plugins.