useYAxisInverseTickSnapScale

Returns a function to convert pixel coordinates back to data values for a YAxis, but snapping to the closest axis tick.

This is similar to useYAxisInverseScale, but instead of returning the exact data value at the pixel position (interpolation), it returns the value of the closest tick.

This is useful for implementing interactions where you want to select the closest tick rather than an exact value or a data point.

This hook must be used within a chart context (inside a LineChart, BarChart, etc.). Returns undefined if used outside a chart context, or if the axes don't exist.

Available since Recharts 3.8

// #region imports and mock data
import {
  CartesianGrid,
  DefaultZIndexes,
  getRelativeCoordinate,
  InverseScaleFunction,
  Line,
  LineChart,
  MouseHandlerDataParam,
  ReferenceLine,
  RelativePointer,
  useXAxisInverseTickSnapScale,
  useYAxisInverseTickSnapScale,
  XAxis,
  YAxis,
  ZIndexLayer,
} from 'recharts';
import { MouseEvent, TouchEvent, useCallback, useState } from 'react';
import { RechartsDevtools } from '@recharts/devtools';

const data = [
  { name: 'Jan', sales: 400 },
  { name: 'Feb', sales: 3000 },
  { name: 'Mar', sales: 50000 },
  { name: 'Apr', sales: 24500 },
  { name: 'May', sales: 6000 },
  { name: 'Jun', sales: 45500 },
];
// #endregion

/**
 * This Crosshair component shows how to convert pixel coordinates to data values.
 * In effect it still follows the mouse pointer, but instead of showing pixel coordinates,
 * it shows the closest data values on both axes.
 *
 * It "snaps" to the closest data points using useXAxisInverseTickSnapScale and useYAxisInverseTickSnapScale hooks.
 *
 */
const AxisTickCrosshair = ({ pointer }: { pointer: RelativePointer | null }) => {
  // Convert pixel coordinates to the closest data values
  const xAxisInverseScale: InverseScaleFunction | undefined = useXAxisInverseTickSnapScale();
  const yAxisInverseScale: InverseScaleFunction | undefined = useYAxisInverseTickSnapScale();

  if (pointer == null || xAxisInverseScale == null || yAxisInverseScale == null) {
    return null;
  }
  const xDataLabel = String(xAxisInverseScale(pointer.relativeX));
  const yDataLabel = String(yAxisInverseScale(pointer.relativeY));
  return (
    <ZIndexLayer zIndex={DefaultZIndexes.cursorLine}>
      <ReferenceLine
        x={xDataLabel}
        /*
         * pointerEvents: none is necessary because without it, browser will detect hovering over the Cross itself
         * which makes it trigger mouseLeave on the chart which makes it erase the Cross which looks like it's blinking.
         * If we skip pointer events on the cross then we can skip the mouseLeave and the movement is smooth.
         */
        style={{ pointerEvents: 'none' }}
        stroke="green"
        strokeWidth={1}
        strokeDasharray="4"
        label={{
          value: xDataLabel,
          position: 'top',
          offset: 5,
        }}
      />
      <ReferenceLine
        y={yDataLabel}
        /*
         * pointerEvents: none is necessary because without it, browser will detect hovering over the Cross itself
         * which makes it trigger mouseLeave on the chart which makes it erase the Cross which looks like it's blinking.
         * If we skip pointer events on the cross then we can skip the mouseLeave and the movement is smooth.
         */
        style={{ pointerEvents: 'none' }}
        stroke="green"
        strokeWidth={1}
        strokeDasharray="4"
        label={{
          value: yDataLabel,
          position: 'right',
          offset: 5,
        }}
      />
    </ZIndexLayer>
  );
};

/**
 * This example demonstrates how to use getRelativeCoordinate to get pointer position in pixels,
 * and then convert those pixel coordinates to the closest axis ticks using useXAxisInverseTickSnapScale and useYAxisInverseTickSnapScale hooks.
 */
export default function AxisTickSnapExample({
  initialPointers = [],
}: {
  initialPointers?: ReadonlyArray<RelativePointer>;
}) {
  const [pointers, setPointers] = useState<ReadonlyArray<RelativePointer>>(initialPointers);

  const handleMouseMove = useCallback(
    (_data: MouseHandlerDataParam, event: MouseEvent<SVGGraphicsElement>) => {
      const chartPointer: RelativePointer = getRelativeCoordinate(event);
      setPointers([chartPointer]);
    },
    [setPointers],
  );

  const handleTouchMove = useCallback(
    (_data: unknown, event: TouchEvent<SVGGraphicsElement>) => {
      const chartPointers = getRelativeCoordinate(event);
      setPointers(chartPointers);
    },
    [setPointers],
  );

  const handleLeave = useCallback(() => {
    setPointers([]);
  }, [setPointers]);

  return (
    <LineChart
      style={{
        width: '100%',
        maxWidth: '500px',
        maxHeight: '200px',
        aspectRatio: 1,
        touchAction: 'none',
      }}
      responsive
      data={data}
      margin={{ top: 20, right: 50, left: 20, bottom: 30 }}
      onMouseMove={handleMouseMove}
      onMouseLeave={handleLeave}
      onTouchMove={handleTouchMove}
      onTouchEnd={handleLeave}
    >
      <CartesianGrid />
      <XAxis dataKey="name" />
      <YAxis width="auto" />
      <Line type="monotone" dataKey="sales" strokeWidth={2} />

      {pointers.map(pointer => (
        <AxisTickCrosshair key={`crosshair-${pointer.relativeX}-${pointer.relativeY}`} pointer={pointer} />
      ))}

      <RechartsDevtools />
    </LineChart>
  );
}

Return value

InverseScaleFunction | undefined

An inverse scale function that maps pixel coordinates to the closest tick value, or undefined.

  • yAxisIdnumber | stringoptional

    The yAxisId of the YAxis. Defaults to 0 if not provided.

    DEFAULT: "defaultAxisId"