Определение элемента под курсором: getElementsAtEventForMode

В Chart.js взаимодействие с графиком строится вокруг системы событий и режимов наведения. Центральный механизм, отвечающий за определение элементов, находящихся под курсором, реализован через метод экземпляра графика getElementsAtEventForMode. Он используется внутри логики tooltip’ов, hover-поведения и пользовательских обработчиков событий.


Сигнатура метода

Метод вызывается на экземпляре графика:

chart.getElementsAtEventForMode(event, mode, options, useFinalPosition)

Параметры:

  • event — объект события мыши или тач-события
  • mode — режим поиска элементов
  • options — конфигурация взаимодействия (interaction options)
  • useFinalPosition — учитывать ли финальную позицию (после анимации)

Возвращает массив элементов диаграммы (Element[]), соответствующих условиям поиска.


Принцип работы механизма поиска

При движении курсора Chart.js выполняет несколько этапов:

  1. Преобразование координат события в координаты canvas
  2. Учет текущего состояния анимации и трансформаций
  3. Выбор элементов данных (точек, столбцов, сегментов)
  4. Применение режима поиска (mode)
  5. Фильтрация через параметры interaction

Итогом является набор элементов, которые считаются «активными» в точке взаимодействия.


Режимы поиска (mode)

Параметр mode определяет стратегию определения элементов.

point

Режим точечного попадания. Возвращает элементы, находящиеся непосредственно под курсором.

Используется для scatter plot, line chart с точками, bubble chart.

mode: 'point'

Поведение строгое: если курсор не попадает в область точки, элемент не возвращается.


nearest

Возвращает ближайшие элементы к курсору, даже если прямого попадания нет.

mode: 'nearest'

Особенности:

  • учитывается расстояние до центра элемента
  • полезен для line charts
  • часто используется в tooltip по умолчанию

index

Возвращает все элементы с одинаковым индексом по оси X.

mode: 'index'

Применение:

  • сравнение значений разных datasets в одной категории
  • bar charts, stacked charts

Если курсор попадает в категорию, возвращаются все dataset-элементы этой категории.


dataset

Возвращает все элементы одного dataset.

mode: 'dataset'

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


x / y (в зависимости от версии)

В современных конфигурациях interaction mode может учитывать только одну ось:

mode: 'x'

или

mode: 'y'

Это позволяет работать с частичными совпадениями по координатной оси.


Параметры interaction options

Объект options управляет фильтрацией найденных элементов.

Пример структуры:

options: {
  intersect: true,
  axis: 'x'
}

intersect

Определяет, требуется ли прямое попадание курсора в элемент.

  • true — курсор должен пересекать элемент
  • false — достаточно близости (особенно важно для nearest)

axis

Ограничивает поиск одной осью:

  • 'x' — только по горизонтали
  • 'y' — только по вертикали
  • null — обе оси

useFinalPosition

Параметр влияет на то, учитывается ли анимационное состояние:

useFinalPosition: false
  • true — используется финальная позиция элементов после анимации
  • false — текущая промежуточная позиция (во время анимации)

Это важно при работе с плавными переходами, чтобы hover не «дрожал» во время анимации.


Внутренний механизм определения элементов

Chart.js использует координатную систему canvas и bounding box каждого элемента.

Для каждого data point:

  1. Вычисляется позиция (x, y)
  2. Определяется зона попадания (hit area)
  3. Проверяется соответствие режиму (mode)
  4. Применяются фильтры interaction

Для разных типов графиков логика различается:

  • bar chart — прямоугольные зоны
  • line chart — точки и линии
  • pie/doughnut — сегменты дуги

Пример базового использования

const elements = chart.getElementsAtEventForMode(
  event,
  'nearest',
  { intersect: true },
  false
);

if (elements.length) {
  const first = elements[0];
  const datasetIndex = first.datasetIndex;
  const index = first.index;

  console.log(datasetIndex, index);
}

Использование в обработчиках событий

Метод часто применяется внутри onClick:

options: {
  onClick: (event) => {
    const elements = chart.getElementsAtEventForMode(
      event,
      'index',
      { intersect: false },
      true
    );

    elements.forEach(el => {
      console.log(el.datasetIndex, el.index);
    });
  }
}

Такой подход позволяет реализовать:

  • кастомные tooltip’ы
  • drill-down навигацию
  • интерактивные таблицы данных
  • подсветку серий

Различие с getElementsAtEvent

Метод getElementsAtEventForMode является более гибким расширением старого подхода:

  • getElementsAtEvent(event) — фиксированная логика
  • getElementsAtEventForMode(...) — управляемая стратегия поиска

Фактически второй метод является ядром современной системы interaction.


Особенности поведения в сложных графиках

Stacked charts

При использовании stacked bar charts режим index возвращает элементы всех слоев стека.

Time scale

При временных осях поиск выполняется по преобразованному timestamp, а не по визуальному положению категории.

Multi-axis charts

Если используется несколько осей, axis в options становится критически важным для корректного определения элементов.


Типичные ошибки при использовании

  • Использование intersect: true в line charts с small points — приводит к «потере» hover
  • Игнорирование axis в grouped bar charts — возвращаются лишние элементы
  • Попытка использовать dataset для точечного анализа значений
  • Несоответствие mode и типа графика

Практическая модель выбора режима

  • точечный анализ данных → point
  • подсветка ближайшего значения → nearest
  • сравнение категорий → index
  • выделение серии → dataset
  • интерактивные hover-эффекты → nearest + intersect:false

Взаимодействие с tooltip системой

TooltipController внутри Chart.js использует тот же метод:

  • вычисляет элементы через getElementsAtEventForMode
  • затем строит модель tooltip data
  • применяет callbacks (label, title, footer)

Это делает метод фундаментальной частью всей системы взаимодействия.


Производительность и оптимизация

При частых событиях (mousemove) важно учитывать:

  • сложность dataset (количество точек)
  • режим nearest дороже, чем index
  • отключение лишних interaction options снижает нагрузку

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

interaction: {
  mode: 'index',
  intersect: false
}

Поведение при кастомных элементах

При использовании кастомных элементов (plugins, custom controllers) необходимо реализовать корректные hit areas, иначе getElementsAtEventForMode не сможет их обнаружить.

Это требует:

  • правильного inRange метода
  • корректного bounding box расчёта
  • учета transform scale/rotation canvas

Роль в архитектуре Chart.js

Метод является связующим звеном между:

  • системой событий DOM
  • системой отрисовки элементов
  • логикой tooltip и hover
  • пользовательскими расширениями

Фактически он определяет, какие данные считаются «активными» в любой момент взаимодействия с графиком.