Мобильное взаимодействие в MapLibre GL JS основано на системе сенсорных событий, которые интерпретируются картой как высокоуровневые жесты: перемещение, масштабирование, вращение и наклон. В отличие от классических DOM touch-событий, библиотека не предоставляет прямой модели «сырых касаний» как основной способ работы. Вместо этого используется абстракция, связывающая сенсорный ввод с состоянием камеры карты.
Внутри MapLibre GL JS сенсорные события проходят несколько уровней обработки:
touchstart,
touchmove, touchend,
touchcancel)move,
zoom, rotate, touchstart и
др.)Ключевая особенность заключается в том, что MapLibre ориентируется не на отдельные касания, а на их комбинации. Например, два пальца интерпретируются как жест масштабирования и вращения, а один палец — как перемещение карты.
MapLibre GL JS предоставляет набор событий, связанных с сенсорным вводом:
touchstart — начало касанияtouchmove — движение пальцев по экрануtouchend — завершение касанияtouchcancel — прерывание касания системойПодписка на события осуществляется через стандартный API карты:
map.on('touchstart', (e) => {
console.log('Начало касания', e);
});
map.on('touchmove', (e) => {
console.log('Движение касания', e);
});
map.on('touchend', (e) => {
console.log('Конец касания', e);
});
Каждое событие содержит объект, включающий информацию о состоянии карты и исходных DOM-событиях.
Событие MapLibre, связанное с касаниями, содержит следующие важные поля:
type — тип событияtarget — экземпляр картыpoint — координаты в пикселях относительно canvaslngLat — географические координаты точки касанияoriginalEvent — исходное DOM touch-событиеtouches — массив текущих активных касанийПример анализа касания:
map.on('touchstart', (e) => {
const firstTouch = e.originalEvent.touches[0];
console.log('Pixel:', e.point);
console.log('Coordinates:', e.lngLat);
console.log('Screen touch:', firstTouch.clientX, firstTouch.clientY);
});
lngLat вычисляется автоматически, что позволяет работать
с геоданными без дополнительной проекции координат.
MapLibre GL JS интерпретирует сенсорный ввод как набор жестов, управляемых внутренними обработчиками:
Эти режимы контролируются через map.touchZoomRotate и
общие настройки взаимодействия:
map.touchZoomRotate.disable(); // отключение pinch/rotate
map.touchZoomRotate.enable(); // включение обратно
Также возможно полное управление интерактивностью:
map.dragPan.disable();
map.scrollZoom.disable();
map.boxZoom.disable();
map.keyboard.disable();
Хотя браузеры поддерживают Pointer Events, MapLibre GL JS исторически использует абстракцию поверх touch-событий. Это означает:
При этом разработчик может комбинировать DOM pointer events с API карты:
map.getCanvas().addEventListener('pointerdown', (e) => {
console.log('Pointer event', e.pointerType);
});
Однако такие обработчики не влияют на внутреннюю механику жестов,
если явно не вмешиваться в preventDefault.
Сенсорные события в браузерах часто сопровождаются стандартными
действиями: прокрутка страницы, масштабирование viewport, жесты OS.
MapLibre предотвращает эти эффекты через preventDefault
внутри своих обработчиков.
При создании кастомных обработчиков важно учитывать:
map.getCanvas().addEventListener('touchmove', (e) => {
e.preventDefault();
});
Без этого мобильные браузеры могут интерпретировать жесты как скролл страницы, что ломает взаимодействие с картой.
Особенно критично это для:
MapLibre отслеживает массив активных касаний и строит из них жесты:
Пример анализа количества касаний:
map.on('touchmove', (e) => {
const touches = e.originalEvent.touches.length;
if (touches === 1) {
console.log('Перемещение карты');
}
if (touches === 2) {
console.log('Масштабирование/вращение');
}
});
Каждое касание в MapLibre проходит преобразование:
Это позволяет напрямую использовать данные жестов для геопривязанных операций:
map.on('touchend', (e) => {
const coords = e.lngLat;
map.addSource('touch-point', {
type: 'geojson',
data: {
type: 'Point',
coordinates: [coords.lng, coords.lat]
}
});
});
При одновременном выполнении жестов система применяет приоритеты:
Конфигурация позволяет управлять этими приоритетами:
const map = new maplibregl.Map({
container: 'map',
interactive: true,
dragRotate: false,
touchPitch: false
});
Отключение dragRotate снижает вероятность конфликтов на
мобильных устройствах.
Сенсорные события являются высокочастотными, особенно
touchmove. В MapLibre они обрабатываются в тесной связке с
render loop WebGL.
Критически важно:
touchmoveОптимизированный подход:
let lastLngLat = null;
map.on('touchmove', (e) => {
lastLngLat = e.lngLat;
});
map.on('touchend', () => {
console.log('Final position', lastLngLat);
});
Несмотря на встроенную систему жестов, можно реализовывать
собственные взаимодействия, опираясь на touchstart и
touchmove.
Пример определения свайпа:
let startX, startY;
map.on('touchstart', (e) => {
const t = e.originalEvent.touches[0];
startX = t.clientX;
startY = t.clientY;
});
map.on('touchend', (e) => {
const t = e.originalEvent.changedTouches[0];
const dx = t.clientX - startX;
const dy = t.clientY - startY;
if (Math.abs(dx) > 50 && Math.abs(dx) > Math.abs(dy)) {
console.log('Swipe detected');
}
});
Такие решения требуют осторожности, поскольку могут конфликтовать с встроенными жестами карты.
Поведение touch-событий сильно зависит от платформы:
click после
touchendMapLibre учитывает эти особенности через унифицированный слой обработки событий.
Каждое сенсорное взаимодействие напрямую изменяет камеру карты:
center — смещение карты при panzoom — масштаб при pinchbearing — угол поворотаpitch — наклонПример отслеживания изменений:
map.on('move', () => {
const center = map.getCenter();
const zoom = map.getZoom();
const bearing = map.getBearing();
console.log(center, zoom, bearing);
});
Touch-события выступают триггером, а move — результатом
трансформации камеры.
Все касания происходят поверх WebGL canvas, который MapLibre создаёт внутри контейнера карты. Для доступа к низкоуровневым событиям используется:
const canvas = map.getCanvas();
canvas.addEventListener('touchstart', (e) => {
console.log('Canvas touch');
});
Однако прямое взаимодействие с canvas требует осторожности, так как может нарушить внутреннюю логику жестов.
Touch-система MapLibre проектировалась как расширяемая. Через комбинацию:
map.on('touch*')map.dragPanmap.touchZoomRotateможно построить альтернативные модели взаимодействия, включая:
Каждый из этих режимов фактически переопределяет стандартную интерпретацию касаний, сохраняя при этом базовую систему координат и рендеринга.