7

is there a way to get the nearest point when clicked anywhere on canvas? Maybe somehow harvest the core 'nearest' method? Thanks

  • Welcome to Stack Overflow! Please take the [tour](https://stackoverflow.com/tour), look around, and read through the [Help Center](https://stackoverflow.com/help), in particular [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) If you run into a specific problem, research it thoroughly, search thoroughly here, and if you're still stuck post your code and a description of the problem. Also, remember to include [Minimum, Complete, Verifiable Example](https://stackoverflow.com/help/mcve). People will be glad to help – Andreas May 31 '19 at 06:42
  • 3
    @Andreas Non-sense. This is a clear question. – ABCD Jan 03 '21 at 21:11

3 Answers3

5

I think you will find getElementsAtXAxis very helpful.

Basically, getElementsAtXAxis has a very similar behaviour to getElementsAtEvent although when the click event doesn't intersect a point of the chart, it will return the nearest ChartElement.

The only downside is that it will return all the ChartElement on the nearest x-axis index.

So, if you use multiple datasets, this might not be the best choice for you.

Code example:

canvas.onclick = function(e) {
    const elts = chart.getElementsAtXAxis(simulatedEvent);
    if (elts && elts.length) {
        // Do something with elts[0]
    }
};

If anyone is looking for the related piece of code, it's in core.controller.js:

getElementAtEvent: function(e) {
    return Interaction.modes.nearest(this, e, {intersect: true});
},

getElementsAtEvent: function(e) {
    return Interaction.modes.index(this, e, {intersect: true});
},

getElementsAtXAxis: function(e) {
    return Interaction.modes.index(this, e, {intersect: false});
},
La masse
  • 1,190
  • 1
  • 10
  • 24
0

I believe you are looking for .getElementAtEvent and .getElementsAtEvent (https://www.chartjs.org/docs/latest/developers/api.html#getelementsatevente)

What you can do - is set up a clickHandler function that will grab the event from onClick and use it to return the chart element under it.

Here is an example from the official docs:

function clickHandler(evt) {
    var firstPoint = myChart.getElementAtEvent(evt)[0];

    if (firstPoint) {
        var label = myChart.data.labels[firstPoint._index];
        var value = myChart.data.datasets[firstPoint._datasetIndex].data[firstPoint._index];
    }
}

After, just add it to your chart canvas (again, from the official docs):

canvas.onclick = clickHandler;
Artem K
  • 169
  • 1
  • 1
  • 9
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/23156468) – Mayur Prajapati May 31 '19 at 07:01
  • @Mayur, thank you for the suggestion. I edited the answer to pull the essential parts of the docs into it. – Artem K May 31 '19 at 07:30
  • 2
    Hey, thanks for the answer. `.getElementAtEvent` and `.getElementsAtEvent` only return elements at the position where you clicked. When I click just randomly on the canvas, it returns an empty array. I would need to get the nearest element wherever I click, hence the mentioned 'nearest' method in the core [link](https://github.com/chartjs/Chart.js/blob/master/src/core/core.interaction.js#L242) . This question has been already asked numerous times before with (for me) incorrect answers and no followups, such as: [link](https://github.com/chartjs/Chart.js/issues/5320) – Ondra da Skacel May 31 '19 at 09:39
0

I achieved this in a graph with two datasets with the following:

const userPricingEl = document.getElementById("userPricingChart");
const userPricingChart = new Chart();

userPricingEl.onclick = function (evt) {
    let nearestPoints = userPricingChart.getElementsAtEventForMode(evt, "nearest", {
        intersect: false
    });
    if (nearestPoints) {
        let nearestPoint = nearestPoints[0];
        let label = userPricingChart.data.datasets[nearestPoint._datasetIndex].label;
        let value = userPricingChart.data.datasets[nearestPoint._datasetIndex].data[nearestPoint._index];
        console.log(label, value);
    }
}

Where "userPricingChart" is a fully fleshed out new Chart() object, which I omitted for brevity.

The key feature here is the getElementsAtEventForMode() function, documented here (albeit arguably badly).

Hope this helps.

George
  • 640
  • 7
  • 13