Редактирование фигур

Редактирование геометрических объектов в Google Maps JavaScript API строится вокруг принципа интерактивной модификации векторных слоёв карты: полилиний, полигонов, окружностей и прямоугольников. Каждый тип фигуры представляет собой объект с внутренней моделью данных, которая может быть изменена пользователем либо программно через API.

Основой редактируемых фигур выступают свойства:

  • editable — включает режим изменения геометрии
  • draggable — позволяет перемещать объект целиком
  • paths / path — структура координат
  • события изменения геометрии

При включении редактирования API переводит объект в состояние, при котором вершины (vertices) становятся перетаскиваемыми маркерами, а изменения немедленно отражаются в модели данных.

Полилинии и полигоны

Для Polyline и Polygon редактирование осуществляется через массив координат типа MVCArray, который предоставляет реактивный интерфейс для работы с вершинами.

const polygon = new google.maps.Polygon({
  paths: [
    { lat: 55.75, lng: 37.61 },
    { lat: 55.76, lng: 37.62 },
    { lat: 55.74, lng: 37.63 }
  ],
  editable: true,
  draggable: true,
  map: map
});

В режиме редактирования каждая вершина становится интерактивной. Добавление, удаление и перемещение точек изменяет внутренний массив paths.

MVCArray и реактивные изменения

Ключевым механизмом является google.maps.MVCArray, который используется для хранения координат:

  • insertAt(index, element) — вставка точки
  • setAt(index, element) — изменение точки
  • removeAt(index) — удаление точки
  • getArray() — получение копии массива

Изменения в MVCArray автоматически отражаются на карте без необходимости повторного создания объекта.

const path = polygon.getPath();

path.insertAt(1, new google.maps.LatLng(55.755, 37.615));
path.setAt(0, new google.maps.LatLng(55.750, 37.610));
path.removeAt(2);

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

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

Основные события

  • set_at — изменение существующей вершины
  • insert_at — добавление вершины
  • remove_at — удаление вершины
google.maps.event.addListener(polygon.getPath(), 'set_at', () => {
  console.log('Изменена вершина');
});

google.maps.event.addListener(polygon.getPath(), 'insert_at', () => {
  console.log('Добавлена вершина');
});

Эти события позволяют синхронизировать состояние карты с внешними системами хранения данных.

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

При включённом draggable: true доступны события:

  • dragstart
  • drag
  • dragend

Они применяются как к целому объекту, так и к отдельным вершинам в режиме редактирования.

Редактирование окружностей

Окружность (Circle) отличается от полигонов тем, что её форма определяется центром и радиусом.

const circle = new google.maps.Circle({
  center: { lat: 55.75, lng: 37.61 },
  radius: 1000,
  editable: true,
  draggable: true,
  map: map
});

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

  • перемещение центра
  • изменение радиуса через перетаскиваемый маркер

Изменения отслеживаются через:

circle.addListener('center_changed', () => {});
circle.addListener('radius_changed', () => {});

Прямоугольники и их редактирование

Прямоугольник (Rectangle) задаётся границами LatLngBounds.

const rectangle = new google.maps.Rectangle({
  bounds: {
    north: 55.76,
    south: 55.74,
    east: 37.65,
    west: 37.60
  },
  editable: true,
  draggable: true,
  map: map
});

Редактирование реализуется через изменение угловых маркеров, которые модифицируют bounds.

События:

  • bounds_changed
rectangle.addListener('bounds_changed', () => {
  const bounds = rectangle.getBounds();
});

Drawing Manager как инструмент редактирования

Для создания и редактирования фигур используется DrawingManager, который предоставляет UI-инструменты рисования.

const drawingManager = new google.maps.drawing.DrawingManager({
  drawingMode: null,
  drawingControl: true,
  drawingControlOptions: {
    position: google.maps.ControlPosition.TOP_CENTER,
    drawingModes: ['polygon', 'polyline', 'rectangle', 'circle']
  }
});

drawingManager.setMap(map);

После создания объекта можно включить редактирование:

polygon.setEditable(true);
polygon.setDraggable(true);

DrawingManager часто используется как стартовая точка, после которой управление передаётся вручную.

Программное изменение геометрии

Редактирование не ограничивается пользовательским интерфейсом. Геометрия может изменяться программно.

Обновление полигона

const path = polygon.getPath();

path.clear();

path.push(new google.maps.LatLng(55.75, 37.61));
path.push(new google.maps.LatLng(55.76, 37.62));
path.push(new google.maps.LatLng(55.74, 37.63));

Полная замена пути

polygon.setPaths([
  { lat: 55.70, lng: 37.60 },
  { lat: 55.71, lng: 37.61 },
  { lat: 55.72, lng: 37.62 }
]);

Сериализация и сохранение состояния

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

Полигон

const coords = polygon.getPath().getArray().map(p => ({
  lat: p.lat(),
  lng: p.lng()
}));

Окружность

const data = {
  center: circle.getCenter().toJSON(),
  radius: circle.getRadius()
};

Прямоугольник

const bounds = rectangle.getBounds().toJSON();

Такая структура используется для хранения в базах данных и последующего восстановления объектов на карте.

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

Редактирование часто разделяется на два режима:

  • режим просмотра
  • режим редактирования

Переключение осуществляется через свойства:

polygon.setEditable(false);
polygon.setDraggable(false);

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

Ограничение редактирования и контроль геометрии

Для контроля допустимых изменений применяются дополнительные проверки:

  • ограничение количества вершин
  • запрет самопересечений
  • фиксация отдельных точек
  • ограничение по географическим границам

Проверки обычно выполняются внутри событий set_at и insert_at.

path.addListener('insert_at', (index) => {
  if (path.getLength() > 10) {
    path.removeAt(index);
  }
});

Работа с геометрической библиотекой

Расширение geometry используется для анализа изменений:

  • вычисление площади
  • проверка попадания точки внутрь полигона
  • расчёт расстояний

Пример контроля площади:

const area = google.maps.geometry.spherical.computeArea(polygon.getPath());

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

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

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

  • частоту событий set_at
  • перерисовку слоя карты
  • минимизацию вычислений в обработчиках

Оптимизация достигается через:

  • дебаунсинг событий
  • кэширование вычислений
  • временное отключение слушателей
let lock = false;

path.addListener('set_at', () => {
  if (lock) return;
  lock = true;

  setTimeout(() => {
    lock = false;
  }, 100);
});

Комбинированное редактирование фигур

В сложных приложениях несколько фигур редактируются одновременно. Для этого используется централизованное управление состоянием:

  • единый список объектов
  • глобальный режим редактирования
  • синхронизация изменений

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

Особенности поведения при трансформации

Перемещение (draggable) и редактирование вершин могут конфликтовать. В таких случаях приоритет определяется типом взаимодействия:

  • перетаскивание вершины изменяет форму
  • перетаскивание объекта перемещает всю фигуру

Это различие важно при построении сложных интерфейсов редактирования геоданных.