Mapbox GL JS предоставляет событийную модель, основанную на подписке
через map.on, где взаимодействие пользователя с картой
транслируется в высокоуровневые события. Среди наиболее часто
используемых — click, dblclick,
contextmenu, формирующие основу интерактивных веб-карт.
Каждое событие в Mapbox GL JS привязывается к объекту карты и может быть глобальным либо контекстным (привязанным к слою или источнику данных):
map.on('click', (e) => {
console.log(e.lngLat);
});
Объект события содержит ключевые данные:
lngLat — географические координаты точки кликаpoint — экранные координаты (x, y)features — массив объектов (если использовался фильтр
слоя)originalEvent — нативное DOM-событиеДля работы с интерактивными слоями обычно используется фильтрация по слоям:
map.on('click', 'cities-layer', (e) => {
const feature = e.features[0];
console.log(feature.properties);
});
Такой подход активирует обработчик только при клике по конкретному слою.
click является фундаментом пользовательской
интерактивности. Он используется для:
Часто применяется совместно с queryRenderedFeatures,
когда требуется контроль без привязки к событию слоя:
map.on('click', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['cities-layer']
});
if (!features.length) return;
const feature = features[0];
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML(`<strong>${feature.properties.name}</strong>`)
.addTo(map);
});
Метод queryRenderedFeatures позволяет извлекать объекты,
которые визуально присутствуют на экране, что делает обработку точной с
точки зрения отображаемого состояния карты.
Событие dblclick по умолчанию связано с поведением
масштабирования карты. При двойном клике Mapbox GL JS увеличивает
масштаб.
Для полного контроля поведения используется подавление стандартного действия:
map.doubleClickZoom.disable();
После отключения встроенного поведения появляется возможность реализовать собственную логику:
map.on('dblclick', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['cities-layer']
});
if (features.length) {
console.log('Double click feature:', features[0]);
}
});
Важно учитывать, что двойной клик может конфликтовать с пользовательскими сценариями редактирования объектов или быстрых переходов по уровням масштабирования.
Событие contextmenu возникает при правом клике мышью. По
умолчанию браузер отображает системное контекстное меню, которое обычно
требуется подавить:
map.getCanvas().addEventListener('contextmenu', (e) => {
e.preventDefault();
});
Далее Mapbox GL JS позволяет обработать событие как часть карты:
map.on('contextmenu', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['cities-layer']
});
if (!features.length) return;
const feature = features[0];
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML(`
<div>
<div>Объект: ${feature.properties.name}</div>
<div>Тип: ${feature.properties.type}</div>
</div>
`)
.addTo(map);
});
Контекстное меню часто используется для:
В интерактивных приложениях события click,
dblclick и contextmenu часто пересекаются по
времени и области действия. Для корректного поведения используется
управление приоритетами:
map.on('click', handleClick);
map.on('dblclick', handleDoubleClick);
map.on('contextmenu', handleContextMenu);
Дополнительно применяется контроль распространения событий:
map.on('click', (e) => {
if (e.originalEvent.shiftKey) {
e.originalEvent.stopPropagation();
}
});
Поле originalEvent содержит нативное событие DOM, что
позволяет использовать дополнительные модификаторы:
shiftKeyaltKeyctrlKey / metaKeybutton)Пример различения действий:
map.on('click', (e) => {
if (e.originalEvent.altKey) {
console.log('Alt + click режим');
return;
}
console.log('Обычный клик');
});
Это позволяет расширять поведение карты без создания дополнительных UI-элементов.
Mapbox GL JS поддерживает два уровня подписки:
Слой-ориентированные события:
map.on('click', 'cities-layer', (e) => {
console.log(e.features);
});
Глобальные события:
map.on('click', (e) => {
console.log(e.lngLat);
});
События слоя автоматически включают features, тогда как
глобальные требуют явного запроса через
queryRenderedFeatures.
На сенсорных экранах:
click заменяет tapcontextmenu часто эмулируется долгим нажатиемdblclick может конфликтовать с системным зумом
браузераДля мобильных сценариев важно учитывать задержки обработки событий и отсутствие аппаратного правого клика.
map.on('touchend', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['cities-layer']
});
});
Частые вызовы queryRenderedFeatures в
mousemove или touchmove могут создавать
нагрузку. Для click, dblclick,
contextmenu это обычно не критично, но при расширении
логики следует учитывать:
Оптимизированный вариант:
map.on('click', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['cities-layer']
});
if (!features.length) return;
requestAnimationFrame(() => {
updateUI(features[0]);
});
});
При наличии нескольких обработчиков часто требуется предотвращение одновременного срабатывания логики:
map.on('dblclick', (e) => {
e.preventDefault();
});
Также применяется флаговое управление состоянием:
let isEditing = false;
map.on('click', (e) => {
if (isEditing) return;
handleSelection(e);
});
Такая модель используется в редакторах геометрии и GIS-интерфейсах, где разные режимы работы карты исключают друг друга.
События клика часто связываются с отображением всплывающих окон:
map.on('click', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['cities-layer']
});
if (!features.length) return;
const feature = features[0];
new mapboxgl.Popup({ offset: 10 })
.setLngLat(e.lngLat)
.setHTML(`<div>${feature.properties.name}</div>`)
.addTo(map);
});
Контекстное меню может использоваться как расширение popup-системы, создавая альтернативную точку входа для действий над объектом.
При активной трансформации карты (zoom, rotate, pitch) координаты
событий сохраняют точность в lngLat, однако экранные
координаты point зависят от текущей матрицы
отображения.
Это важно при:
map.on('click', (e) => {
const { lngLat, point } = e;
console.log(lngLat, point);
});
Разделение логики географических и экранных координат позволяет корректно строить интерфейсы поверх WebGL-карты.