Tracking Cursor’s position via API

This tutorial will explain how you can track Cursor's position within plot area, as well as map it to real values.

Prerequisites

If you haven't done so already, we strongly suggest you take a look at the "Chart Cursor" article, which walks through every step and aspect of using this chart helper.

We will also be relying on event handlers in this tutorial, so it might be a good idea to familiarize yourself with the concept by checking out "Event Listeners" article.

Tracking Cursor's position

Getting position

To track Cursor's position we will be using its cursorpositionchanged event.

It will be invoked every time a cursor's position changes over the plot area.

It goes something like this:

chart.cursor.events.on("cursorpositionchanged", function(ev) {
  // ...
});
chart.cursor.events.on("cursorpositionchanged", function(ev) {
  // ...
});
{
  // ...
  "cursor": {
    "events": {
      "cursorpositionchanged": function(ev) {
        // ..
      }
    }
  }
}

Now, whenever you glide your mouse over or touch chart's plot area, our event handle will fire. At this point it does nothing since we haven't added any code to it, yet.

Let's see how we can make it useful.

The event handler function will receive a parameter object which, among other properties, will have target property that holds reference to cursor itself.

Since we now have Cursor's object, we can examine its reference and find out that it has properties xPosition and yPosition that respectively hold cursor's relative horizontal and vertical positions within plot area.

chart.cursor.events.on("cursorpositionchanged", function(ev) {
  console.log("x: ", ev.target.xPosition);
  console.log("y: ", ev.target.yPosition);
});
chart.cursor.events.on("cursorpositionchanged", function(ev) {
  console.log("x: ", ev.target.xPosition);
  console.log("y: ", ev.target.yPosition);
});
{
  // ...
  "cursor": {
    "events": {
      "cursorpositionchanged": function(ev) {
        console.log("x: ", ev.target.xPosition);
        console.log("y: ", ev.target.yPosition);
      }
    }
  }
}

As we mentioned earlier, the position properties will show cursor's relative position within plot area, where 0 indicates left/top edge, 0.5 - the middle, and 1 - right/bottom edge.

Not very useful, huh?

Converting to real value, date, or category

The next obvious step is to convert relative "position" to a real value within real axis scale.

Lucky for us, each type of axis has helper functions that will convert position to a real value within it's scale.

Below are listed the functions that will help us:

Axis type Conversion function Comment
CategoryAxis positionToIndex(position) Returns an index of the category that corresponds relative position.
DateAxis positionToDate(position) Returns a Date object that corresponds to relative position.
ValueAxis positionToValue(position) Returns a numeric value that corresponds to the relative position.

So, if our chart has a horizontal Date axis, and a vertical Value axis, we could use positionToDate and positionToValue respectively to convert Cursor's relative xPosition and yPosition to real values.

chart.cursor.events.on("cursorpositionchanged", function(ev) {
  console.log("x: ", ev.target.chart.xAxes.getIndex(0).positionToDate(ev.target.xPosition));
  console.log("y: ", ev.target.chart.yAxes.getIndex(0).positionToValue(ev.target.yPosition));
});
chart.cursor.events.on("cursorpositionchanged", function(ev) {
  console.log("x: ", ev.target.chart.xAxes.getIndex(0).positionToDate(ev.target.xPosition));
  console.log("y: ", ev.target.chart.yAxes.getIndex(0).positionToValue(ev.target.yPosition));
});
{
  // ...
  "cursor": {
    "events": {
      "cursorpositionchanged": function(ev) {
        console.log("x: ", ev.target.chart.xAxes.getIndex(0).positionToDate(ev.target.xPosition));
        console.log("y: ", ev.target.chart.yAxes.getIndex(0).positionToValue(ev.target.yPosition));
      }
    }
  }
}

Now, when you will glide the Cursor of the plot area, you will be getting meaningful x and y coordinates, expressed in values that correspond to the axis type and scale.

Logging last position

The last thing remaining is to log this data somewhere, so that we can access it later, when we need it, perhaps on click.

For that we can define a variable that holds it:

let cursorPosition = {
  x: null,
  y: null
};
chart.cursor.events.on("cursorpositionchanged", function(ev) {
  cursorPosition.x = ev.target.chart.xAxes.getIndex(0).positionToDate(ev.target.xPosition);
  cursorPosition.y = ev.target.chart.yAxes.getIndex(0).positionToValue(ev.target.yPosition);
});
var cursorPosition = {
  x: null,
  y: null
};
chart.cursor.events.on("cursorpositionchanged", function(ev) {
  cursorPosition.x = ev.target.chart.xAxes.getIndex(0).positionToDate(ev.target.xPosition);
  cursorPosition.y = ev.target.chart.yAxes.getIndex(0).positionToValue(ev.target.yPosition);
});
{
  // ...
  "cursor": {
    "events": {
      "cursorpositionchanged": function(ev) {
        cursorPosition.x = ev.target.chart.xAxes.getIndex(0).positionToDate(ev.target.xPosition);
        cursorPosition.y = ev.target.chart.yAxes.getIndex(0).positionToValue(ev.target.yPosition);
      }
    }
  }
}

As simple, as that.

Using tracked info

Obviously, just tracking stuff is not useful in itself. Let's put it to good use.

Let's do something when user clicks on the plot area.

To register click/tap on a XY chart's plot area, we can use hit event on chart's plotContainer:

chart.plotContainer.events.on("hit", function(ev) {
  console.log("Clicked on", cursorPosition);
});
chart.plotContainer.events.on("hit", function(ev) {
  console.log("Clicked on", cursorPosition);
});
{
  // ...
  "plotContainer": {
    "events": {
      "hit": function(ev) {
        console.log("Clicked on", cursorPosition);
      }
    }
  }
}

Now, whenever user clicks anywhere within plot area, we'll get coordinates of that event, expressed in real values.

Here's the full working chart:

See the Pen amCharts V4: Tracking cursor position in axes by amCharts (@amcharts) on CodePen.24419