useXAxisTicks

Returns the ticks of an XAxis.

This hook is useful for accessing the calculated ticks of an XAxis. The ticks are the same as the ones rendered by the XAxis component.

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

Array<TickItem> | undefined

An array of ticks, or undefined if the axis doesn't exist or hasn't been calculated yet.

  • xAxisIdnumber | stringoptional

    The xAxisId of the XAxis. Defaults to 0 if not provided.

    DEFAULT: "defaultAxisId"