3

I've implemented the technique described in this question to render vertical lines on my chart to show key dates when something important happened.

However, the text describing these events can be quite long, so just drawing text on the canvas isn't a good solution.

Is there some way to use the chart.js API to draw an invisible point on the chart (at the top of the line) which will become interactive and show a tooltip when the mouse hovers over it?

As far as I can see, only data points will show tooltips. I attempted to add another series to contain the lines data, but without much success - it also created a legend for this series, which I don't want. I set the values to 9999 to try to get them to appear at the top of the canvas, but this did not work and seems like a hack.

Kev
  • 2,656
  • 3
  • 39
  • 63

1 Answers1

1

You could add a second dataset that contains a single value at the x-position where the vertical line should be drawn, its value should correspond to the highest value of the first dataset. To make the point invisible, define transparent background and border colors using 'rgba(0,0,0,0)'.

 {
   data: [null, null, 12],
   pointRadius: 10,
   backgroundColor: 'rgba(0,0,0,0)',
   borderColor: 'rgba(0,0,0,0)'
 }

To only display the legend label of the relevant dataset, you need to define a legend.labels.filter function.

legend: {
  labels: {
    filter: legendItem => legendItem.datasetIndex == 0
  }
},

Further we need to define some tooltip.callback functions to show desired data in the tooltips.

Please take a look at below runnable code snippet and see how it works. This code uses the latest stable version of Chart.js (currently 2.9.3).

new Chart('canvas', {
  type: 'line',
  plugins: [{
    beforeDraw: chart => {
      var ctx = chart.chart.ctx;
      var xAxis = chart.scales['x-axis-0'];
      var yAxis = chart.scales['y-axis-0'];
      ctx.save();
      var lineAtIndex = chart.data.datasets[0].lineAtIndex;
      var x = xAxis.getPixelForTick(lineAtIndex);
      ctx.strokeStyle = '#ff0000';
      ctx.beginPath();
      ctx.moveTo(x, yAxis.bottom);
      ctx.lineTo(x, yAxis.top);
      ctx.stroke();
      ctx.restore();
    }
  }],
  data: {
    labels: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
    datasets: [{
        label: 'My Dataset',
        data: [12, 3, 2, 1, 8, 8, 2, 2, 3, 5, 7, 1],
        lineAtIndex: 2,
        lineTooltip: ['This is', 'a multi-line', 'tooltip']
      },
      {
        data: [null, null, 12],
        pointRadius: 10,
        backgroundColor: 'rgba(0,0,0,0)',
        borderColor: 'rgba(0,0,0,0)'
      }
    ]
  },
  options: {
    legend: {
      labels: {
        filter: legendItem => legendItem.datasetIndex == 0
      }
    },
    tooltips: {
      callbacks: {
        title: (tooltipItems, data) => {
          if (tooltipItems[0].datasetIndex == 0) {     
            return data.labels[tooltipItems[0].index];
          }
          return data.datasets[0].lineTooltip;
        },
        label: (tooltipItems, data) => {
          if (tooltipItems.datasetIndex == 0) {     
            return data.datasets[0].label + ': ' +  data.datasets[0].data[tooltipItems.index];
          }
          return null;
        }
      }
    },
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="canvas" height="90"></canvas>
uminder
  • 23,831
  • 5
  • 37
  • 72