Событийная система построена на интерфейсе Evented,
который реализует подписку, удаление подписки и эмиссию событий. Любой
экземпляр карты является источником событий: map.on,
map.off, map.once, а также низкоуровневым
механизмом map.fire, через который можно программно
инициировать события.
События в Mapbox GL JS делятся на несколько категорий:
load, idle,
render)click,
mousemove, drag)data,
sourcedata)styledata, sourcedata)error, remove)Симуляция событий опирается на возможность вручную генерировать эти сигналы без участия реального ввода пользователя или рендера браузера.
fire и внутренний цикл событийВнутри Mapbox GL JS каждый объект Map наследует
метод:
map.fire(type, eventData);
Этот метод напрямую вызывает обработчики, зарегистрированные через
map.on(type, handler).
Базовая структура вызова:
map.on('click', (e) => {
console.log(e.lngLat);
});
map.fire('click', {
lngLat: { lng: 30.5, lat: 50.4 },
point: { x: 120, y: 80 },
originalEvent: null
});
С точки зрения системы, fire не отличает синтетическое
событие от реального, если передана корректная структура объекта.
Для корректной симуляции важно соблюдать формат события, который ожидает обработчик.
Типичное событие click содержит:
type — тип событияtarget — экземпляр картыlngLat — географические координатыpoint — координаты пикселяoriginalEvent — DOM-объект (может быть
null при симуляции)features — (опционально) найденные объекты слояПример полного синтетического события:
map.fire('click', {
type: 'click',
target: map,
lngLat: { lng: 37.6173, lat: 55.7558 },
point: { x: 400, y: 300 },
originalEvent: null,
features: []
});
Событие click чаще всего используется для взаимодействия
с объектами слоя.
Симуляция включает два уровня:
const lngLat = { lng: 12.4924, lat: 41.8902 };
const point = map.project(lngLat);
const features = map.queryRenderedFeatures(point, {
layers: ['pois-layer']
});
map.fire('click', {
lngLat,
point,
features,
originalEvent: null
});
Такой подход позволяет воспроизводить поведение интерфейса без реального клика мыши.
queryRenderedFeaturesВнутри Mapbox GL JS обработчики кликов часто используют:
map.queryRenderedFeatures(point, options);
При симуляции событий важно заранее вычислить результат этого запроса, иначе логика приложения может вести себя непредсказуемо.
Типовой паттерн:
firefunction simulateFeatureClick(map, lngLat, layerId) {
const point = map.project(lngLat);
const features = map.queryRenderedFeatures(point, {
layers: [layerId]
});
map.fire('click', {
lngLat,
point,
features,
originalEvent: null
});
}
Событие mousemove используется для интерактивного
подсвета объектов.
map.on('mousemove', 'cities-layer', (e) => {
map.getCanvas().style.cursor = 'pointer';
});
Симуляция:
const lngLat = { lng: 2.3522, lat: 48.8566 };
const point = map.project(lngLat);
const features = map.queryRenderedFeatures(point, {
layers: ['cities-layer']
});
map.fire('mousemove', {
lngLat,
point,
features,
originalEvent: null
});
Дополнительно может симулироваться событие mouseleave,
если требуется имитация ухода курсора:
map.fire('mouseleave', {
lngLat,
point,
features: [],
originalEvent: null
});
События перетаскивания состоят из последовательности:
mousedownmousemovemouseupСимуляция строится как цепочка вызовов fire.
map.fire('mousedown', {
lngLat: start,
point: map.project(start),
originalEvent: null
});
map.fire('mousemove', {
lngLat: mid,
point: map.project(mid),
originalEvent: null
});
map.fire('mouseup', {
lngLat: end,
point: map.project(end),
originalEvent: null
});
Такая модель используется для тестирования перемещения карты и кастомных жестов.
Слои в Mapbox GL JS часто зависят от состояния карты и взаимодействий.
Для проверки логики можно вручную генерировать события, связанные с конкретными слоями:
map.fire('click', {
lngLat: { lng: -74.006, lat: 40.7128 },
point: { x: 200, y: 150 },
features: [
{
type: 'Feature',
properties: { id: 1, name: 'Test' },
geometry: {
type: 'Point',
coordinates: [-74.006, 40.7128]
},
layer: { id: 'cities-layer' }
}
],
originalEvent: null
});
Это позволяет обходить реальные вычисления рендера и напрямую тестировать обработчики.
setFeatureState при симуляцииЧасто события используются вместе с динамическим состоянием объектов:
map.setFeatureState(
{ source: 'cities', id: 1 },
{ hover: true }
);
При симуляции событий логика может включать:
firemouseleavemap.setFeatureState({ source: 'cities', id: 1 }, { hover: true });
map.fire('mousemove', {
lngLat,
point,
features,
originalEvent: null
});
map.setFeatureState({ source: 'cities', id: 1 }, { hover: false });
fire для событий загрузки и состояния картыНекоторые системные события также могут быть симулированы:
map.fire('load');
map.fire('idle');
map.fire('render');
Однако такие вызовы влияют только на обработчики, но не запускают внутренние процессы рендеринга, поэтому используются преимущественно в тестовых окружениях.
Система событий Mapbox GL JS имеет внутренние зависимости от WebGL и реального состояния рендера:
fire не изменяет состояние картыСобытие существует только на уровне логики подписчиков.
При работе с синтетическими событиями критически важно согласование:
lngLat (географические координаты)point (экранные координаты)const lngLat = { lng: 139.6917, lat: 35.6895 };
const point = map.project(lngLat);
Ошибка в этой паре приводит к рассинхронизации логики:
featuresСимуляция редко ограничивается одиночным событием. Типовой сценарий включает:
function simulateInteraction(map, lngLat, layerId) {
const point = map.project(lngLat);
const features = map.queryRenderedFeatures(point, {
layers: [layerId]
});
map.fire('mousemove', { lngLat, point, features, originalEvent: null });
map.setFeatureState(
{ source: layerId, id: features[0]?.id },
{ active: true }
);
map.fire('click', { lngLat, point, features, originalEvent: null });
}
Такая модель отражает реальное поведение интерфейса без участия пользователя и браузерных событий.