Добавление слушателей событий

Google Maps JavaScript API построен вокруг событийной модели, в которой взаимодействие пользователя с картой, а также изменения состояния карты, экспонируются через систему слушателей. Архитектура событий основана на паттерне Observer: объекты карты и её компонентов генерируют события, а код приложения регистрирует обработчики, реагирующие на эти события.

События в API делятся на несколько категорий:

  • События карты (Map events) — клики, перемещения, изменение масштаба
  • События объектов (Marker, Polyline, Polygon) — взаимодействие с геометрией
  • UI-события — взаимодействие с элементами управления
  • События состояния — завершение загрузки, изменение проекции

Система событий реализована через объект google.maps.event и методы экземпляров, таких как addListener.

Ключевой принцип:

Каждый объект карты может быть источником событий, а любой обработчик может быть подписан на эти события.

Регистрация слушателей событий

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

google.maps.event.addListener(instance, eventName, handler);

или через сокращённую форму:

instance.addListener(eventName, handler);

Пример обработки клика по карте

map.addListener("click", (event) => {
  console.log("Координаты клика:", event.latLng.lat(), event.latLng.lng());
});

Объект event содержит контекст события, включая географические координаты latLng.

Типы событий карты

Событие click

Срабатывает при клике по карте. Передаёт объект MouseEvent, содержащий координаты.

map.addListener("click", (e) => {
  const position = {
    lat: e.latLng.lat(),
    lng: e.latLng.lng()
  };
});

Событие bounds_changed

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

map.addListener("bounds_changed", () => {
  const bounds = map.getBounds();
});

Событие zoom_changed

Срабатывает при изменении масштаба:

map.addListener("zoom_changed", () => {
  console.log("Zoom:", map.getZoom());
});

Событие center_changed

Вызывается при изменении центра карты:

map.addListener("center_changed", () => {
  const center = map.getCenter();
});

События маркеров

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

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

marker.addListener("click", () => {
  console.log("Маркер нажат");
});

Перетаскивание маркера

Если включена опция draggable: true, доступны события:

marker.addListener("dragstart", () => {
  console.log("Начало перетаскивания");
});

marker.addListener("drag", () => {
  console.log("Перетаскивание");
});

marker.addListener("dragend", (e) => {
  console.log("Финальная позиция:", e.latLng);
});

Использование объекта google.maps.event

Наряду с методами экземпляров используется глобальный объект:

google.maps.event.addListener(map, "click", handler);

Также доступны дополнительные функции:

  • addListenerOnce — одноразовый обработчик
  • removeListener — удаление подписки
  • clearInstanceListeners — очистка всех слушателей объекта

Одноразовый обработчик

google.maps.event.addListenerOnce(map, "idle", () => {
  console.log("Карта впервые стабилизировалась");
});

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

Удаление слушателей событий

Каждый зарегистрированный слушатель возвращает объект подписки:

const listener = map.addListener("click", handler);

Удаление:

google.maps.event.removeListener(listener);

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

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

В обработчиках событий значение this не всегда указывает на объект карты. Поэтому предпочтительным является использование стрелочных функций или явное сохранение ссылки:

const self = map;

map.addListener("click", function (e) {
  self.setCenter(e.latLng);
});

или:

map.addListener("click", (e) => {
  map.setCenter(e.latLng);
});

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

Polyline

polyline.addListener("click", (e) => {
  console.log("Клик по линии:", e.latLng);
});

Polygon

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

Дополнительно могут передаваться индексы вершин и сегментов.

Кастомные взаимодействия через события карты

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

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

Пример динамического добавления маркера:

map.addListener("click", (e) => {
  new google.maps.Marker({
    position: e.latLng,
    map: map
  });
});

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

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

  1. mousedown
  2. mouseup
  3. click
  4. bounds_changed (если произошло изменение)
  5. idle (после завершения всех обновлений)

Понимание порядка позволяет избегать конфликтов между обработчиками.

Производительность и управление событиями

Чрезмерное количество слушателей может приводить к снижению производительности.

Рекомендуемые практики:

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

События DOM и события карты

События API не являются DOM-событиями. Несмотря на внешнее сходство, они:

  • не всплывают в DOM-дереве
  • не используют стандартный EventTarget
  • обрабатываются внутри системы Google Maps

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

Продвинутая маршрутизация событий

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

map.addListener("click", (e) => {
  marker.setPosition(e.latLng);

  google.maps.event.trigger(marker, "custom_move");
});

marker.addListener("custom_move", () => {
  console.log("Маркер перемещён через кастомное событие");
});

Механизм trigger позволяет инициировать пользовательские события вручную.

Работа с несколькими слушателями

Один объект может иметь множество обработчиков одного события:

map.addListener("click", handler1);
map.addListener("click", handler2);

Все обработчики будут вызваны последовательно в порядке регистрации.

Обработка ошибок в событиях

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

map.addListener("click", (e) => {
  try {
    riskyOperation(e);
  } catch (err) {
    console.error(err);
  }
});

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

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

map.addListener("idle", () => {
  console.log("Карта полностью загружена");
});

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

Динамическое управление подписками

В сложных интерфейсах слушатели добавляются и удаляются в зависимости от состояния приложения:

let clickListener = null;

function enableClick() {
  clickListener = map.addListener("click", handleClick);
}

function disableClick() {
  google.maps.event.removeListener(clickListener);
}

Такой подход предотвращает накопление неактуальных обработчиков и обеспечивает предсказуемое поведение интерфейса.