Режимы рисования

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

В экосистеме MapLibre GL JS работа с редактируемой графикой поверх карты строится через концепцию режимов (modes). Режим определяет текущее поведение пользовательского ввода: клики, перемещения курсора, перетаскивание вершин, создание новых объектов и их редактирование.

Механизм режимов чаще всего реализуется через надстройку над базовым рендером карты — библиотеку MapLibre GL Draw, которая вводит конечный автомат состояний для геометрий GeoJSON.

Режимы рисования позволяют разделить поведение на изолированные сценарии:

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

Архитектура режимов

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

  • onSetup() — инициализация состояния режима
  • onClick() — обработка кликов
  • onMouseMove() — реакция на движение курсора
  • onKeyUp() / onKeyDown() — клавиатурные события
  • toDisplayFeatures() — управление отображением GeoJSON
  • onStop() — завершение режима

Состояние режима хранит временные данные:

  • текущая геометрия
  • активная вершина
  • промежуточные координаты
  • выделенные элементы

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


Базовые встроенные режимы

simple_select

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

Поведение:

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

Типичные операции:

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

direct_select

Режим точечного редактирования геометрии.

Особенности:

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

Механика работы:

  • каждая вершина представлена как draggable handle
  • изменение координат мгновенно обновляет GeoJSON
  • пересчет геометрии происходит в реальном времени

Используется при точной геопривязке объектов.


draw_point

Режим создания точечных объектов.

Поведение:

  • каждый клик добавляет новый Feature типа Point
  • отсутствует стадия завершения формы
  • режим остается активным до переключения

Применение:

  • отметки на карте
  • POI-объекты
  • временные маркеры

draw_line_string

Режим построения ломаных линий.

Алгоритм:

  • первый клик задает стартовую точку
  • последующие клики добавляют вершины
  • двойной клик или Enter завершает линию

Особенности:

  • динамическая отрисовка preview-линии
  • поддержка undo последнего сегмента
  • автоподсветка текущего сегмента

draw_polygon

Режим построения полигонов.

Логика:

  • последовательное добавление вершин
  • автоматическое замыкание контура
  • запрет самопересечения (опционально)

Дополнительные функции:

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

Статический режим

Static mode используется для блокировки редактирования.

Поведение:

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

Применение:

  • режим просмотра
  • защита данных от изменений
  • отображение финальных геометрий

Пользовательские режимы

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

Структура пользовательского режима:

const customMode = {
  onSetup() {
    return {
      coordinates: []
    };
  },

  onClick(state, e) {
    state.coordinates.push([e.lngLat.lng, e.lngLat.lat]);
  },

  toDisplayFeatures(state, geojson, display) {
    display(geojson);
  }
};

Ключевые возможности:

  • переопределение всех событий ввода
  • интеграция с внешними состояниями приложения
  • реализация специализированных инструментов (измерение, снаппинг, трассировка маршрутов)

Управление переходами между режимами

Система режимов построена на переключении контекста:

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

Пример логики переходов:

  • simple_select → direct_select при выборе объекта
  • draw_polygon → simple_select при завершении рисования
  • draw_line_string → draw_line_string при продолжении построения

Состояние и хранение данных

Каждый режим работает поверх GeoJSON Feature Collection.

Основные сущности:

  • Feature
  • Geometry
  • FeatureCollection

Состояние режима синхронизируется с источником данных:

  • добавление новых features
  • обновление координат
  • удаление объектов

Любое изменение проходит через единый pipeline обновления слоя карты.


Обработка событий ввода

События MapLibre GL JS передаются в режим через адаптер:

  • mouse events
  • touch events
  • keyboard events

Типовая последовательность:

  1. событие поступает от карты
  2. передается активному режиму
  3. режим обновляет состояние
  4. вызывается перерисовка слоя

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


Визуализация промежуточных состояний

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

  • preview линий
  • ghost vertices
  • временные полигоны
  • выделенные сегменты

Функция toDisplayFeatures определяет, какие элементы:

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

Это позволяет разделять внутреннее состояние и визуальную модель.


Управление активными вершинами

В режимах редактирования каждая геометрия разбивается на набор интерактивных узлов.

Операции:

  • перемещение вершины
  • вставка новой точки между существующими
  • удаление узла

Для линий и полигонов применяется топологический пересчет:

  • сохранение целостности формы
  • обновление соседних сегментов
  • перерасчет bounding box

Событийная модель и приоритеты

При обработке взаимодействий действует приоритет:

  1. drag событий
  2. click событий
  3. hover событий
  4. keyboard событий

Это предотвращает конфликт между редактированием и навигацией карты.


Производительность режимов

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

Оптимизации включают:

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

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


Интеграция с внешними слоями

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

  • heatmap слои
  • raster tiles
  • vector tiles
  • кастомные WebGL слои

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


Сериализация состояния режимов

Для сохранения состояния используется преобразование:

  • GeoJSON как основной формат
  • дополнительные metadata поля
  • временные свойства режима исключаются при сохранении

Это позволяет:

  • сохранять черновики
  • восстанавливать сессию редактирования
  • синхронизировать состояние между клиентами