Normally, XYCursor, if added to a chart will try to show a tooltip for each series for the hovered date or category. This does not work for charts that have both X and Y axes as ValueAxis. This tutorial will show how we can fix that.
The problem
Say, we have an XYChart with three series plotting on numeric values for both X and Y.
This means we are using ValueAxis for both X and Y.
Now we want to display a tooltip for all series over same hovered X value.
That would be easy if our X axis was DateAxis or CategoryAxis: just add an XYCursor and set tooltipText for all series:
let lineSeries = chart.series.push(new am4charts.LineSeries());
lineSeries.dataFields.valueY = "ay";
lineSeries.dataFields.valueX = "ax";
lineSeries.tooltipText = "X: {valueX} / Y: {valueY}";
let lineSeries2 = chart.series.push(new am4charts.LineSeries());
lineSeries2.dataFields.valueY = "by";
lineSeries2.dataFields.valueX = "bx";
lineSeries2.tooltipText = "X: {valueX} / Y: {valueY}";
var lineSeries = chart.series.push(new am4charts.LineSeries());
lineSeries.dataFields.valueY = "ay";
lineSeries.dataFields.valueX = "ax";
lineSeries.tooltipText = "X: {valueX} / Y: {valueY}";
var lineSeries2 = chart.series.push(new am4charts.LineSeries());
lineSeries2.dataFields.valueY = "by";
lineSeries2.dataFields.valueX = "bx";
lineSeries2.tooltipText = "X: {valueX} / Y: {valueY}";
{
// ...
"series": [{
"type": "LineSeries",
"tooltipText": "X: {valueX} / Y: {valueY}",
"dataFields": {
"valueY": "ay",
"valueX": "ax"
}
}, {
"type": "LineSeries",
"tooltipText": "X: {valueX} / Y: {valueY}",
"dataFields": {
"valueY": "by",
"valueX": "bx"
}
}]
}
This won't work with a all-ValueAxis scenario, though.
The solution
The solution is to give ValueAxis an ability to find the closest data item to cursor's position.
To do that all we need to do is to create a method that does it. It needs to be called getSeriesDataItem().
If we want to enable this for all charts on the page, we can override ValueAxis class prototype:
am4charts.ValueAxis.prototype.getSeriesDataItem = function(series: am4charts.XYSeries, position: number): am4charts.XYSeriesDataItem {
const key: string = this.axisFieldName + this.axisLetter;
const value: number = this.positionToValue(position);
const dataItem = series.dataItems.getIndex(series.dataItems.findClosestIndex(value, (x: any) => {
return x[key] ? <number>x[key] : undefined;
}, "any"));
return dataItem;
}
am4charts.ValueAxis.prototype.getSeriesDataItem = function(series, position) {
var key = this.axisFieldName + this.axisLetter;
var value = this.positionToValue(position);
var dataItem = series.dataItems.getIndex(series.dataItems.findClosestIndex(value, function(x) {
return x[key] ? x[key] : undefined;
}, "any"));
return dataItem;
}
Or, if we want to enable it just for a single ValueAxis instance:
valueAxisX.getSeriesDataItem = function(series: am4charts.XYSeries, position: number): am4charts.XYSeriesDataItem {
const key: string = this.axisFieldName + this.axisLetter;
const value: number = this.positionToValue(position);
const dataItem = series.dataItems.getIndex(series.dataItems.findClosestIndex(value, (x: any) => {
return x[key] ? <number>x[key] : undefined;
}, "any"));
return dataItem;
}
valueAxisX.getSeriesDataItem = function(series, position) {
var key = this.axisFieldName + this.axisLetter;
var value = this.positionToValue(position);
var dataItem = series.dataItems.getIndex(series.dataItems.findClosestIndex(value, function(x) {
return x[key] ? x[key] : undefined;
}, "any"));
return dataItem;
}
Examples
All ValueAxis
See the Pen Scatter Chart with cursor and tooltips for all series by amCharts team (@amcharts) on CodePen.
Single ValueAxis
See the Pen Scatter Chart with cursor and tooltips for all series by amCharts team (@amcharts) on CodePen.