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

В веб-картах геометрия представлена как набор структур: точки, линии, полигоны, окружности и их комбинации. В HERE Technologies JavaScript API каждая геометрия существует одновременно в двух состояниях: как математическая модель (координаты) и как интерактивный объект карты (MapObject), способный реагировать на действия пользователя.

Редактирование геометрии строится вокруг трёх базовых операций:

  • изменение координат вершин
  • добавление и удаление узлов
  • преобразование формы через перетаскивание

При этом API разделяет данные геометрии и инструменты взаимодействия, что позволяет гибко управлять поведением объектов на карте.


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

Точки (Marker / Point)

Точка является базовым элементом. В редакторском контексте она может быть:

  • фиксированной (только отображение)
  • перетаскиваемой (draggable)
  • привязанной к геометрии (например, вершина полигона)
const marker = new H.map.Marker({ lat: 52.5, lng: 13.4 }, {
  volatility: true
});

marker.draggable = true;
map.addObject(marker);

Ключевое свойство volatility: true сообщает движку, что объект будет часто изменяться, и оптимизирует перерисовку.


Линии (Polyline)

Полилиния состоит из массива координат и является основой для маршрутов и трасс.

Редактирование полилинии включает:

  • перемещение точек
  • вставку промежуточных узлов
  • удаление сегментов
const lineString = new H.geo.LineString();

lineString.pushPoint({ lat: 52.5, lng: 13.4 });
lineString.pushPoint({ lat: 52.6, lng: 13.5 });

const polyline = new H.map.Polyline(lineString, {
  style: { lineWidth: 4 },
  volatility: true
});

map.addObject(polyline);

Полигоны

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

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

  • первая и последняя точка автоматически связываются
  • внутренние отверстия (holes) обрабатываются отдельно
  • пересечения могут быть запрещены логикой приложения
const strip = new H.geo.LineString();

strip.pushPoint({ lat: 52.5, lng: 13.4 });
strip.pushPoint({ lat: 52.6, lng: 13.5 });
strip.pushPoint({ lat: 52.5, lng: 13.6 });

const polygon = new H.map.Polygon(strip, {
  style: { fillColor: 'rgba(0, 128, 255, 0.3)' },
  volatility: true
});

map.addObject(polygon);

Механизм интерактивного редактирования

Включение событийной модели

Редактирование начинается с активации событий pointer/mouse. API использует унифицированную модель событий:

  • tap
  • dragstart
  • drag
  • dragend
map.addEventListener('dragstart', onDragStart, false);
map.addEventListener('drag', onDrag, false);
map.addEventListener('dragend', onDragEnd, false);

Каждое событие содержит:

  • экранные координаты
  • географические координаты
  • ссылку на объект карты

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

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

Типичный подход:

  1. преобразование геометрии в набор draggable-узлов
  2. привязка событий drag к каждому узлу
  3. обновление LineString при перемещении
function updateGeometry(polyline, index, newCoords) {
  const line = polyline.getGeometry();
  line.removePoint(index);
  line.insertPoint(index, newCoords);
  polyline.setGeometry(line);
}

Редакторские слои и объекты управления

H.map.Group как контейнер редактирования

Редактируемые объекты часто группируются в контейнер:

const group = new H.map.Group();
map.addObject(group);

Группа позволяет:

  • управлять набором объектов как единым целым
  • централизованно обрабатывать события
  • включать/выключать режим редактирования

Привязка к стилю редактирования

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

  • увеличенные вершины
  • контрастные линии
  • маркеры узлов
const style = {
  lineWidth: 6,
  strokeColor: '#ff0000'
};

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


Работа с вершинами геометрии

Добавление узлов

Добавление новых точек происходит через вставку в LineString:

lineString.insertPoint(index, { lat: 52.55, lng: 13.45 });

Часто используется логика:

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

Удаление узлов

Удаление требует аккуратной обработки топологии:

lineString.removePoint(index);

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


Преобразования геометрии

Перемещение всей фигуры

Полное смещение объекта реализуется через пересчёт всех координат:

function shiftGeometry(lineString, deltaLat, deltaLng) {
  const points = lineString.getPoints();

  const newLine = new H.geo.LineString();

  points.forEach(p => {
    newLine.pushPoint({
      lat: p.lat + deltaLat,
      lng: p.lng + deltaLng
    });
  });

  return newLine;
}

Масштабирование и вращение

Более сложные трансформации требуют:

  • выбора центра преобразования
  • применения матричных операций
  • пересчёта координат в проекции

Типовой подход:

  1. перевод координат в плоскую систему
  2. применение transform matrix
  3. обратное преобразование в географические координаты

Синхронизация геометрии и интерфейса

Редактирование в реальном времени требует постоянной синхронизации:

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

Основная проблема — избежание лишних перерисовок.

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

  • throttling событий drag
  • временные буферы координат
  • обновление только изменённого сегмента

Работа с GeoJSON

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

Преимущества:

  • совместимость с внешними сервисами
  • сериализация геометрии
  • хранение версий
const geojson = polygon.toGeoJSON();

Обратное преобразование:

const geometry = H.geo.LineString.fromGeoJson(geojson);

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

Редактируемая геометрия должна проверяться на корректность:

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

Часто добавляется слой бизнес-логики:

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

Производительность при большом количестве узлов

При работе с плотными геометриями возникают узкие места:

  • перерасчёт геометрии при каждом drag
  • перерисовка большого количества вершин
  • обработка событий мыши

Оптимизационные стратегии:

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

Режимы взаимодействия с геометрией

Обычно выделяются несколько режимов:

  • просмотр (read-only)
  • редактирование вершин
  • свободное рисование
  • геометрические преобразования

Переключение режимов управляет:

  • активными событиями
  • доступностью drag
  • отображением управляющих точек

Связь геометрии с маршрутизацией

Редактируемая геометрия часто используется как:

  • пользовательский маршрут
  • зона доставки
  • область поиска

Изменение геометрии может триггерить:

  • перерасчёт маршрута
  • обновление изохрон
  • пересчёт расстояний

Это требует строгой синхронизации между UI и сервисами маршрутизации.


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

Каждый объект обычно имеет состояние:

  • idle
  • selected
  • editing
  • disabled

Состояние влияет на:

  • реакцию на события
  • визуальный стиль
  • доступность трансформаций

Архитектура редактора геометрии

Типичная структура:

  • слой карты (map)
  • слой объектов (objects layer)
  • слой управления (controls layer)
  • обработчики событий (event bus)
  • модель данных (geometry state)

Такое разделение позволяет:

  • отделить UI от логики
  • масштабировать количество объектов
  • подключать внешние редакторы и инструменты