Уведомления об изменениях

В Mapbox GL JS вся модель взаимодействия с картой построена вокруг событийной системы. Любое изменение состояния карты — от загрузки стиля до смещения камеры или обновления источника данных — транслируется через поток уведомлений, на которые можно подписываться и реагировать в реальном времени.

Событийная модель основана на паттерне Observer. Карта выступает в роли источника событий, а обработчики подписываются на конкретные типы изменений.

Основной объект — экземпляр map, создаваемый через new mapboxgl.Map(...). Он генерирует события, отражающие:

  • жизненный цикл карты;
  • изменения камеры;
  • обновления источников данных;
  • рендеринг и перерисовку;
  • ошибки и предупреждения.

Каждое событие можно перехватывать через метод:

map.on('event-name', handler);

и удалять через:

map.off('event-name', handler);

События жизненного цикла карты

Инициализация карты проходит несколько фаз, каждая из которых сопровождается уведомлениями.

load

Срабатывает, когда стиль карты и все ресурсы загружены.

map.on('load', () => {
    // безопасно добавлять слои и источники
});

На этом этапе можно:

  • добавлять источники данных (addSource);
  • создавать слои (addLayer);
  • модифицировать стиль.

idle

Сигнализирует о завершении всех рендеринговых операций и отсутствии активных загрузок.

map.on('idle', () => {
    console.log('Карта полностью стабилизировалась');
});

Это событие полезно для определения момента, когда карта перестала «дергаться».


Изменения камеры и навигации

Камера карты — центральный объект визуального состояния. Любое изменение позиции вызывает серию событий.

move

Срабатывает при любом изменении положения карты:

  • pan (перемещение);
  • zoom;
  • rotate;
  • pitch.
map.on('move', () => {
    console.log(map.getCenter(), map.getZoom());
});

moveend

Фиксирует завершение движения камеры.

map.on('moveend', () => {
    console.log('Перемещение завершено');
});

zoomstart / zoomend

Позволяют отслеживать начало и конец масштабирования.

map.on('zoomstart', () => {
    console.log('Начало зума');
});

map.on('zoomend', () => {
    console.log('Конец зума');
});

rotate / pitch

Дополнительно можно отслеживать наклон и вращение карты:

map.on('rotate', () => {});
map.on('pitch', () => {});

События рендеринга

Внутренний рендеринг WebGL генерирует отдельный поток уведомлений.

render

Срабатывает каждый раз при отрисовке кадра.

map.on('render', () => {
    // вызывается очень часто
});

Используется для:

  • анимаций;
  • синхронизации внешних визуальных элементов;
  • профилирования.

data

Сигнализирует об изменении данных, влияющих на визуализацию.

map.on('data', (e) => {
    console.log(e.dataType, e.isSourceLoaded);
});

Уведомления об источниках данных

Источники (sources) в Mapbox GL JS могут загружаться асинхронно и обновляться динамически.

sourcedata

Отслеживает изменения конкретных источников:

map.on('sourcedata', (e) => {
    console.log(e.sourceId, e.isSourceLoaded);
});

Это событие полезно при работе с:

  • vector tiles;
  • GeoJSON, обновляемым в реальном времени;
  • тайловыми сервисами.

data события по источникам

map.on('data', (e) => {
    if (e.sourceId === 'my-source') {
        console.log('Обновление конкретного источника');
    }
});

События слоёв и стиля

Изменения визуальной структуры карты также генерируют уведомления.

styledata

Срабатывает при изменении стиля карты:

map.on('styledata', () => {
    console.log('Стиль обновлён');
});

Используется при:

  • динамической смене темы;
  • подгрузке новых стилей;
  • частичном обновлении слоёв.

Обработка ошибок и диагностика

error

Центральное событие для отладки.

map.on('error', (e) => {
    console.error(e.error);
});

Оно может сигнализировать о:

  • проблемах загрузки тайлов;
  • ошибках стиля;
  • сетевых сбоях;
  • некорректных источниках.

Принцип «событие как поток состояния»

Событийная модель Mapbox GL JS не просто уведомляет об изменениях, а формирует поток состояния карты. Это позволяет строить реактивные системы:

  • синхронизацию UI с картой;
  • внешние панели фильтров;
  • динамическую загрузку данных;
  • интеграцию с аналитикой.

Пример синхронизации состояния:

map.on('move', () => {
    const state = {
        center: map.getCenter(),
        zoom: map.getZoom(),
        bearing: map.getBearing(),
        pitch: map.getPitch()
    };

    updateSidebar(state);
});

Частота событий и оптимизация

Некоторые события вызываются с высокой частотой (move, render). Их использование требует оптимизации.

Типичные подходы:

  • throttle для ограничения частоты вызовов;
  • debounce для реакции после завершения движения;
  • перенос тяжёлых вычислений в moveend или idle.

Пример оптимизации:

let timeout;

map.on('move', () => {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
        console.log('Стабильное состояние карты');
    }, 200);
});

Контекст события и объект Event

Каждое событие передаёт объект event, содержащий дополнительную информацию:

  • type — тип события;
  • target — экземпляр карты;
  • sourceId — идентификатор источника (для data-событий);
  • tile — информация о тайле;
  • isSourceLoaded — статус загрузки.
map.on('sourcedata', (e) => {
    if (e.isSourceLoaded) {
        console.log(`Источник ${e.sourceId} загружен`);
    }
});

Механизм подписки и отписки

Корректное управление подписками критично при динамических интерфейсах.

function onMove() {
    console.log('движение');
}

map.on('move', onMove);

// позже
map.off('move', onMove);

При удалении карты:

map.remove();

все подписки уничтожаются автоматически, предотвращая утечки памяти.