Система обработки событий мыши в MapLibre GL JS основана на событийной модели браузера и внутреннем механизме диспетчеризации, который связывает DOM-события canvas с географическими объектами карты. Все взаимодействия пользователя с картой транслируются в высокоуровневые события, содержащие координаты, экранные пиксели и информацию о слоях, попавших под курсор.
Внутри MapLibre GL JS мышиные события формируются поверх
HTMLCanvasElement, на котором рендерится карта WebGL. Браузер генерирует
стандартные DOM-события (mousedown, mouseup,
click, mousemove, contextmenu),
которые библиотека перехватывает и преобразует в геопространственные
события.
Каждое событие в API карты содержит:
Такая структура позволяет работать как с низкоуровневыми пользовательскими действиями, так и с объектами слоёв (layers), не обращаясь напрямую к WebGL-сцене.
Основной механизм взаимодействия — метод map.on. Он
позволяет подписываться как на глобальные события карты, так и на
события конкретных слоёв.
Пример привязки события:
map.on('click', (e) => {
console.log(e.lngLat);
});
Поддерживается два основных режима:
Пример событий слоя:
map.on('click', 'cities-layer', (e) => {
console.log(e.features);
});
В этом случае обработчик получает только те геометрические объекты,
которые принадлежат слою cities-layer.
Событие click формируется при быстром нажатии и
отпускании кнопки мыши без существенного перемещения курсора. Оно
является наиболее часто используемым в интерактивных картах.
Основные особенности:
mousedown и mouseupfeatures при перекрытии
слоёвПример обработки:
map.on('click', (e) => {
const { lngLat, point, features } = e;
if (features && features.length) {
console.log(features[0].properties);
}
});
При работе с векторными слоями важно учитывать, что порядок
features зависит от порядка слоёв и их z-index.
События mousedown и mouseup отражают момент
нажатия и отпускания кнопки мыши соответственно.
Используются для:
Пример:
map.on('mousedown', (e) => {
console.log('Нажатие:', e.point);
});
map.on('mouseup', (e) => {
console.log('Отпускание:', e.point);
});
Эти события полезны при построении логики, зависящей от длительности удержания кнопки или изменения положения курсора.
mousemove — одно из наиболее частых событий,
генерируемых при перемещении курсора над картой. Оно используется
для:
Пример:
map.on('mousemove', (e) => {
const { lngLat } = e;
console.log(lngLat.lng, lngLat.lat);
});
При активном использовании этого события важно учитывать
производительность. Часто применяется троттлинг или
requestAnimationFrame, чтобы избежать перегрузки основного
потока.
MapLibre GL JS поддерживает специальные события для слоёв:
mouseentermouseleaveОни работают аналогично DOM-событиям и срабатывают при входе и выходе курсора из области объектов слоя.
Пример:
map.on('mouseenter', 'parks-layer', () => {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'parks-layer', () => {
map.getCanvas().style.cursor = '';
});
Эти события часто используются для улучшения UX, например изменения курсора или отображения подсказок.
Событие contextmenu возникает при вызове контекстного
меню (обычно правой кнопкой мыши). Оно полезно для реализации
пользовательских меню действий на карте.
Пример:
map.on('contextmenu', (e) => {
console.log('Контекстное меню:', e.lngLat);
});
Часто используется совместно с preventDefault для
подавления стандартного поведения браузера.
map.on('contextmenu', (e) => {
e.preventDefault();
});
Одной из ключевых возможностей мышиных событий является доступ к
объектам карты через features. Однако при необходимости
можно выполнять более гибкие запросы:
map.on('click', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['cities-layer']
});
console.log(features);
});
Метод queryRenderedFeatures позволяет:
Это особенно важно при сложных визуализациях с перекрывающимися слоями.
Каждое событие содержит два типа координат:
Различие принципиально:
point используется для UI-логики (оверлеи,
позиционирование)lngLat используется для географических операцийПример преобразования:
map.on('click', (e) => {
const screen = e.point;
const geo = e.lngLat;
console.log(screen, geo);
});
Мышиные события учитывают трансформации карты:
Это означает, что point всегда соответствует текущему
состоянию canvas, а lngLat пересчитывается в соответствии с
матрицей трансформации камеры.
При резких изменениях камеры события могут временно агрегироваться для оптимизации производительности.
При одновременной работе нескольких слоёв события обрабатываются по следующему принципу:
passive)Это важно при проектировании интерактивных карт, где несколько объектов перекрывают друг друга.
Свойство originalEvent позволяет получить доступ к
исходному DOM-событию:
map.on('click', (e) => {
console.log(e.originalEvent.button);
});
Это используется для:
Shift, Ctrl)Пример проверки модификаторов:
map.on('click', (e) => {
if (e.originalEvent.shiftKey) {
console.log('Shift + клик');
}
});
Хотя MapLibre GL JS не предоставляет отдельного drag API для пользовательских объектов, оно легко реализуется через комбинацию событий:
mousedownmousemovemouseupПример логики:
let isDragging = false;
map.on('mousedown', (e) => {
isDragging = true;
});
map.on('mousemove', (e) => {
if (!isDragging) return;
console.log('Перетаскивание:', e.lngLat);
});
map.on('mouseup', () => {
isDragging = false;
});
Такая модель используется для рисования, редактирования геометрии и интерактивных инструментов.
Событие mousemove может генерироваться десятки раз в
секунду. При сложной логике это приводит к деградации
производительности.
Типичные подходы оптимизации:
requestAnimationFramequeryRenderedFeaturesПример с requestAnimationFrame:
let scheduled = false;
map.on('mousemove', (e) => {
if (scheduled) return;
scheduled = true;
requestAnimationFrame(() => {
console.log(e.lngLat);
scheduled = false;
});
});
Мышиные события тесно связаны со стилями карты. Каждый слой может иметь:
Это напрямую влияет на то, какие features будут
возвращены при событии. Даже при одинаковых координатах результат может
отличаться в зависимости от текущего состояния стиля карты.