Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Charts.js tooltip overlapping text on chart

As Charts.js does not yet support annotations, I have added annotations of the data points after the chart is drawn. using ctx.fillText as shown below.

        animation: {
            animateScale: true,
            animateRotate: true,
            onComplete: function () {
                var chartInstance = this.chart,
                    ctx = chartInstance.ctx;
                ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
                ctx.textAlign = 'center';
                ctx.fillStyle = this.chart.config.options.defaultFontColor;
                ctx.textBaseline = 'bottom';

                this.data.datasets.forEach(function (dataset, i) {
                    var meta = chartInstance.controller.getDatasetMeta(i);
                    meta.data.forEach(function (bar, index) {
                        data = dataset.data[index];
                        ctx.fillText(data, bar._model.x, bar._model.y - 5);
                    });
                });
            }
        }

This works great, other than the fact that now the tooltip is shown below the newly added text. This is not that obvious, however sometimes it overlaps in a bad place meaning that you cannot see the tooltip behind.

enter image description here

Is there a way to set the z-index of the ctx.fillText or tooltip so I can layer them correctly?

like image 893
user3284707 Avatar asked Feb 06 '23 20:02

user3284707


1 Answers

@user3284707 Actually what you have to do is draw the numbers on top of your bars before the tooltips, you are drawing them onComplete, putting them on top of everything.

I draw those numbers using:

Chart.plugins.register({
  beforeDraw: function(chartInstance) {
    if (chartInstance.config.options.showDatapoints) {
      var helpers = Chart.helpers;
      var ctx = chartInstance.chart.ctx;
      var fontColor = helpers.getValueOrDefault(chartInstance.config.options.showDatapoints.fontColor, chartInstance.config.options.defaultFontColor);

      // render the value of the chart above the bar
      ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
      ctx.textAlign = 'center';
      ctx.textBaseline = 'bottom';
      ctx.fillStyle = fontColor;

      chartInstance.data.datasets.forEach(function (dataset) {
        for (var i = 0; i < dataset.data.length; i++) {
          var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
          var scaleMax = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
          var yPos = (scaleMax - model.y) / scaleMax >= 0.93 ? model.y + 20 : model.y - 5;
          var label = dataset.data[i] || '';
          ctx.fillText(label.toLocaleString(), model.x, yPos);
        }
      });
    }
  }
});

Notice the beforeDraw there.

Hope this helps 3 years later, I spent the last 30 minutes trying to fix this 🤣

like image 171
Shinta Avatar answered Feb 08 '23 10:02

Shinta