Evented — базовый механизм событийной модели, на котором строится взаимодействие между компонентами MapLibre GL JS. Практически все ключевые сущности библиотеки (карта, источники данных, слои, стили) наследуют или используют Evented-интерфейс для организации реактивного поведения.
Evented реализует классическую модель publish/subscribe, где объект:
Базовая идея заключается в том, что объект не знает, кто именно обрабатывает событие, а подписчики не знают внутреннюю реализацию источника события.
Метод on регистрирует обработчик события:
map.on('load', () => {
console.log('Карта загружена');
});
Поддерживается регистрация нескольких обработчиков на одно событие, а также подписка на события с пространствами имён.
Пример с пространством имён:
map.on('click.userLayer', 'my-layer', (e) => {
console.log('Клик по слою my-layer');
});
Здесь:
click — тип события,userLayer — namespace,'my-layer' — фильтр по слою.Метод off используется для удаления ранее
зарегистрированных обработчиков:
function handler() {
console.log('click');
}
map.on('click', handler);
map.off('click', handler);
Удаление возможно по:
Особенно важно управлять подписками при динамическом создании интерфейсов, чтобы избежать утечек памяти.
Метод once позволяет зарегистрировать обработчик,
который выполнится только один раз:
map.once('idle', () => {
console.log('карта завершила все рендеры');
});
После срабатывания обработчик автоматически удаляется.
Метод fire используется для генерации пользовательских
событий:
map.fire('custom-event', {
detail: { value: 42 }
});
Событие передаётся всем подписанным слушателям.
Каждое событие передаёт объект event, содержащий
стандартные поля:
type — тип события,target — объект-источник,originalEvent — нативное событие (если есть),Пример обработки:
map.on('click', (e) => {
console.log(e.type);
console.log(e.lngLat);
});
Для событий карты часто доступны географические данные:
lngLat,point,features при
queryRenderedFeatures.Evented является базовым классом, который расширяется множеством компонентов библиотеки:
Это обеспечивает единый интерфейс подписки на события независимо от уровня абстракции.
Пример:
const source = map.getSource('points');
source.on('data', (e) => {
console.log('Данные источника обновились');
});
Обработчики событий выполняются с контекстом, зависящим от реализации, но обычно:
this указывает на объект-источник события,map.on('load', function () {
console.log(this === map); // true
});
Evented поддерживает namespace-модель для управления группами обработчиков:
map.on('click.layerA', handlerA);
map.on('click.layerB', handlerB);
Удаление по namespace:
map.off('click.layerA');
Это позволяет:
Evented хранит обработчики в структуре, аналогичной словарю:
eventType -> [handlers]
eventType.namespace -> [handlers]
Каждый обработчик хранит:
При вызове события происходит:
Evented допускает каскадную генерацию событий:
map.on('data', () => {
map.fire('data-processed');
});
Это используется для построения реактивных цепочек, где одно событие инициирует другое, формируя поток обновлений состояния.
Ошибки внутри обработчиков не должны прерывать цепочку вызовов других слушателей. Поэтому реализация Evented изолирует вызовы:
map.on('click', () => {
throw new Error('test');
});
Другие обработчики click при этом продолжают
выполняться.
Evented широко применяется для построения UI-слоёв поверх карты:
Пример синхронизации:
map.on('move', () => {
const center = map.getCenter();
store.set('center', center);
});
В некоторых реализациях доступен метод очистки всех слушателей:
map.remove();
или внутренние механизмы очистки при уничтожении объекта. Это критически важно для предотвращения утечек памяти при динамическом создании карт.
В TypeScript-окружении Evented позволяет описывать типы событий:
map.on('click', (e: mapboxgl.MapMouseEvent) => {
console.log(e.lngLat);
});
Это улучшает:
Evented выступает связующим слоем между:
Без Evented архитектура библиотеки теряет реактивность и становится набором изолированных компонентов без синхронизации состояния.