Recharts value at pointer to show in tooltip?

Viewed 6465

Is it possible in Recharts to show a Horizontal line at the Y location where the user has their mouse over and retrieve that Y value so we can display it on the Tooltip?

https://meridian.a2z.com/components/tooltip/?platform=react-web

I've been trying to do some research into how we could get the Y value on the graph where the mouse is hovering or clicked, but I'm having trouble seeing where we could even pull that out.

Any tips on attributes or components we could use to grab this data? Is it even something we have access to from the library?

To clarify, we're trying to get the value of the Y axis at where the user has their cursor over the graph.

So if the graph looks like this and the user has their mouse at the pink dot location, I would be trying to grab out the value of ~7000 - what the y value would be at that graph location cursor location

2 Answers

Edit:

Note about responsiveness: If you want to make this responsive, just adjust the chartBounds based on the padding/margin you've applied to the chart component and you should be good to go.

If you're trying something more advanced and need the height and width to pass to the chart component for more calculations, the following article should help: https://www.pluralsight.com/tech-blog/getting-size-and-position-of-an-element-in-react/


NOTE: This is a bit of a hack and may not be a perfect solution but it should be enough to get you on the right track

You should be able to use the chartX and chartY fields from onMouseMove. Unfortunately, this is just the pixel value under the cursor but you should be able to translate it into the range you are using for your graph.

Here is an example put together using the SimpleLineChart example recharts has up. This should work if you just want to get the Y value under the user's cursor and can be extended to get the X value as well.

const {LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend} = Recharts;
const data = [
      {name: 'Page A', uv: 4000, pv: 2400, amt: 2400},
      {name: 'Page B', uv: 3000, pv: 1398, amt: 2210},
      {name: 'Page C', uv: 2000, pv: 9800, amt: 2290},
      {name: 'Page D', uv: 2780, pv: 3908, amt: 2000},
      {name: 'Page E', uv: 1890, pv: 4800, amt: 2181},
      {name: 'Page F', uv: 2390, pv: 3800, amt: 2500},
      {name: 'Page G', uv: 3490, pv: 4300, amt: 2100},
];


//The pixel bounds for the LineChart, 0,0 is the top left corner
// these were found using the inspector built into the web browser
// these are in pixels but correspond to the values used in your graph
// so 246 is 0 Y on the graph and 5 is 10000 Y on the graph (according to your data)
const chartBoundsY = {min: 246, max: 5}

// The bounds we are using for the chart
const chartMinMaxY = {min: 0, max: 10000}

// Convert the pixel value from the cursor to the scale used in the chart
const remapRange = value => {
  let fromAbs = value - chartBoundsY.min
  let fromMaxAbs =  chartBoundsY.max - chartBoundsY.min      

  let normal = fromAbs / fromMaxAbs

  let toMaxAbs = chartMinMaxY.max - chartMinMaxY.min
  let toAbs = toMaxAbs * normal

  return Math.ceil(toAbs + chartMinMaxY.min)
}

const SimpleLineChart = React.createClass({
  render () {
    return (
      <LineChart 
        width={600} height={300} data={data}
        margin={{top: 5, right: 30, left: 20, bottom: 5}}
        onMouseMove={props => {
          // We get the values passed into the onMouseMove event 
          if(props.isTooltipActive) {
            // If the tooltip is active then we display the Y value 
            // under the mouse using our custom mapping
            console.log(remapRange(props.chartY))
          }
        }}    
      >
       <XAxis dataKey="name"/>
       <YAxis/>
       <CartesianGrid strokeDasharray="3 3"/>
       <Tooltip/>
       <Legend />
       <Line type="monotone" dataKey="pv" stroke="#8884d8" activeDot={{r: 8}}/>
       <Line type="monotone" dataKey="uv" stroke="#82ca9d" />
      </LineChart>
    )
  }
})

ReactDOM.render(
  <SimpleLineChart />,
  document.getElementById('container')
)

You can open this example in jsfiddle and paste in the code above in the JS editor to try it out for yourself. http://recharts.org/en-US/examples

Here is the documentation for the mouse event for the LineChart: http://recharts.org/en-US/api/LineChart

This can be done with the axis scale option together with d3's invert method.
The following code excerpt should give you an idea.

const domainY = d3.extent(data, d => d[keyY])
const scaleY = d3.scaleLinear().domain(domainY).range([0, 1])

<AreaChart
 onMouseDown={(e) => console.log(scaleY.invert(e.chartY))}
 ...

<YAxis
 domain={['auto', 'auto']}
 dataKey={keyY}
 type="number"
 scale={scaleY}
 ...
Related