Variations on `nearest` interaction mode
See original GitHub issueFeature Proposal
Either add some sort of nearestPerDataset
mode and some sort of intersectRadius
or maxDistance
option, or make it easier to create new interaction modes by exporting more functions from core.interaction.js.
Feature Use Case
I have some dense data with uneven X values and would like for the tooltip to display the nearest value for each dataset. The current Chart.js interaction modes don’t do what I want:
x
displays multiple values per dataset, because the data is dense enough that there’s more than one value within range.nearest
looks for the single nearest X coordinate. Since the datasets have uneven X values, one or more datasets are often excluded.
See https://codesandbox.io/s/chartjs-interaction-modes-pkf2b?file=/src/index.js for a demo.
To solve this, I’m locally experimenting with a variation of nearest
that determines the nearest element per dataset and returns all nearest-per-dataset elements whose distance is close enough to minDistance.
Unrelated to this, I was also experimenting with a variation on {mode: 'nearest', axis: 'xy'}
that only shows items if the cursor is relatively close to a data point. I wanted something that’s more tolerant than intersect: true
but not so broad that it pops up a tooltip at the other end of the chart if you mouse over a large, sparse chart. (In other words, it’s identical to core.interaction.js’s getNearestItems
with !intersect
, except that it would also check minDistance
against some sort of intersectRadius
or maxDistance
option.)
I suspect these options are specialized enough that they shouldn’t necessarily go into Chart.js, and I’m fine with implementing them myself. However, it feels hard to implement them myself: if I want behavior similar to nearest
, I have to reference private members and duplicate a lot of non-exported functionality from core.interaction.js.
So, instead of adding more specialized interaction modes and options, what about exporting more of core.interaction.js?
Possible Implementation
A simple exported function could look like this:
export function evaluateItems(callback, chart, position, axis, intersect?, useFinalPosition?) {
const minPadding = chart._minPadding;
if (!_isPointInArea(position, chart.chartArea, minPadding)) {
return;
}
const evaluationFunc = (element, datasetIndex, index) => {
if (intersect && !element.inRange(position.x, position.y, useFinalPosition)) {
return;
}
const center = element.getCenterPoint(useFinalPosition);
if (
!_isPointInArea(center, chart.chartArea, minPadding) &&
!element.inRange(position.x, position.y, useFinalPosition)
) {
return;
}
callback(element, datasetIndex, index);
};
optimizedEvaluateItems(chart, axis, position, evaluationFunc);
}
There may also be room to consolidate some of the core.interaction.js modes (so they share more implementation and so their implementation is closer to a hypothetical exported evaluateItems
).
I can work on a PR if this seems reasonable / desirable.
Issue Analytics
- State:
- Created 2 years ago
- Comments:5 (5 by maintainers)
Top GitHub Comments
This is tracked in #9974, if I’m understanding correctly.
FWIW, that’s not quite what I was looking for with
nearestPerDataset
- it would avoid displaying multiple values for dense data (which is what I wanted), but it sounds like it wouldn’t accommodate uneven data rates (the ability to display something for each dataset when one dataset is at X coordinates 0, 1, 2, and another at 0.01, 1.01, 2.01).Yup, I’m happy to look at a PR. I agree with starting with just the code changes since there will probably be some iterations to get to the final design