Порядок срабатывания событий

Событийная модель Google Maps JavaScript API построена поверх собственного механизма google.maps.event, который обеспечивает регистрацию, удаление и последовательное срабатывание обработчиков. Несмотря на внешнюю схожесть с DOM-событиями, внутренняя логика существенно отличается: отсутствует стандартное всплытие по дереву DOM, а порядок вызовов определяется жизненным циклом объектов карты, асинхронной загрузкой тайлов и внутренними состояниями MVCObject.

Каждый объект API, наследующий MVCObject, поддерживает событийную систему:

  • регистрация: addListener
  • одноразовое выполнение: addListenerOnce
  • удаление: removeListener
  • ручной вызов: trigger

Ключевой момент заключается в том, что обработчики хранятся в порядке регистрации и вызываются строго последовательно. Это формирует предсказуемый линейный порядок исполнения внутри одного события.

Однако глобальный порядок событий определяется не только регистрацией, но и фазами жизненного цикла карты.

Этапы инициализации карты и ранние события

Создание экземпляра карты через new google.maps.Map() запускает цепочку внутренних операций:

  1. создание DOM-контейнера и привязка Div
  2. инициализация проекции и контролов
  3. запуск загрузки тайлов
  4. установка начального состояния центра и масштаба

На этом этапе события начинают генерироваться до того, как карта становится полностью интерактивной.

Типичный порядок ранних событий:

  • bounds_changed (может сработать несколько раз подряд)
  • center_changed
  • zoom_changed
  • projection_changed (внутреннее, редко используемое напрямую)
  • tilesloaded (ключевой маркер готовности тайлов)
  • idle (финальная точка стабилизации состояния)

Важно, что bounds_changed, center_changed и zoom_changed могут вызываться многократно и асинхронно в рамках одной инициализации.

Порядок событий при полной загрузке карты

После завершения загрузки тайлов формируется устойчивое состояние карты. Именно здесь возникает важная последовательность:

  1. tilesloaded
  2. серия внутренних перерасчётов границ
  3. idle

Событие idle является индикатором того, что карта завершила все текущие вычисления и не находится в процессе анимации или загрузки тайлов. Оно часто используется как точка безопасного выполнения логики, зависящей от полностью готового состояния карты.

События изменения состояния карты

При взаимодействии пользователя или программных вызовах (setCenter, setZoom, panTo) формируется последовательность событий, зависящая от типа изменения.

Изменение центра

При вызове изменения центра:

  • center_changed срабатывает многократно во время анимации
  • после завершения движения возникает idle

Порядок:

  1. center_changed (серия вызовов)
  2. bounds_changed (если изменяются границы)
  3. idle

Изменение масштаба

При изменении zoom:

  • zoom_changed может быть вызван несколько раз при анимации
  • пересчитываются тайлы
  • обновляются границы

Порядок:

  1. zoom_changed
  2. bounds_changed
  3. tilesloaded (при загрузке новых тайлов)
  4. idle

События взаимодействия с пользователем

Интерактивные события имеют собственный порядок, который зависит от слоя карты и приоритета объектов.

Клик по карте

При клике на пустую область карты:

  1. обработка событий слоя карты
  2. click на объекте Map
  3. возможный dblclick (если не перехвачен zoom behavior)
  4. mousemove / mouseover (если курсор движется дальше)

Особенность заключается в том, что событие click карты срабатывает только если клик не был перехвачен overlay-объектами (маркер, полилиния, полигон).

Клик по маркеру

Маркер имеет более высокий приоритет, чем карта. Поэтому порядок следующий:

  1. mousedown на маркере
  2. mouseup
  3. click на маркере
  4. подавление click карты
  5. bounds_changed (если изменился центр через UI)
  6. idle (при завершении анимации)

Если на маркере используется анимация (BOUNCE или DROP), дополнительно могут возникать асинхронные события, не влияющие на базовый порядок клика.

События перетаскивания карты

Перетаскивание (drag) формирует отдельный цикл событий:

  1. dragstart
  2. непрерывная серия center_changed
  3. drag
  4. dragend
  5. idle

Здесь ключевое отличие заключается в том, что center_changed вызывается значительно чаще остальных событий, так как привязан к непрерывному обновлению координат.

Асинхронность и микрозадержки

События Google Maps API не синхронизированы с DOM Event Loop напрямую. Многие операции выполняются через внутренние очереди обновлений:

  • перерасчёт тайлов выполняется асинхронно
  • события idle откладываются до завершения всех визуальных изменений
  • анимации используют промежуточные кадры, не всегда доступные через события API

Из-за этого возможна ситуация, когда логически «последнее» событие (zoom_changed) фактически происходит раньше завершения загрузки тайлов, а итоговое состояние фиксируется только через idle.

Взаимодействие событий объектов и карты

Объекты overlay (Marker, Polyline, Polygon, Circle) имеют собственные события, но они не участвуют в DOM-иерархии карты.

Порядок при наложении клика:

  1. проверка попадания в overlay-объекты сверху вниз
  2. если объект найден — его события
  3. если объект не найден — события карты

Таким образом формируется приоритетная модель:

  • Marker → Polyline → Polygon → Map

При наличии нескольких перекрывающихся объектов верхний визуальный слой получает событие первым.

Предотвращение распространения событий

Хотя модель не является DOM-подобной, существует механизм подавления дальнейшей обработки:

  • event.stop() (или event.stopPropagation() в зависимости от типа события)

Использование приводит к остановке передачи события к нижележащим слоям карты, но не влияет на уже зарегистрированные обработчики на том же объекте.

Важно: порядок внутри одного объекта сохраняется даже при использовании stop-механизмов.

Порядок удаления и добавления слушателей

Добавление обработчиков через addListener формирует очередь в порядке регистрации:

  1. первый добавленный обработчик
  2. второй
  3. третий

Удаление через removeListener исключает конкретный обработчик, не влияя на порядок остальных.

При массовой регистрации важно учитывать, что порядок исполнения остаётся неизменным до момента удаления.

Влияние программных вызовов на порядок событий

Вызовы API напрямую влияют на последовательность событий:

  • setCenter() вызывает center_changed и потенциально idle
  • setZoom() вызывает zoom_changed и перезагрузку тайлов
  • panTo() инициирует серию промежуточных событий движения

Программные изменения и пользовательские действия используют один и тот же поток событий, поэтому возможны пересечения:

  • пользователь начал drag
  • код вызвал setZoom
  • оба процесса формируют единый общий поток событий

В таких случаях порядок определяется внутренним event loop API, где приоритет отдается анимационным состояниям карты.

Ключевая особенность порядка событий

Главная характеристика событийной системы заключается в разделении на три уровня:

  • мгновенные синхронные события (click, dragstart)
  • событийные серии во время анимации (center_changed, zoom_changed)
  • финализирующие события стабилизации (idle)

Именно idle выступает как точка консолидации всех предыдущих изменений, объединяя разрозненные события в завершённое состояние карты.