Crosshair: настройка перекрестья

Перекрестье (crosshair) в визуализациях Nivo представляет собой интерактивный элемент, который следует за курсором и визуально фиксирует текущую позицию на графике. Оно используется для повышения читаемости значений в точке наведения и синхронизации визуального контекста между осями.

В зависимости от типа графика (Line, Scatter, Area) перекрестье может работать в связке с сеткой, тултипами и слоями отрисовки, формируя единый механизм навигации по данным.


Типы перекрестья

В Nivo перекрестье концептуально делится на несколько режимов отображения:

Вертикальное перекрестье (x-axis tracking) Отображает линию, фиксирующую положение по оси X. Используется в линейных графиках для анализа временных рядов.

Горизонтальное перекрестье (y-axis tracking) Фиксирует значение по оси Y. Реже используется самостоятельно, чаще — в комбинации с вертикальным режимом.

Полное перекрестье (full crosshair) Сочетает вертикальную и горизонтальную линии, образуя координатную привязку к точке данных.

Тип перекрестья определяется логикой взаимодействия компонента и настройками слоя (layers), а также режимами наведения (mesh/slices).


Базовое включение перекрестья в Line графике

В ResponsiveLine перекрестье обычно активируется через комбинацию интерактивных свойств.

import { ResponsiveLine } from '@nivo/line'

const data = [
  {
    id: 'series-1',
    data: [
      { x: 1, y: 10 },
      { x: 2, y: 20 },
      { x: 3, y: 15 },
    ],
  },
]

export default function Chart() {
  return (
    <ResponsiveLine
      data={data}
      margin={{ top: 20, right: 20, bottom: 50, left: 50 }}
      xScale={{ type: 'linear' }}
      yScale={{ type: 'linear', min: 0, max: 'auto' }}
      useMesh={true}
      enableSlices="x"
    />
  )
}

Параметры useMesh и enableSlices косвенно управляют тем, как формируется область наведения, которая и определяет поведение перекрестья.


Режимы взаимодействия: mesh и slices

useMesh

Механизм mesh создаёт невидимую триангуляционную сетку поверх графика. Она обеспечивает точное определение ближайшей точки, даже если реальные данные разрежены.

useMesh={true}

Mesh особенно полезен при:

  • большом количестве точек
  • шумных временных рядах
  • необходимости точного crosshair без привязки к точкам данных

enableSlices

Slices формируют вертикальные или горизонтальные срезы данных.

enableSlices="x"

Возможные значения:

  • "x" — вертикальный срез (основной режим для crosshair по времени)
  • "y" — горизонтальный срез
  • false — отключено

Срезы обеспечивают синхронное выделение всех серий на одной координате, что напрямую связано с отображением перекрестья.


Настройка визуального оформления перекрестья

В Nivo перекрестье может быть переопределено через кастомные слои (layers) или стилизовано через theme.

Стилизация через theme

theme={{
  crosshair: {
    line: {
      stroke: '#ff0000',
      strokeWidth: 1,
      strokeOpacity: 0.8,
      strokeDasharray: '4 4',
    },
  },
}}

Основные параметры:

  • stroke — цвет линии
  • strokeWidth — толщина
  • strokeOpacity — прозрачность
  • strokeDasharray — пунктирный стиль

Кастомизация через layers

Перекрестье может быть полностью переопределено через кастомный слой.

const CustomCrosshair = ({ x, y }) => {
  if (!x || !y) return null

  return (
    <g>
      <line
        x1={x}
        x2={x}
        y1={0}
        y2="100%"
        stroke="black"
        strokeWidth={1}
      />
      <line
        x1={0}
        x2="100%"
        y1={y}
        y2={y}
        stroke="black"
        strokeWidth={1}
      />
    </g>
  )
}

Подключение:

<ResponsiveLine
  data={data}
  layers={[
    'grid',
    'markers',
    'axes',
    'areas',
    'lines',
    CustomCrosshair,
    'points',
    'legends',
  ]}
/>

Такой подход полностью заменяет стандартную реализацию перекрестья.


Синхронизация перекрестья с tooltip

Перекрестье тесно связано с системой tooltip. В Nivo tooltip получает координаты активной точки, которые затем используются для позиционирования линий.

tooltip={({ point }) => (
  <div>
    x: {point.data.x}
    <br />
    y: {point.data.y}
  </div>
)}

При этом:

  • mesh/slices определяют активную точку
  • tooltip отображает данные
  • crosshair визуально фиксирует позицию

Поведение перекрестья в Scatter Plot

В ScatterPlot перекрестье работает через аналогичную механику, но вместо линий чаще используется точечная привязка.

<ResponsiveScatterPlot
  data={data}
  useMesh={true}
  nodeSize={8}
  tooltip={({ node }) => (
    <div>
      x: {node.data.x}
      y: {node.data.y}
    </div>
  )}
/>

Здесь crosshair часто проявляется как связка:

  • подсветка ближайшего узла
  • вертикальная/горизонтальная линия (если кастомизировано)
  • tooltip

Контроль поведения перекрестья через события

Nivo позволяет отслеживать движение курсора и управлять логикой отображения:

onMouseM ove={(node, event) => {
  // node содержит активную точку
}}

onMouseLe ave={() => {
  // сброс состояния crosshair
}}

Такая модель используется для:

  • синхронизации нескольких графиков
  • внешнего управления tooltip
  • кастомных overlay-компонентов

Комбинирование перекрестья с анимациями

При включённых анимациях перекрестье может наследовать задержки обновления позиции. Это важно учитывать при высокой частоте обновлений данных.

motionConfig="stiff"
animate={true}

При использовании:

  • мягких анимаций возможна задержка следования crosshair
  • отключение анимаций повышает точность реакции

Производительность при использовании crosshair

Основные факторы влияния:

1. useMesh

  • увеличивает вычислительную нагрузку при большом количестве точек

2. enableSlices

  • требует агрегации данных по осям

3. кастомные layers

  • могут замедлять рендер при сложной логике SVG

Оптимизация обычно достигается через:

  • ограничение количества точек
  • мемоизацию tooltip-компонентов
  • отключение лишних слоёв

Практические паттерны использования

Синхронизация нескольких графиков

Перекрестье используется как внешний сигнал:

const [cursor, setCursor] = useState(null)

onMouseM ove={(node) => setCursor(node)}

Глобальный crosshair для dashboard

Общий state курсора передаётся в несколько компонентов, обеспечивая единое положение перекрестья.

Фокус на временных рядах

Наиболее эффективный режим:

enableSlices="x"
useMesh={false}

Он обеспечивает стабильное вертикальное перекрестье, соответствующее временной оси.


Комбинация сетки, slices и mesh формирует основу интерактивной навигации по данным в Nivo, где перекрестье выступает центральным визуальным индикатором текущей позиции анализа.