Mapbox GL JS предоставляет собственную систему событий поверх
WebGL-карты, включая поддержку сенсорных взаимодействий. На мобильных
устройствах ключевыми становятся touchstart,
touchmove и touchend, которые позволяют
отслеживать начало касания, его перемещение и завершение.
Эти события интегрированы в систему событий карты и регистрируются
через map.on(...), а не через стандартные DOM-обработчики,
что обеспечивает синхронизацию с внутренним состоянием рендеринга и
жестами карты (панорамирование, масштабирование, вращение).
Mapbox GL JS обрабатывает касания через абстракцию событий карты. При этом каждый touch-событие содержит:
type — тип события (touchstart,
touchmove, touchend)target — экземпляр картыpoint — координаты на экране (x, y)lngLat — географические координатыoriginalEvent — исходное DOM TouchEventfeatures — (если используется
queryRenderedFeatures) объекты под курсоромКлючевая особенность заключается в том, что Mapbox интерпретирует касания не как изолированные DOM-события, а как часть интерактивного состояния карты.
Событие touchstart возникает при первом касании экрана.
Оно фиксирует момент, когда пользователь начинает взаимодействие с
картой.
map.on('touchstart', (e) => {
console.log('Touch start');
console.log(e.point);
console.log(e.lngLat);
});
touchmove вызывается многократно при перемещении пальца
по экрану. Это наиболее «нагруженное» событие с точки зрения
производительности, так как может срабатывать десятки раз в секунду.
map.on('touchmove', (e) => {
console.log('Touch move');
console.log(e.point);
console.log(e.lngLat);
});
Из-за высокой частоты вызовов важно минимизировать вычисления внутри обработчика:
map.on('touchmove', (e) => {
requestAnimationFrame(() => {
updateOverlay(e.lngLat);
});
});
Использование requestAnimationFrame позволяет
синхронизировать обновления с рендерингом и снизить нагрузку.
touchmove часто применяется для реализации:
Событие touchend фиксирует момент, когда пользователь
убирает палец с экрана.
map.on('touchend', (e) => {
console.log('Touch end');
});
touchstart → touchmove → touchendMapbox GL JS по умолчанию использует touch-события для реализации встроенных жестов:
При добавлении пользовательских обработчиков важно учитывать, что события могут конкурировать с внутренними механизмами карты.
Для полного контроля над touch-событиями можно отключить интерактивность:
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
interactive: false
});
Либо выборочно отключить поведение:
map.dragPan.disable();
map.scrollZoom.disable();
map.touchZoomRotate.disable();
Фиксирует начальную точку взаимодействия. Используется для инициализации состояния.
Отслеживает непрерывное движение. Основной канал динамических обновлений.
Завершает взаимодействие и фиксирует результат.
На устройствах с поддержкой мультитач каждый палец генерирует отдельные touch-события. Mapbox агрегирует их в единый поток взаимодействия карты.
map.on('touchstart', (e) => {
console.log(e.originalEvent.touches.length);
});
Поле touches позволяет определить количество активных
касаний.
Через e.originalEvent можно получить доступ к нативному
TouchEvent:
map.on('touchmove', (e) => {
const touches = e.originalEvent.touches;
console.log(touches);
});
Это важно при реализации сложных жестов, где требуется низкоуровневый контроль.
Mapbox автоматически преобразует экранные координаты в географические:
e.point — пиксельные координаты относительно контейнера
картыe.lngLat — долгота и широтаmap.on('touchstart', (e) => {
const { lng, lat } = e.lngLat;
console.log(lng, lat);
});
Эта абстракция позволяет работать с геоданными без ручного преобразования проекций.
Типичная логика обработки пользовательского жеста строится как конечный автомат:
touchstart — фиксация начальной точкиtouchmove — обновление текущего состоянияtouchend — финализация действияlet isDrawing = false;
let path = [];
map.on('touchstart', (e) => {
isDrawing = true;
path = [e.lngLat];
});
map.on('touchmove', (e) => {
if (!isDrawing) return;
path.push(e.lngLat);
});
map.on('touchend', () => {
isDrawing = false;
console.log(path);
});
Mapbox GL JS рендерит карту через WebGL, поэтому любые частые
обновления в touchmove могут влиять на:
Оптимизация достигается через:
requestAnimationFrameРазные браузеры по-разному обрабатывают touch-события:
touchmoveMapbox компенсирует эти различия через собственный event layer, однако логика приложения должна учитывать вариативность поведения.
При использовании карты внутри scroll-контейнера возможны конфликты между:
Решение часто включает:
.map-container {
touch-action: none;
}
Это отключает нативную обработку жестов браузером и передаёт управление карте.
Иногда необходимо реагировать только на первичное касание:
map.on('touchstart', (e) => {
if (e.originalEvent.touches.length > 1) return;
console.log('Single touch');
});
Это позволяет разделять жесты одного пальца и мультитач.
Touch-события часто используются совместно с кастомными слоями Mapbox:
map.on('touchend', (e) => {
const features = map.queryRenderedFeatures(e.point);
console.log(features);
});
Такой подход позволяет реализовать интерактивные элементы карты без DOM-оверлеев.