DOM события внутри карты

В Google Maps JavaScript API взаимодействие с картой строится вокруг событий, которые делятся на две большие группы: события объекта карты и DOM-события контейнера карты. Первые генерируются самой картой и её сущностями (маркер, полилиния, прямоугольник), вторые возникают на уровне HTML-элемента, в котором карта рендерится.

Ключевой механизм подписки — функция google.maps.event.addListener, обеспечивающая привязку обработчиков к объектам API.

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

google.maps.event.addListener(map, "click", (event) => {
  console.log(event.latLng.toString());
});

События карты и DOM-контейнера

Карта рендерится внутри обычного DOM-элемента <div>, но большинство взаимодействий перехватывается внутренним слоем API. Поэтому важно различать:

  • события карты (click, drag, zoom_changed)
  • события DOM-элемента (mousedown, mouseup, mousemove на контейнере)

DOM-события работают напрямую с элементом, тогда как события карты абстрагированы и возвращают географические координаты.

const mapDiv = document.getElementById("map");

mapDiv.addEventListener("click", (e) => {
  console.log("DOM click:", e.clientX, e.clientY);
});

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


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

click

Срабатывает при клике по карте с возвратом координат latLng.

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

dblclick

Двойной клик. Часто используется для зума или пользовательских действий.

map.addListener("dblclick", (event) => {
  console.log("Double click at:", event.latLng.toJSON());
});

mousemove

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

map.addListener("mousemove", (event) => {
  console.log(event.latLng.toString());
});

rightclick

Контекстное меню мыши.

map.addListener("rightclick", (event) => {
  console.log("Right click:", event.latLng.toJSON());
});

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

center_changed

Срабатывает при изменении центра карты, включая перетаскивание.

map.addListener("center_changed", () => {
  console.log("Center changed");
});

zoom_changed

Фиксирует изменение уровня масштаба.

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

bounds_changed

Срабатывает при изменении видимых границ карты.

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

idle

Один из наиболее полезных событий. Срабатывает после завершения всех анимаций и обновлений.

map.addListener("idle", () => {
  console.log("Map is stable");
});

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

dragstart

Начало перетаскивания карты.

drag

Активное перетаскивание.

dragend

Завершение перемещения.

map.addListener("dragstart", () => console.log("Start dragging"));
map.addListener("drag", () => console.log("Dragging"));
map.addListener("dragend", () => console.log("End dragging"));

DOM-события контейнера карты

Несмотря на внутреннюю обработку событий API, контейнер карты остаётся обычным DOM-элементом. Это позволяет навешивать стандартные обработчики:

const mapDiv = document.getElementById("map");

mapDiv.addEventListener("mousedown", (e) => {
  console.log("Mouse down on map container");
});

Однако такие события не дают информации о географических координатах и часто конфликтуют с внутренними обработчиками карты.


Перехват событий через google.maps.event

Google Maps API предоставляет собственный механизм подписки, который предпочтительнее стандартных DOM-обработчиков при работе с картой.

google.maps.event.addListener(map, "mousemove", (event) => {
  console.log(event.latLng.lat(), event.latLng.lng());
});

Также существует привязка к DOM-элементам через API:

google.maps.event.addDomListener(mapDiv, "click", () => {
  console.log("DOM click via Google API");
});

Этот метод считается устаревшим, но встречается в старых проектах.


Объект события и его структура

События карты возвращают объект, содержащий:

  • latLng — координаты точки
  • pixel (в некоторых событиях) — экранные координаты
  • domEvent — исходное DOM-событие
map.addListener("click", (event) => {
  console.log(event.domEvent);   // оригинальный MouseEvent
  console.log(event.latLng);     // географические координаты
});

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


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

При взаимодействии с картой события часто формируют цепочку:

  1. DOM событие (mousedown)
  2. внутренний перехват API
  3. событие карты (dragstart, click)
  4. обновление состояния (center_changed, zoom_changed)
  5. стабилизация (idle)

Понимание этого порядка важно при построении сложных интерфейсов поверх карты, особенно при комбинировании пользовательских слоёв и стандартных контролов.


Особенности распространения событий

События карты не всплывают через DOM-дерево браузера. Они изолированы внутри API и не участвуют в стандартной фазе bubbling/capturing.

DOM-события контейнера, наоборот, работают по классической модели браузера, но могут быть частично перехвачены картой, особенно при взаимодействии с жестами (drag, zoom).


Отмена поведения и блокировка взаимодействий

Некоторые события позволяют управлять поведением карты через методы объекта события или конфигурацию карты.

map.addListener("click", (event) => {
  event.stop(); // предотвращение дальнейшей обработки
});

Также управление возможно через настройки:

const map = new google.maps.Map(document.getElementById("map"), {
  draggable: false,
  disableDoubleClickZoom: true
});

Производительность событийной модели

Частые события, такие как mousemove, могут вызываться десятки раз в секунду. Это требует контроля нагрузки:

  • минимизация вычислений внутри обработчика
  • использование throttling или debouncing
  • отказ от тяжёлых DOM-операций
let lastUpdate = 0;

map.addListener("mousemove", (event) => {
  const now = Date.now();
  if (now - lastUpdate < 50) return;
  lastUpdate = now;

  console.log(event.latLng.toJSON());
});

Комбинирование DOM и API событий

В сложных интерфейсах часто требуется синхронизация DOM-событий и событий карты:

map.addListener("click", (event) => {
  const panel = document.getElementById("info");
  panel.innerText = `${event.latLng.lat()}, ${event.latLng.lng()}`;
});

mapDiv.addEventListener("mousemove", (e) => {
  console.log("Pixel:", e.clientX, e.clientY);
});

Такая связка позволяет одновременно работать с географическими и экранными координатами, разделяя уровни ответственности между DOM и API.