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.