Search code examples
javascriptamcharts4

Vertically-oriented chart only shows single tooltip for all data items in amCharts V4


I am trying to make amCharts V4 to show tooltip for the data item most close to the cursor.

The problem is that my chart is mostly oriented vertically. I was able to break amCharts V4 sample by updating the sample data to get a vertical chart: https://codepen.io/fvnever/pen/jOwyQEE

Here, the data tooltips aren't changing as I move my cursor over the Y axis, and I want them to be updated. I.e. on the following image, it should show the tooltip closest to the cursor from series 1, and it instead shows some item from the beginning of said series.

Chart with broken tooltips

I've tried various suggestions from the documentation: setting and not setting chart.cursor.xAxis, chart.cursor.yAxis, chart.cursor.snapToSeries. Nothing seems to work.


Solution

  • There's no such feature out of the box, but it's possible to implement one. Two steps:

    1. Make sure to disable the default tooltip behavior:

      chart.cursor.snapToSeries = [];
      
    2. Now, handle the 'cursorpositionchanged' event and control the tooltip there, something like the following.

      Please note that this examples is very inefficient (it will iterate over all the chart nodes on every mouse move), so for any practical use, it would be better to store the data points in some sort of precalculated k-d tree.

      chart.cursor.events.on('cursorpositionchanged', (e) => {
        const cursor = e.target;
        const cursorPoint = cursor.point;
      
        let closestSeries = null;
        let closestItem = null;
        let minimalDistance = null;
        for (const series of chart.series) {
          for (const dataItem of series.dataItems) {
            const dataPoint = dataItem.point;
            const distance = Math.sqrt(Math.pow(cursorPoint.x - dataPoint.x, 2) + Math.pow(cursorPoint.y - dataPoint.y, 2));
            if (minimalDistance === null || distance < minimalDistance) {
              minimalDistance = distance;
              closestItem = dataItem;
              closestSeries = series;
            }
          }
        }
      
        for (const series of chart.series)
          series.tooltip.disabled = series !== closestSeries;
      
        if (closestItem)
          closestSeries.showTooltipAtDataItem(closestItem);
      });
      

    Full example for testing: https://codepen.io/fvnever/pen/yLXbEKG