Механизм зума выделением области в Chart.js основан на обработке событий мыши или касания и динамическом изменении диапазона шкал (scales) графика. В отличие от дискретного увеличения через кнопки или программные вызовы, drag-зум предполагает интерактивное выделение прямоугольной области, которая затем становится новым видимым диапазоном данных.
Основная логика построена вокруг трёх этапов:
Во время движения вычисляются координаты прямоугольника выделения, который визуально накладывается поверх canvas. После завершения выделения координаты преобразуются в значения шкал (x/y), и график пересчитывает диапазон отображаемых данных.
Ключевой момент: Chart.js сам по себе не реализует drag-to-zoom, эта
функциональность предоставляется через расширение
chartjs-plugin-zoom.
Базовая интеграция требует подключения плагина масштабирования и панорамирования:
import { Chart } from 'chart.js';
import zoomPlugin from 'chartjs-plugin-zoom';
Chart.register(zoomPlugin);
После регистрации становится доступна конфигурация
options.plugins.zoom.
Режим drag-зума активируется через настройку zoom по оси с
использованием drag:
const config = {
type: 'line',
data: {
labels: ['A', 'B', 'C', 'D', 'E'],
datasets: [{
label: 'Данные',
data: [10, 25, 18, 30, 22]
}]
},
options: {
plugins: {
zoom: {
zoom: {
wheel: {
enabled: false
},
pinch: {
enabled: false
},
drag: {
enabled: true,
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor: 'rgba(54, 162, 235, 0.8)',
borderWidth: 1
},
mode: 'x'
}
}
}
}
};
Параметр drag.enabled включает механизм выделения
области. Параметр mode определяет оси, которые будут
масштабироваться:
x — только горизонтальная осьy — только вертикальнаяxy — обе оси одновременноВнутри Chart.js координаты мыши находятся в системе canvas, тогда как шкалы работают в доменных значениях данных. Плагин выполняет преобразование через API шкал:
scale.getValueForPixel(pixel)scale.getPixelForValue(value)Логика выделения области опирается на эти методы для вычисления диапазона:
const xStart = chart.scales.x.getValueForPixel(startX);
const xEnd = chart.scales.x.getValueForPixel(endX);
После вычисления диапазона вызывается обновление шкал:
chart.options.scales.x.min = xStart;
chart.options.scales.x.max = xEnd;
chart.update();
Во время движения мыши плагин отрисовывает overlay-слой. Он создаётся поверх canvas через дополнительный контекст или внутренний plugin hook.
Параметры визуализации:
backgroundColor — заливка выделенной областиborderColor — рамка прямоугольникаborderWidth — толщина линииПри этом область пересчитывается на каждом событии
mousemove, что требует оптимизации через
requestAnimationFrame для предотвращения избыточных
перерисовок.
Для предотвращения ухода в некорректные диапазоны используются ограничения:
limits: {
x: {
min: 'original',
max: 'original'
},
y: {
min: 'original',
max: 'original'
}
}
Значение 'original' фиксирует границы исходного набора
данных, предотвращая чрезмерное увеличение или смещение.
Также возможно программное ограничение:
zoom: {
limits: {
x: { minRange: 5 },
y: { minRange: 10 }
}
}
Минимальный диапазон предотвращает слишком сильное приближение, при котором график теряет информативность.
После применения drag-зума часто требуется восстановление исходного состояния:
chart.resetZoom();
Метод сбрасывает значения min и max всех
шкал до исходных, определённых при инициализации графика.
В некоторых сценариях используется ручной сброс:
chart.options.scales.x.min = undefined;
chart.options.scales.x.max = undefined;
chart.update();
При работе с несколькими осями (например, две Y-оси) важно явно указать, какие шкалы участвуют в zoom:
zoom: {
drag: {
enabled: true
},
mode: 'xy',
overScaleMode: 'xy'
}
Параметр overScaleMode определяет, какие шкалы реагируют
на выделение, если курсор находится над областью пересечения нескольких
осей.
При использовании временных шкал (type: 'time') drag-зум
оперирует не индексами массива, а timestamp значениями.
Особенность:
Пример:
scales: {
x: {
type: 'time',
time: {
unit: 'day'
}
}
}
При выделении области плагин возвращает диапазон времени, который
напрямую применяется к min и max.
Поведение выделения может быть модифицировано через callbacks:
plugins: {
zoom: {
zoom: {
drag: {
enabled: true,
onDragStart: ({ chart }) => {
chart.canvas.style.cursor = 'crosshair';
},
onDrag: ({ chart }) => {
// пользовательская логика во время перетаскивания
},
onDragEnd: ({ chart, range }) => {
// доступ к рассчитанному диапазону
}
}
}
}
}
Эти хуки позволяют интегрировать:
Частый сценарий — одновременное масштабирование нескольких Chart.js экземпляров. Реализация выполняется через общий обработчик:
onDragEnd: ({ chart, range }) => {
charts.forEach(c => {
c.options.scales.x.min = range.x.min;
c.options.scales.x.max = range.x.max;
c.update();
});
}
Такой подход обеспечивает визуальную синхронизацию аналитических панелей.
Drag-зум конфликтует с стандартными интерактивными элементами:
Для устранения конфликтов используется отключение hover во время drag:
onDragStart: ({ chart }) => {
chart.options.plugins.tooltip.enabled = false;
}
После завершения:
onDragEnd: ({ chart }) => {
chart.options.plugins.tooltip.enabled = true;
}
При интенсивных данных drag-to-zoom может вызывать нагрузку из-за постоянных пересчётов шкал.
Основные методы оптимизации:
requestAnimationFrameanimation: false
Также полезно использовать:
normalized: true
для оптимизации обработки больших датасетов.
На сенсорных экранах drag-зум может конфликтовать с прокруткой страницы. Решение заключается в:
touchAction: 'none' на canvaspinch как альтернативного жестаzoom: {
pinch: {
enabled: true
}
}
Часто встречающиеся проблемы:
modeКаждая из этих ошибок приводит либо к отсутствию реакции drag, либо к некорректному отображению данных.
Изменение масштаба в Chart.js не пересоздаёт график, а модифицирует состояние scales:
minmaxsuggestedMinsuggestedMaxПосле drag-зума происходит перерасчёт:
Эта модель позволяет сохранять состояние графика и обеспечивает плавность интерактивных операций.