Recharts: how is it possible to show only the value of ONE data point inside a Tooltip?

3k Views Asked by At

I am trying to implement the following example inside a Recharts LineChart: the Tooltip value is relative to the blue point, because my mouse happens to be near it, and further away from the grey point with the same x-value. If I move the mouse closer to the grey point, the tooltip content changes.

Tooltip showing data about just ONE data series

However, all available examples show that a Recharts Tooltip receives data about all the data series being drawn and that it seems not possible to discriminate the point nearest to the mouse, so that the Tooltip may provide its value only.

Is there a way to specify for which dot I want to send data to the Tooltip?

1

There are 1 best solutions below

0
On BEST ANSWER

At the end of a long fruitless search, I decided to solve this problem myself. The minimal code is published in this Github gist.

The basic problem to solve is that any standard Recharts tooltip receives information about:

  • the x-value where the mouse pointer is at the moment, expressed in pixels on the chart canvas
  • the y-values for all the data series in closest position to the mouse x-value, expressed in the y-axis real-world unit (euros, kilograms, etc.)

It is necessary therefore to feed the custom tooltip also with y-axis mouse position information expressed in pixels on the chart canvas. The tooltip can then calculate which data series is closest to the vertical mouse position and display only the value belonging to that data series.

Extracting the y-position in pixels is tricky, because Recharts changes the mapping between pixel and ordinate values each time it redraws the chart. But there is a chart component that must know very well this mapping, in order to place itself at the right vertical position and display the corresponding real-world ordinate value: that's every tick on the y-axis.

Problem is: how do we plug into the Recharts drawing workflow in order to get to know the mapping?

Here's how: the tick property of the Recharts YAxis component allows to provide a custom React component, albeit not documented with examples. This custom component is instantiated one time for each tick that Recharts decides to place on the y-axis. By trial and error I found out that my custom Tick component receives the following properties:

{ x, y, payload, ...anyCustomPropertyAddedByMe }

Where x and y are the cartesian coordinates of the tick (canvas pixels) and payload is such an object:

{ coordinates, isShow, offset, tickCoord, value }

Where value is expressed in real-world y-axis units.

The idea is to find out the couple (y, value) for the lowest and highest tick in each drawing and calculate the conversion factor between pixels and real values. This will allow the custom tooltip to perform the computations mentioned above. (Strictly speaking it would be enough to collect two couples from the first two ticks that are instantiated at each chart repaint, but choosing the two most far apart gives more precision)

The whole algorithm is divided among three components:

  • a tooltipCollector: this is a JavaScript module that presents two methods:

    1. collect(value, y), invoked by the customized tick, that stores all couples (y, value) in a private array _collection
    2. maxAndMin(), invoked by the custom tooltip, that reads the _collection array and returns the couple of items in the collection that represent the lowest and highest ticks (watch out that vertical pixel values in a canvas are measured upside down!)
  • a CustomizedTick React component that:

    1. receives the tooltip collector among its custom properties
    2. sends its y and payload.value to the collector by invoking its collect(y, value) method
    3. returns a very simple JSX tick markup that makes usage of y (to place itself at the right vertical position) and payload.value (to display the user the real-world value the tick indicates)
  • a CustomTooltip React component that:

    1. receives the tooltip collector among its custom properties and invokes its maxAndMin() method
    2. verifies (by considering its prop coordinate.y) whether it's close enough to one of the chart data series, using a threshold value; this ensures that the tooltip is drawn only when the mouse cursor is very close to a point on the graph
    3. modifies its returned JSX markup to contain only the value relative to the data series the mouse is closest to; in case more points in the chart are closer than the threshold, the tooltip will present more than one value

The code in my gist has been simplified to remove all unnecessary JSX markup. It presents a chart component that puts at work all the above mentioned components.

Single-value CustomTooltip in action

Please note that the standard Recharts behaviour of highlighting all the data series' points to which the tooltip abscissa is pointing has not been changed. It is therefore good practice to put a color code in the tooltip content to illustrate clearly to which data series the displayed value belongs.