Система событий Google Maps

В Google Maps JavaScript API используется событийно-ориентированная модель взаимодействия, основанная на регистрации обработчиков и их последующем вызове при изменении состояния объектов карты. Почти все интерактивные элементы карты — сама карта, маркеры, полигоны, линии, информационные окна — генерируют события, позволяя строить сложную логику без постоянного опроса состояния.

События делятся на две ключевые категории:

  • DOM-события (например, клики по контейнеру карты)
  • Map Events — события, генерируемые объектами API (карта, маркеры, геометрия)
  • UI Events — взаимодействия с элементами управления
  • State Events — изменения состояния объектов (центр карты, масштаб, позиция маркера)

Основной механизм подписки реализован через пространство имён google.maps.event.


Регистрация и удаление обработчиков

Базовый способ работы с событиями — функция addListener.

const map = new google.maps.Map(document.getElementById("map"), {
  center: { lat: 50.45, lng: 30.52 },
  zoom: 10
});

const listener = google.maps.event.addListener(map, "center_changed", () => {
  console.log("Центр карты изменился:", map.getCenter().toString());
});

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

google.maps.event.removeListener(listener);

Удаление слушателей критично для предотвращения утечек памяти, особенно в SPA-приложениях, где карта может создаваться и уничтожаться многократно.


Одноразовые события

Для сценариев, где обработчик должен сработать только один раз, используется addListenerOnce.

google.maps.event.addListenerOnce(map, "tilesloaded", () => {
  console.log("Плитки карты загружены");
});

После первого вызова обработчик автоматически удаляется.


Основные события объекта Map

Google Maps JavaScript API предоставляет богатый набор событий, связанных с состоянием карты:

Изменение позиции и масштаба

  • center_changed — изменение центра карты
  • zoom_changed — изменение уровня масштаба
  • bounds_changed — изменение видимой области
map.addListener("zoom_changed", () => {
  console.log("Zoom:", map.getZoom());
});

Часто эти события срабатывают многократно при анимации, поэтому их использование требует оптимизации (например, debounce).


События завершения взаимодействия

  • idle — карта завершила все анимации и загрузку
  • tilesloaded — загружены тайлы карты
map.addListener("idle", () => {
  console.log("Карта стабилизировалась");
});

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


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

  • click
  • dblclick
  • rightclick
  • mousemove
  • dragstart, drag, dragend
map.addListener("click", (event) => {
  console.log("Клик по карте:", event.latLng.toString());
});

Объект event обычно содержит:

  • latLng — координаты точки
  • pixel — экранные координаты (в некоторых событиях)
  • дополнительные свойства в зависимости от типа события

События маркеров (Marker Events)

Маркер является одним из наиболее часто используемых объектов API и поддерживает собственные события:

  • click
  • dragstart
  • drag
  • dragend
  • mouseover
  • mouseout
const marker = new google.maps.Marker({
  position: { lat: 50.45, lng: 30.52 },
  map,
  draggable: true
});

marker.addListener("dragend", (event) => {
  console.log("Новая позиция:", event.latLng.toString());
});

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


События геометрических объектов

Объекты типа Polyline, Polygon, Rectangle, Circle также поддерживают события:

  • click
  • mousemove
  • rightclick
const polygon = new google.maps.Polygon({
  paths: [
    { lat: 50.1, lng: 30.1 },
    { lat: 50.2, lng: 30.2 },
    { lat: 50.3, lng: 30.1 }
  ],
  map
});

polygon.addListener("click", (event) => {
  console.log("Клик по полигону:", event.latLng.toString());
});

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


События InfoWindow

Информационные окна поддерживают ограниченный набор событий:

  • closeclick
  • domready
const infoWindow = new google.maps.InfoWindow({
  content: "<div>Информация</div>"
});

infoWindow.addListener("domready", () => {
  console.log("InfoWindow готов к работе");
});

Событие domready особенно важно для манипуляции DOM внутри окна.


Система приоритетов и всплытие событий

В Google Maps JavaScript API события не всегда всплывают в привычном DOM-смысле. Например:

  • клик по маркеру не обязательно вызывает клик карты
  • события геометрии не всегда транслируются на уровень карты
  • UI-события отделены от map events

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


Пространство имён google.maps.event

Старый, но до сих пор активно используемый механизм:

Основные методы

  • addListener
  • addListenerOnce
  • removeListener
  • clearInstanceListeners
  • trigger
google.maps.event.trigger(map, "resize");

Метод trigger позволяет искусственно генерировать события, что используется при интеграции с внешними UI-компонентами.


Пользовательские события

Хотя API не предоставляет полноценной системы кастомных событий, можно имитировать её через trigger:

google.maps.event.addListener(map, "custom_event", (data) => {
  console.log("Кастомное событие:", data);
});

google.maps.event.trigger(map, "custom_event", {
  type: "manual",
  payload: 123
});

Такой подход применяется для синхронизации модулей в сложных приложениях.


Управление жизненным циклом слушателей

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

  • хранение ссылок на listeners
  • группировка подписок по компонентам
  • очистка через clearInstanceListeners
google.maps.event.clearInstanceListeners(map);

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


Особенности производительности

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

  • mousemove и drag могут генерироваться десятки раз в секунду
  • обработчики должны быть максимально лёгкими
  • рекомендуется использовать throttle/debounce для тяжёлых операций

Особенно критичны события:

  • bounds_changed
  • center_changed
  • zoom_changed

Их частота может резко возрастать при анимациях карты.


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

События часто используются как триггеры загрузки данных:

  • обновление маркеров при изменении bounds
  • подгрузка тайловых данных при idle
  • синхронизация состояния UI с картой
map.addListener("idle", async () => {
  const bounds = map.getBounds();
  await fetchData(bounds);
});

Такой подход позволяет связывать визуальную часть карты с внешними источниками данных без постоянного polling-механизма.