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

Mapbox GL JS использует событийно-ориентированную модель взаимодействия с картой, где графические примитивы и пользовательские действия обрабатываются через набор режимов редактирования. В экосистеме Mapbox GL Draw режимы определяют поведение инструмента при создании, изменении и выделении геометрии, формируя конечный пользовательский опыт работы с пространственными объектами.


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

Ключевая идея заключается в разделении логики:

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

Режим не существует изолированно: он работает в связке с состоянием FeatureCollection, которое хранит все геометрические объекты.


Базовые режимы Mapbox GL Draw

Стандартный набор режимов охватывает основные сценарии редактирования.

simple_select

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

Характерные особенности:

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

Поведение определяется тем, какие объекты находятся в состоянии selected.


direct_select

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

Позволяет:

  • перемещать вершины (vertices)
  • изменять форму линий и полигонов
  • добавлять или удалять узлы

Внутренне режим работает с индексами координат, изменяя структуру массива coordinates в GeoJSON.


draw_point

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

Основные характеристики:

  • одиночный клик создаёт новый Point
  • режим завершается автоматически после создания
  • минимальное состояние редактирования

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


draw_line_string

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

Поведение:

  • каждый клик добавляет новую вершину
  • курсор мыши отображает «резиновую линию»
  • завершение происходит по двойному клику или нажатию Enter

Линия формируется как массив координат, который динамически расширяется.


draw_polygon

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

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

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

Полигон хранит структуру:

coordinates: [
  [ [lng, lat], [lng, lat], ... , [lng, lat] ]
]

Жизненный цикл режима

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

onSetup

Инициализация состояния режима. Вызывается при активации режима.

Используется для:

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

onClick

Обработка кликов по карте.

Зависит от режима:

  • добавление вершин
  • выбор объектов
  • завершение рисования

onMouseMove

Отвечает за интерактивное обновление геометрии.

Типичное применение:

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

onKeyUp / onKeyDown

Обработка клавиатурных событий:

  • удаление последней точки (Backspace)
  • отмена действия (Escape)
  • завершение рисования (Enter)

onStop

Вызывается при выходе из режима.

Используется для:

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

onTrash

Обработка удаления объектов.

Позволяет централизованно управлять удалением выбранных feature.


Внутренние состояния и feature-state

Режимы активно используют feature-state Mapbox GL JS для хранения метаданных объектов.

Типичные состояния:

  • active: true — объект редактируется
  • meta: "vertex" — вершина линии/полигона
  • selected: true — объект выделен

Эти состояния не входят в GeoJSON напрямую, но влияют на отрисовку слоя.


Переходы между режимами

Смена режима осуществляется через changeMode, что является центральным механизмом управления состоянием.

Пример:

mapboxDraw.changeMode('simple_select');
mapboxDraw.changeMode('draw_polygon');
mapboxDraw.changeMode('direct_select', { featureId: '123' });

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


Кастомные режимы

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

Структура кастомного режима:

const customMode = {
  onSetup() {
    return {
      active: true
    };
  },

  onClick(state, e) {
    state.count = (state.count || 0) + 1;
    return state;
  },

  onMouseMove(state, e) {
    state.lastPosition = [e.lngLat.lng, e.lngLat.lat];
    return state;
  },

  onKeyUp(state, e) {
    if (e.key === 'Escape') {
      return this.changeMode('simple_select');
    }
  }
};

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

  • рисование кругов
  • ограничение по сетке (snap-to-grid)
  • построение зон интереса
  • интерактивные измерительные инструменты

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

Во время рисования создаются промежуточные объекты:

  • currentVertex
  • hotPoint
  • midPoint
  • activeLine

Они не сохраняются в итоговом GeoJSON, но используются для визуализации и взаимодействия.


Взаимодействие с источниками данных

Режимы тесно связаны с GeoJSONSource, который обновляется при каждом изменении состояния.

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

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

Mapbox GL JS использует WebGL-рендеринг, поэтому обновления происходят эффективно через diff состояния, а не полную перерисовку сцены.


Режим редактирования вершин

direct_select реализует сложную систему манипуляции вершинами.

Основные операции:

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

Каждая вершина имеет индекс в массиве координат, что позволяет точно изменять структуру геометрии без пересоздания объекта.


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

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

  • mousedown
  • mousemove
  • mouseup
  • click

События преобразуются в географические координаты через map.project и map.unproject, что обеспечивает синхронизацию экранных и географических координат.


Отрисовка интерактивных элементов

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

  • line layer для линий
  • fill layer для полигонов
  • circle layer для вершин

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


Управление завершением рисования

Завершение режима зависит от типа геометрии:

  • point — мгновенное завершение
  • line_string — двойной клик или Enter
  • polygon — замыкание контура или Enter

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


Особенности поведения в WebGL контексте

Режимы не взаимодействуют напрямую с DOM-элементами геометрии. Вся логика построена на:

  • буферизации координат
  • обновлении GeoJSON
  • GPU-рендеринге через style layers

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