Chart.js: Show tooltips based on cursors x position in line charts

Created on 19 Apr 2016  路  31Comments  路  Source: chartjs/Chart.js

Hi,

I'm working with scatter charts and a large amount of points which results in an overlapping of the hover areas while trying to trigger the tooltips. I would like to bypass this mechanism and use the current x position of the mouse cursor instead to show the corresponding tooltip on the line chart. Here is an example of what I'm trying to describe in flotcharts:
http://www.flotcharts.org/flot/examples/tracking/index.html

It looks like this was the normal behavior of line charts in v1 to trigger the tooltips, but is it still possible to do this with v2?

support

Most helpful comment

@etimberg Actually intersect = false is right, it was my error. Fiddle shows it working: https://jsfiddle.net/o30ne2w9/

Sorry to have bothered you!

All 31 comments

Facing the same challenge...I'd love to know how to approach implementing this too.

I highly doubt the core devs will respond as their rules clearly state that we should not be asking support questions in the issue tracker ( use stackoverflow with the appropriate tag ).
I ended up implementing something similar that you can see here: http://hoboman313.github.io/chartsjs-demo/
Note that I created this solely as a demo to show off to some designers, so the code is pretty shit. I couldn't figure out how to properly extend the Chart.elements.Point:inRange() properly to be used by the Chart.line so I ended up monkey patching the library >_<.

@mdh-cc @hoboman313 I think you need to use the inLabelRange function of the point elements.

What you could do is replace the getElementAtEvent and getElementsAtEvent functions with versions that use inLabelRange instead of inRange. You should be able to do this after charts are created.

I'd be happy to merge a PR adding a new tooltip mode that added this functionality. I can give you some direction in implementing it if necessary

@etimberg I would love to see how to implement this also for a Line chart. Any example code would be great. Thanks!

@ericcirone I created a fiddle for you. In it I hotpatch the getElementsAtEvent method on the main chart controller to use inLabelRange.

https://jsfiddle.net/a077grhm/

@etimberg Thanks so much! Hopefully this is can be implemented as a new tooltip mode. Side note, on a bar chart, when you are on top of the bar the bar goes into hover mode, but doesn't display the tooltip. Any idea?

@ericcirone It'd make a great mode. To anyone who comes across this, I'd be happy to accept a PR for this.

is the tooltip mode set to label?

config = {
  tooltip: {
    mode: 'label'
  }
}

@etimberg You got it. I forgot to set those to label. Thanks a bunch.

@etimberg Thank you for the fiddle, this should solve my current problem.

isDatasetVisible does not seem to be a part of helpers at this time in 2.1.3. I noticed you're using 2.0.2 in the fiddle @etimberg.
I found this.isDatasetVisible to be valid but now its dataset is undefined. Could you point me in the right direction? or should I SO this question?

It would be great if this functionality can become a standard option again (it was in 1.x)

@ThaJay here's an updated version of the fiddle: https://jsfiddle.net/a077grhm/3/

This is on our radar to add back. If someone wants to PR it I'd happily merge it. They'd need a new mode string to set the tooltip to this mode, and a new function to that does what the fiddle does. I'd be happy to discuss refactoring this. I think that these functions should be stored somewhere else so they're easier to patch and extend

Nice thanks!
It would have taken me days to figure out all those small api changes, but your fiddle works for us.
So far, you guys have impressed me with your fast and high quality responses on here, very good work.

Glad it works for your use case. I'll try and add this back before the next release so that you don't need any hacks to make it work :smiley:

I've built a plugin for this which we use on PriceSpy (https://m.pricespy.co.uk/product/3499390/statistics)
The difference is that we show a tooltip until we reach a new one (we have so many data points it will be a lot of "blinking" otherwise)

Would be nice to have in core.

If it might be of any help this is the function that's called on onclick, onmousemove and ontouchmove.
I guess it need some minor tuning to work with multiple datasets.

let activeTooltip = null;

function showTooltipForPointEvenIfNotHoveringExactlyOverIt(chartInstance, evt) {
  const helpers = Chart.helpers;
  const eventPosition = helpers.getRelativePosition(evt, chartInstance.chart);

  helpers.each(chartInstance.data.datasets, (dataset, datasetIndex) => {
    if (chartInstance.isDatasetVisible(datasetIndex)) {
      helpers.each(chartInstance.getDatasetMeta(datasetIndex).data, element => {
        if (element.inLabelRange(eventPosition.x, eventPosition.y)) {
          activeTooltip = element;
          return;
        }
      });
    }
  });

  if (activeTooltip) {
    chartInstance.tooltipActive.push(activeTooltip);
    chartInstance.tooltip.update(true);
    chartInstance.render(0, true);
  }
}

@etimberg: This is exactly what I was looking for -- I'll give it a shot and report back.

Thanks!

@etimberg: Just tried your hotfix with the 2.1.6 release, but it's giving me an error:
Uncaught TypeError: helpers.isDatasetVisible is not a function

Any idea what could be causing this?

EDIT: Actually, it looks like there are some changes between the Charts JS version used in the fiddle and the current release. I have an idea how to hack it together. I'll give it a shot and report back (again).

@adamtLICOR isDatasetVisible is now a method on the core chart instance.https://github.com/chartjs/Chart.js/blob/master/src/core/core.controller.js#L481

Yup, I figured that part out. I tried copying the getElementsAtEvent() method and just swapping in inLabelRange, but that doesn't seem to do the trick (still only highlights on the literal dot).

Here's my new code, maybe I'm missing something:

    getElementsAtXAxis: function(e){
        var me = this;
        var eventPosition = helpers.getRelativePosition(e, me.chart);
        var elementsArray = [];

        var found = (function() {
            if (me.data.datasets) {
                for (var i = 0; i < me.data.datasets.length; i++) {
                    var meta = me.getDatasetMeta(i);
                    if (me.isDatasetVisible(i)) {
                        for (var j = 0; j < meta.data.length; j++) {
                            if (meta.data[j].inLabelRange(eventPosition.x, eventPosition.y)) {
                                return meta.data[j];
                            }
                        }
                    }
                }
            }
        }).call(me);

        if (!found) {
            return elementsArray;
        }

        helpers.each(me.data.datasets, function(dataset, datasetIndex) {
            if (me.isDatasetVisible(datasetIndex)) {
                var meta = me.getDatasetMeta(datasetIndex);
                elementsArray.push(meta.data[found._index]);
            }
        }, me);

        return elementsArray;
    }

@etimberg -- Annnnd, I'm dumb -- I was setting the hover mode on the chart hover, but not on the tooltip. :)

It seems to work now, just fine.

If you're still looking for someone to PR the fix, I'd be more than happy to make one!

@adamtLICOR please feel free to PR this. I think we should add a new mode for this (since it is different than the current label model which some may want).

@etimberg: Okay, great! Working on it now!

(I'm the same dude -- @adamtLICOR -- just on my personal account, instead of my work account)

Thanks for all your help!

Hi Friends,
I am trying to get that thick vertical line as cursor point to display this label as show in initial request
http://www.flotcharts.org/flot/examples/tracking/index.html

What should I add to Etimberg's method to make the line visible ? any help will be appreciated

@lakjakmr from reading this board, I think you need to update to the latest version and set the tooltip mode in your configuration to 'label' or 'x-axis'

config = {
  tooltips: {
    mode: 'label'  // or 'x-axis'
  }
}

The docs now say that x-axis mode is deprecated (change made by @etimberg), and suggests using index mode with intersect = false, but that doesn't seem to replicate this functionality.

Is this a bug, or was x-axis mode just marked deprecated by mistake?

@jdudley1123 the docs have an error. It should read intersect = true.

@etimberg Actually intersect = false is right, it was my error. Fiddle shows it working: https://jsfiddle.net/o30ne2w9/

Sorry to have bothered you!

hi,
sorry to post this question but, i was trying to set a vertical line folowing the mouse like @hoboman313 did in his example here http://hoboman313.github.io/chartsjs-demo/, is it possible?
Thanks.

hi, sorry, but i can't find how do the same in 2.8.0 (https://jsfiddle.net/a077grhm/3/)

@hoboman313 can you show me the code of your http://hoboman313.github.io/chartsjs-demo/, to be honest i am trying to build the same in ANGULAR, face lots of problems now.

Was this page helpful?
0 / 5 - 0 ratings