Событийная модель Google Maps JavaScript API построена поверх
собственного механизма google.maps.event, который
обеспечивает регистрацию, удаление и последовательное срабатывание
обработчиков. Несмотря на внешнюю схожесть с DOM-событиями, внутренняя
логика существенно отличается: отсутствует стандартное всплытие по
дереву DOM, а порядок вызовов определяется жизненным циклом объектов
карты, асинхронной загрузкой тайлов и внутренними состояниями
MVCObject.
Каждый объект API, наследующий MVCObject, поддерживает
событийную систему:
addListeneraddListenerOnceremoveListenertriggerКлючевой момент заключается в том, что обработчики хранятся в порядке регистрации и вызываются строго последовательно. Это формирует предсказуемый линейный порядок исполнения внутри одного события.
Однако глобальный порядок событий определяется не только регистрацией, но и фазами жизненного цикла карты.
Создание экземпляра карты через new google.maps.Map()
запускает цепочку внутренних операций:
DivНа этом этапе события начинают генерироваться до того, как карта становится полностью интерактивной.
Типичный порядок ранних событий:
bounds_changed (может сработать несколько раз
подряд)center_changedzoom_changedprojection_changed (внутреннее, редко используемое
напрямую)tilesloaded (ключевой маркер готовности тайлов)idle (финальная точка стабилизации состояния)Важно, что bounds_changed, center_changed и
zoom_changed могут вызываться многократно и асинхронно в
рамках одной инициализации.
После завершения загрузки тайлов формируется устойчивое состояние карты. Именно здесь возникает важная последовательность:
tilesloadedidleСобытие idle является индикатором того, что карта
завершила все текущие вычисления и не находится в процессе анимации или
загрузки тайлов. Оно часто используется как точка безопасного выполнения
логики, зависящей от полностью готового состояния карты.
При взаимодействии пользователя или программных вызовах
(setCenter, setZoom, panTo)
формируется последовательность событий, зависящая от типа изменения.
При вызове изменения центра:
center_changed срабатывает многократно во время
анимацииidleПорядок:
center_changed (серия вызовов)bounds_changed (если изменяются границы)idleПри изменении zoom:
zoom_changed может быть вызван несколько раз при
анимацииПорядок:
zoom_changedbounds_changedtilesloaded (при загрузке новых тайлов)idleИнтерактивные события имеют собственный порядок, который зависит от слоя карты и приоритета объектов.
При клике на пустую область карты:
click на объекте Mapdblclick (если не перехвачен zoom
behavior)mousemove / mouseover (если курсор
движется дальше)Особенность заключается в том, что событие click карты
срабатывает только если клик не был перехвачен overlay-объектами
(маркер, полилиния, полигон).
Маркер имеет более высокий приоритет, чем карта. Поэтому порядок следующий:
mousedown на маркереmouseupclick на маркереclick картыbounds_changed (если изменился центр через UI)idle (при завершении анимации)Если на маркере используется анимация (BOUNCE или
DROP), дополнительно могут возникать асинхронные события,
не влияющие на базовый порядок клика.
Перетаскивание (drag) формирует отдельный цикл
событий:
dragstartcenter_changeddragdragendidleЗдесь ключевое отличие заключается в том, что
center_changed вызывается значительно чаще остальных
событий, так как привязан к непрерывному обновлению координат.
События Google Maps API не синхронизированы с DOM Event Loop напрямую. Многие операции выполняются через внутренние очереди обновлений:
idle откладываются до завершения всех
визуальных измененийИз-за этого возможна ситуация, когда логически «последнее» событие
(zoom_changed) фактически происходит раньше завершения
загрузки тайлов, а итоговое состояние фиксируется только через
idle.
Объекты overlay (Marker, Polyline, Polygon, Circle) имеют собственные события, но они не участвуют в DOM-иерархии карты.
Порядок при наложении клика:
Таким образом формируется приоритетная модель:
При наличии нескольких перекрывающихся объектов верхний визуальный слой получает событие первым.
Хотя модель не является DOM-подобной, существует механизм подавления дальнейшей обработки:
event.stop() (или event.stopPropagation()
в зависимости от типа события)Использование приводит к остановке передачи события к нижележащим слоям карты, но не влияет на уже зарегистрированные обработчики на том же объекте.
Важно: порядок внутри одного объекта сохраняется даже при использовании stop-механизмов.
Добавление обработчиков через addListener формирует
очередь в порядке регистрации:
Удаление через removeListener исключает конкретный
обработчик, не влияя на порядок остальных.
При массовой регистрации важно учитывать, что порядок исполнения остаётся неизменным до момента удаления.
Вызовы API напрямую влияют на последовательность событий:
setCenter() вызывает center_changed и
потенциально idlesetZoom() вызывает zoom_changed и
перезагрузку тайловpanTo() инициирует серию промежуточных событий
движенияПрограммные изменения и пользовательские действия используют один и тот же поток событий, поэтому возможны пересечения:
setZoomВ таких случаях порядок определяется внутренним event loop API, где приоритет отдается анимационным состояниям карты.
Главная характеристика событийной системы заключается в разделении на три уровня:
click,
dragstart)center_changed,
zoom_changed)idle)Именно idle выступает как точка консолидации всех
предыдущих изменений, объединяя разрозненные события в завершённое
состояние карты.