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

В Google Maps JavaScript API взаимодействие пользователя с картой строится вокруг событийной модели. Почти каждый объект карты — маркер, линия, многоугольник, окружность — способен генерировать события, на которые можно подписаться через механизм addListener. События делятся на пользовательские (click, drag, mouseover и т.д.) и внутренние (изменение состояния объектов через методы API).

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


Базовый механизм подписки на события

Все интерактивные объекты используют единый интерфейс:

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

Где:

  • instance — объект карты или её примитив (Marker, Polygon, Polyline и др.)
  • eventName — имя события
  • handler — функция-обработчик

Пример:

const marker = new google.maps.Marker({
  position: { lat: 55.751244, lng: 37.618423 },
  map: map,
  title: "Москва"
});

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

Современный синтаксис также допускает:

marker.addListener("click", handler);

Оба варианта эквивалентны, но второй считается более лаконичным.


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

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

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

click

Срабатывает при нажатии на маркер.

marker.addListener("click", () => {
  infoWindow.open(map, marker);
});

dblclick

Двойной клик по маркеру. Используется для альтернативных действий, например масштабирования или редактирования.

marker.addListener("dblclick", () => {
  map.setZoom(map.getZoom() + 1);
});

dragstart, drag, dragend

События перетаскивания маркера. Работают только при draggable: true.

marker.setDraggable(true);

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

marker.addListener("drag", (event) => {
  console.log("Текущая позиция:", event.latLng.toString());
});

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

mouseover и mouseout

Используются для визуального взаимодействия.

marker.addListener("mouseover", () => {
  marker.setAnimation(google.maps.Animation.BOUNCE);
});

marker.addListener("mouseout", () => {
  marker.setAnimation(null);
});

rightclick

Контекстное взаимодействие (ПКМ).

marker.addListener("rightclick", (event) => {
  console.log("Контекстное меню маркера");
});

События линий (Polyline)

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

click на линии

const polyline = new google.maps.Polyline({
  path: [
    { lat: 55.75, lng: 37.61 },
    { lat: 55.76, lng: 37.62 }
  ],
  map: map
});

polyline.addListener("click", (event) => {
  console.log("Клик по линии в точке:", event.latLng.toString());
});

mousemove

Используется для отслеживания положения курсора вдоль линии.

polyline.addListener("mousemove", (event) => {
  console.log("Курсор над линией:", event.latLng.toString());
});

События многоугольников (Polygon)

Polygon позволяет работать с замкнутыми областями и поддерживает расширенный набор взаимодействий.

click и dblclick

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

mouseover / mouseout

Применяются для динамического выделения областей.

polygon.addListener("mouseover", () => {
  polygon.setOptions({ fillColor: "#FF0000" });
});

polygon.addListener("mouseout", () => {
  polygon.setOptions({ fillColor: "#00FF00" });
});

rightclick

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


События окружностей (Circle)

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

click

circle.addListener("click", (event) => {
  console.log("Клик по окружности");
});

изменение параметров

Хотя circle не является редактируемым по умолчанию, при включении editable: true можно отслеживать изменения:

circle.setEditable(true);

circle.addListener("radius_changed", () => {
  console.log("Радиус изменён:", circle.getRadius());
});

circle.addListener("center_changed", () => {
  console.log("Центр изменён:", circle.getCenter().toString());
});

События прямоугольников (Rectangle)

Rectangle поддерживает те же принципы, что и circle, но с привязкой к bounds.

bounds_changed

rectangle.addListener("bounds_changed", () => {
  console.log("Границы изменены:", rectangle.getBounds());
});

editable события

При включении редактирования:

rectangle.setEditable(true);

rectangle.addListener("dragend", () => {
  console.log("Прямоугольник перемещён");
});

События изменения состояния объектов

Многие объекты Google Maps API имеют внутренние события изменения свойств:

  • position_changed (Marker)
  • zoom_changed (Map)
  • center_changed (Map)
  • visible_changed
  • zindex_changed

Пример:

marker.addListener("position_changed", () => {
  console.log("Новая позиция маркера:", marker.getPosition().toString());
});

Работа с картой как источником событий

Карта сама является крупным источником событий, которые часто комбинируются с событиями объектов.

click по карте

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

zoom_changed

map.addListener("zoom_changed", () => {
  console.log("Новый zoom:", map.getZoom());
});

drag событий карты

map.addListener("dragstart", () => {
  console.log("Начало перемещения карты");
});

map.addListener("dragend", () => {
  console.log("Конец перемещения карты");
});

Объект события (MouseEvent)

При взаимодействии с геометрическими объектами большинство событий передают объект MouseEvent, содержащий:

  • latLng — координаты точки взаимодействия
  • domEvent — нативное DOM-событие (при наличии)
  • stop() — остановка дальнейшего распространения события

Пример:

marker.addListener("click", (event) => {
  console.log(event.latLng.lat(), event.latLng.lng());
});

Управление подписками на события

Каждый вызов addListener возвращает объект подписки:

const listener = marker.addListener("click", () => {
  console.log("click");
});

Удаление:

google.maps.event.removeListener(listener);

Очистка всех событий объекта:

google.maps.event.clearInstanceListeners(marker);

Очистка всех глобальных слушателей:

google.maps.event.clearListeners(marker, "click");

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

Динамическое связывание данных

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

marker.addListener("dragend", (event) => {
  updateFormCoordinates(event.latLng);
});

Привязка InfoWindow к объектам

const infoWindow = new google.maps.InfoWindow({
  content: "Информация"
});

polygon.addListener("click", (event) => {
  infoWindow.setPosition(event.latLng);
  infoWindow.open(map);
});

Использование замыканий

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

function createMarker(data) {
  const marker = new google.maps.Marker({
    position: data.position,
    map: map
  });

  marker.addListener("click", () => {
    console.log(data.id);
  });
}

Особенности поведения событий

Событийная модель Google Maps имеет ряд особенностей:

  • События не всегда всплывают как в DOM
  • Некоторые события зависят от включённых опций (например, draggable)
  • Производительность может снижаться при большом количестве обработчиков
  • Рекомендуется избегать создания анонимных функций в циклах при массовой генерации объектов

Производственные аспекты

При работе с большим количеством маркеров и фигур важно учитывать:

  • необходимость удаления слушателей при уничтожении объектов
  • минимизацию количества активных обработчиков
  • использование кластеризации маркеров вместо индивидуальных событий
  • централизованную обработку событий через делегирование логики
const markers = [];

for (let i = 0; i < 1000; i++) {
  const marker = new google.maps.Marker({
    position: generatePosition(i),
    map: map
  });

  marker.addListener("click", handleClick);
  markers.push(marker);
}

Комбинирование событий разных объектов

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

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

  marker.addListener("click", () => {
    console.log("Маркер создан по клику на карту");
  });
});

Приоритет событий и взаимодействие слоёв

При работе с несколькими слоями (markers, polygons, overlays) важно учитывать порядок обработки событий. Более специфические объекты (например, маркеры) перехватывают события раньше, чем карта.

Поведение может зависеть от:

  • zIndex
  • прозрачности фигур
  • включённых интерактивных опций слоя