Chart Cursor
Cursor is a crosshaired lines you see on the chart when hovering the plot area. It helps to gauge precise position on value scale, helps display tooltips for multiple series at a time, can be used as a zoom tool, as well as provides interactivity to the charts.
This article will explain how chart cursors are created, configured, as well as their relationship with other chart elements like axes and series.
Cursor basics
Section titled “Cursor basics”Creating cursor
Section titled “Creating cursor”Creating a chart cursor is super easy. You just instantiate an object of a cursor type that is relevant to the chart type, then assign it to chart’s cursor property.
For an XY chart, that’s XYCursor. For a Radar chart it’s RadarCursor.
chart.cursor = new am4charts.XYCursor();chart.cursor = new am4charts.XYCursor();{ // ... "cursor": { // No need to set `type` here - the chart already // knows what type of cursor it needs. }}Let’s take a simple XY chart with three Line series, and add a cursor there:
Now, when you hover the plot area, you see two lines - horizontal and vertical going to each Axis, with Tooltips indicating cursor vertical and horizontal position.
Adding a Cursor also automatically enables zooming. Try holding mouse button or touch down and moving it around. It will zoom the chart.
That’s the default look and behavior of the chart Cursor.
Subsequent sections will show how to modify cursor’s appearance and behavior to suit your particular needs.
Configuring cursor
Section titled “Configuring cursor”By default, Cursor looks like two crossed black dashed lines. Some theme, might modify this look. You can do it, too.
Just like any other object in amCharts 4, Cursor is an object with own properties you can modify to change its appearance.
For a full selection of properties available, take a look at the class reference entry for XYCursor and RadarCursor.
Let’s just look at a few here.
Changing basic appearance settings
Section titled “Changing basic appearance settings”Suppose, we don’t like that cursor line is dashed. We also not crazy about it being black, and so thin, and so prominent. Yes, we’re awfully nitpicky, but that’s not a problem, because it’s all doable easily.
Examining XYCursor’s class reference, like we suggested a minute ago, we see that it has two separate properties - lineX and lineY - that hold actual line objects for vertical line and horizontal line respectively.
We can use those to configure the look of Cursor’s lines, to apply our changes:
chart.cursor.lineX.stroke = am4core.color("#8F3985");chart.cursor.lineX.strokeWidth = 4;chart.cursor.lineX.strokeOpacity = 0.2;chart.cursor.lineX.strokeDasharray = "";
chart.cursor.lineY.stroke = am4core.color("#8F3985");chart.cursor.lineY.strokeWidth = 4;chart.cursor.lineY.strokeOpacity = 0.2;chart.cursor.lineY.strokeDasharray = "";chart.cursor.lineX.stroke = am4core.color("#8F3985");chart.cursor.lineX.strokeWidth = 4;chart.cursor.lineX.strokeOpacity = 0.2;chart.cursor.lineX.strokeDasharray = "";
chart.cursor.lineY.stroke = am4core.color("#8F3985");chart.cursor.lineY.strokeWidth = 4;chart.cursor.lineY.strokeOpacity = 0.2;chart.cursor.lineY.strokeDasharray = "";{ // ... "cursor": { "lineX": { "stroke": "#8F3985", "strokeWidth": 4, "strokeOpacity": 0.2, "strokeDasharray": "" }, "lineY": { "stroke": "#8F3985", "strokeWidth": 4, "strokeOpacity": 0.2, "strokeDasharray": "" } }}Beautiful!
Disabling cursor lines
Section titled “Disabling cursor lines”In case you don’t want one or both Cursor’s lines to show, you can use their respective universal disabled property.
Let’s try disabling horizontal line: (lineY)
chart.cursor.lineY.disabled = true;chart.cursor.lineY.disabled = true;{ // ... "cursor": { // ... "lineY": { "disabled": true } }}Enabling “full-width” cursor lines
Section titled “Enabling “full-width” cursor lines”Cursor is not limited to a thin, or fixed-width lines either.
On Date and Category axis, it can also display a full-width fill instead of a line.
For that we have cursor’s fullWidthLineX and fillWidthLineY settings, that accept boolean true/false values, with false being default. As you probably already guessed, fullWidthLineX enables vertical full-width Cursor line, while fullWidthLineY enables horizontal.
Please note, that it’s usually not enough to enable those settings. At the very least, the Cursor needs to know which particular axis to use to manage it’s “full width” line. For that we’ll also need to set Cursor’s xAxis and yAxis respectively.
We will also want to configure fill* settings.
Something like this:
chart.cursor.xAxis = categoryAxis;chart.cursor.fullWidthLineX = true;chart.cursor.lineX.strokeWidth = 0;chart.cursor.lineX.fill = am4core.color("#8F3985");chart.cursor.lineX.fillOpacity = 0.1;chart.cursor.xAxis = categoryAxis;chart.cursor.fullWidthLineX = true;chart.cursor.lineX.strokeWidth = 0;chart.cursor.lineX.fill = am4core.color("#8F3985");chart.cursor.lineX.fillOpacity = 0.1;{ // ... "cursor": { // ... "xAxis": "a1", // referring to an Axis by its "id" "fullWidthLineX": true, "lineX": { "strokeWidth": 0, "fill": "#8F3985", "fillOpacity": 0.1 } }}Cursor behavior
Section titled “Cursor behavior”Cursor, besides indicating position, has a lot of other functional purposes. This section will discuss them in greater detail.
Zooming & panning
Section titled “Zooming & panning”Cursor can be used to zoom in, pan (move current selection) the chart, or select ranges on a chart.
By default, Cursor is used to select a horizontal range to zoom in chart to.
Try dragging cursor in the below chart. Once you press your button and start moving you’ll see it starting to select a range. Once you release mouse button, the chart will zoom in to show the selected range.
This behavior can be changed in a lot of ways, using Cursor’s property behavior.
Here’s a full list of available options:
Setting | Purpose | Sample |
|---|---|---|
| Zooms all horizontal axes |
|
| Zooms all vertical axes |
|
| Zooms both horizontal and vertical axes See note about |
|
| Pans the chart (moves zoomed selection) horizontally |
|
| Pans the chart (moves zoomed selection) vertically |
|
| Pans the chart both horizontally and vertically |
|
| Selects horizontal range |
|
| Selects vertical range |
|
| Selects both horizontal and vertical range |
|
| Does nothing |
|
More on zooming
If Cursor behavior is set to zooming (zoomX, zoomY, zoomXY) the whole chart will be zoomed in when selecting ranges.
Please note that all respective axes will be zoomed in the zoom direction. For example, if you have set Cursor behavior to zoomY and you have two vertical axes, both of them will be zoomed.
There is no way to attach zoom to just one axis.
zoomXY behavior and DateAxis
Section titled “zoomXY behavior and DateAxis”The zoomXY behavior will function differently if one of the chart axes is DateAxis. It will zoom the DateAxis but will adjust the opposing ValueAxis to fit all values within selected range.
To disable this you can use this workaround: disable selectionextremeschangedevent on all series in the chart:
series.events.off( "selectionextremeschanged", valueAxis.handleSelectionExtremesChange, valueAxis, false);series.events.off( "selectionextremeschanged", valueAxis.handleSelectionExtremesChange, valueAxis, false);{ // ... "series": [{ // ... "callback": function() { this.events.off( "selectionextremeschanged", this.yAxis.handleSelectionExtremesChange, this.yAxis, false ); } }]}More on panning
Section titled “More on panning”Panning is moving current selection in one direction or the other. Naturally, panning will not work if the chart is fully zoomed out.
The chart can be zoomed in (before panning) using Scrollbar and/or programatically via API.
There’s one Cursor setting that affects pan behavior: maxPanOut.
If it’s set to zero, the Cursor will not be allowed to pan beyond actual range of data.
However, if you set it to a relative value, say 0.15, Cursor will allow the user to drag selection beyond data range, then will gently snap back to the data range when released. The value is relative, meaning that 0.15 will allow user to drag 15% beyond actual range.
More on selection
Section titled “More on selection”Selection, on its own, does not make a lot of sense. However, when combined with specific events, it can be turned into a powerful tool.
The two events in question are Cursor’s selectstarted (indicates that user started selection) and selectended (indicating user is done selecting).
Handler function for those events will receive Cursor’s object, which we can then use to determine current selection ranges using Cursor’s xRange and yRange properties, that hold currently selected horizontal and vertical ranges respectively.
Below example shows how we can use Cursor’s events to check the selection on the Category axis, with help of its method getPositionLabel(location), which converts start/end values returned by xRange to actual categories.
chart.cursor.behavior = "selectX";chart.cursor.events.on("selectended", function(ev) { let range = ev.target.xRange; if (range) { let axis = ev.target.chart.xAxes.getIndex(0); let from = axis.getPositionLabel(axis.toAxisPosition(range.start)); let to = axis.getPositionLabel(axis.toAxisPosition(range.end)); alert("Selected from " + from + " to " + to); }});chart.cursor.behavior = "selectX";chart.cursor.events.on("selectended", function(ev) { var range = ev.target.xRange; if (range) { var axis = ev.target.chart.xAxes.getIndex(0); var from = axis.getPositionLabel(axis.toAxisPosition(range.start)); var to = axis.getPositionLabel(axis.toAxisPosition(range.end)); alert("Selected from " + from + " to " + to); }});{ // ... "cursor": { // ... "behavior": "selectX", "events": { "selectended": function(ev) { var range = ev.target.xRange; if (range) { var axis = ev.target.chart.xAxes.getIndex(0); var from = axis.getPositionLabel(axis.toAxisPosition(range.start)); var to = axis.getPositionLabel(axis.toAxisPosition(range.end)); alert("Selected from " + from + " to " + to); } } } }}And here’s a working example of the the above. Try selecting a range on it:
Relation to series
Section titled “Relation to series”Series tooltips
Section titled “Series tooltips”An added bonus to using Cursor is that it can simultaneously interact with multiple chart elements, such as display tooltips for all series in the same position.
To enable such usage all you have to do is to set tooltipText (or tooltipHTML) for each series you want tooltips displayed on.
let series1 = chart.series.push(new am4charts.LineSeries());// ...series1.tooltipText = "{categoryX}: [bold]{valueY}[/]";
let series2 = chart.series.push(new am4charts.LineSeries());// ...series2.tooltipText = "{categoryX}: [bold]{valueY}[/]";
let series3 = chart.series.push(new am4charts.LineSeries());// ...series3.tooltipText = "{categoryX}: [bold]{valueY}[/]";var series1 = chart.series.push(new am4charts.LineSeries());// ...series1.tooltipText = "{categoryX}: [bold]{valueY}[/]";
var series2 = chart.series.push(new am4charts.LineSeries());// ...series2.tooltipText = "{categoryX}: [bold]{valueY}[/]";
var series3 = chart.series.push(new am4charts.LineSeries());// ...series3.tooltipText = "{categoryX}: [bold]{valueY}[/]";{ // ... "series": [{ "type": "LineSeries", // ... "tooltipText": "{categoryX}: [bold]{valueY}[/]" }, { "type": "LineSeries", // ... "tooltipText": "{categoryX}: [bold]{valueY}[/]" }, { "type": "LineSeries", // ... "tooltipText": "{categoryX}: [bold]{valueY}[/]" }]}Here’s how it looks like live: (hover over chart)
Limiting number of series tooltips
Section titled “Limiting number of series tooltips”Cursor will display tooltips for all series in the same date/category by default. This might not be the best approach for a chart with a lot of series, as it might get a bit cluttery.
With Cursor’s maxTooltipDistance property, you can instruct the chart to display only closest tooltips to the actual location of the mouse cursor or the location of the tap on screen.
Setting this property to any number disables display of all tooltips but the closest data item as well as those that are within set number of pixels from that target data item.
For example, if we set it to 20, cursor will show tooltip for the closest data item. If there are other data items within 20 pixel radius from it, it will show tooltips for those as well.
chart.cursor.maxTooltipDistance = 20;chart.cursor.maxTooltipDistance = 20;{ // ... "cursor": { // ... "maxTooltipDistance": 20 }}Snapping to data items
Section titled “Snapping to data items”You can also make Cursor “snap” to actual data items of the series by setting its snapToSeries property to either a Series reference or an array of Series references.
chart.cursor.snapToSeries = [series1, series2, series3];chart.cursor.snapToSeries = [series1, series2, series3];{ // ... "cursor": { // ... "snapToSeries": ["s1", "s2", "s3"] }}Now, the cursor will not follow mouse cursor but rather snap to the neares data point out of all the series set in snapToSeries.
Try it here:
Series bullets
Section titled “Series bullets”Tooltips is not the only thing how Cursor can affect series. It can also trigger “hover” state for series’ bullets in Cursor’s current location.
To enable it, all you have to do is to add “hover” state to series’ bullets.
So, if I wanted bullets of the Cursor’s location to grow, I’d have to add scale property to each bullet’s “hover” state.
let bullet1 = series1.bullets.push(new am4charts.CircleBullet());let bullet1hover = bullet1.states.create("hover");bullet1hover.properties.scale = 1.3;
let bullet2 = series2.bullets.push(new am4charts.CircleBullet());let bullet2hover = bullet2.states.create("hover");bullet2hover.properties.scale = 1.3;
let bullet3 = series3.bullets.push(new am4charts.CircleBullet());let bullet3hover = bullet3.states.create("hover");bullet3hover.properties.scale = 1.3;var bullet1 = series1.bullets.push(new am4charts.CircleBullet());var bullet1hover = bullet1.states.create("hover");bullet1hover.properties.scale = 1.3;
var bullet2 = series2.bullets.push(new am4charts.CircleBullet());var bullet2hover = bullet2.states.create("hover");bullet2hover.properties.scale = 1.3;
var bullet3 = series3.bullets.push(new am4charts.CircleBullet());var bullet3hover = bullet3.states.create("hover");bullet3hover.properties.scale = 1.3;{ // ... "series": [{ "type": "LineSeries", // ... "bullets": [{ "type": "CircleBullet", "states": { "hover": { "properties": { "scale": 1.3 } } } }] }, { "type": "LineSeries", // ... "bullets": [{ "type": "CircleBullet", "states": { "hover": { "properties": { "scale": 1.3 } } } }] }, { "type": "LineSeries", // ... "bullets": [{ "type": "CircleBullet", "states": { "hover": { "properties": { "scale": 1.3 } } } }] }]}Here’s how this looks:
Axis tooltips
Section titled “Axis tooltips”As you have already noticed in the number of examples before, each of the Cursor’s lines end up with a tooltip on each axis, indicating said line’s precise location on that axis.

There’s a lot of ways to configure those tooltips to make them useful and look according to your liking.
Relation to legend
Section titled “Relation to legend”Cursor, being a busy bee, can have an impact on yet another chart control - Legend.
With a little bit of setup we can make the Legend dynamically show values (or other information) under Cursor next to related series items in Legend.
In short, you can set up your series to apply different labels in their Legend items using series’ legendSettings.itemLabelText and legendSettings.itemValueText properties:
series1.legendSettings.itemValueText = "{valueY}";series1.legendSettings.itemValueText = "{valueY}";{ // ... "series": { "type": "LineSeries", // ... "legendSettings": { // ... "itemValueText": "{valueY}" } }}Location on axis
Section titled “Location on axis”By default the cursor-initiated axis tooltip will snap to the middle of the category/date/cell on a related axis.
That snap position can be controlled using axis’ renderer’s tooltipLocation property.
It accepts values from 0 (zero) to 1 (one), with zero meaning beginning of the cell, 1 - end, and 0.5 being default middle.
E.g., the below code will make cursor stick to the beginning of the date cell:
dateAxis.renderer.tooltipLocation = 0;dateAxis.renderer.tooltipLocation = 0;{ // ... "xAxes": [{ // ... "renderer": { "tooltipLocation": 0 } }]}











