Контроллеры навигации

Контроллеры навигации в Deck.gl отвечают за преобразование пользовательских действий (мышь, клавиатура, тач-устройства) в изменения состояния камеры. Это слой логики, который связывает визуализацию данных с интерактивным управлением сценой: панорамированием, вращением, масштабированием и изменением перспективы.

В основе Deck.gl лежит модель viewState — объект, описывающий положение и ориентацию камеры. Контроллер не изменяет сцену напрямую, а лишь модифицирует viewState, который затем используется слоями и представлениями (View) для пересчёта проекции.

Ключевая идея:

  • пользователь взаимодействует с интерфейсом;
  • контроллер интерпретирует события;
  • обновляется viewState;
  • Deck.gl пересчитывает камеру и перерисовывает слои.

Такое разделение делает систему предсказуемой и легко расширяемой.

Базовая модель viewState

viewState — центральная точка управления навигацией. Его структура зависит от типа представления, но чаще всего включает:

  • координаты центра (longitude, latitude)
  • масштаб (zoom)
  • наклон (pitch)
  • поворот (bearing)

Для 3D-вью может добавляться:

  • altitude
  • параметры камеры в пространстве

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

Включение контроллера в DeckGL

Контроллер активируется через свойство controller в компоненте DeckGL:

<DeckGL
  initialViewState={{
    longitude: 37.6173,
    latitude: 55.7558,
    zoom: 10,
    pitch: 0,
    bearing: 0
  }}
  controller={true}
/>

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

controller={{
  dragPan: true,
  scrollZoom: true,
  doubleClickZoom: false,
  touchRotate: true,
  keyboard: true
}}

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

Типы встроенных контроллеров

Deck.gl предоставляет несколько специализированных контроллеров, каждый из которых ориентирован на определённый тип сцены.

MapController

Используется для 2D-картографических представлений. Поддерживает:

  • панорамирование карты
  • плавный zoom колесом мыши
  • инерцию движения
  • ограничение границ

Основная задача — имитация поведения классических картографических библиотек.

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

  • zoom центрируется относительно курсора;
  • поддерживается кинетическое движение;
  • возможна фиксация диапазонов масштаба.

OrbitController

Предназначен для 3D-сцен с орбитальным вращением камеры вокруг центра.

Поддерживает:

  • вращение вокруг осей X и Y
  • zoom в/из сцены
  • орбитальное движение камеры

Типичное применение — визуализация 3D-объектов, архитектурных моделей и геометрических сцен.

Поведение камеры:

  • камера всегда смотрит на фиксированную точку;
  • перемещение мыши изменяет углы bearing и pitch.

FirstPersonController

Используется для навигации в стиле «от первого лица».

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

  • движение вперёд/назад по направлению взгляда;
  • поворот камеры мышью;
  • управление через клавиатуру (WASD);
  • ограниченная орбита (камера не вращается вокруг точки, а перемещается в пространстве).

Этот контроллер полезен для симуляций и 3D-исследований пространства.

Настройка ограничений навигации

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

Пример ограничений:

controller={{
  minZoom: 3,
  maxZoom: 15,
  minPitch: 0,
  maxPitch: 60
}}

Такие параметры предотвращают:

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

Для географических приложений также используются границы:

  • maxBounds (ограничение области карты)
  • логика clamp значений координат

Управление инерцией и плавностью

Навигация в Deck.gl может включать кинетическое поведение — продолжение движения после отпускания мыши.

Ключевые параметры:

  • inertia — коэффициент затухания
  • dragRotate — чувствительность вращения
  • scrollZoomSpeed — скорость масштабирования

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

Обработка событий контроллера

Контроллеры генерируют события, которые могут быть перехвачены:

  • onViewStateChange
  • onInteractionStateChange
  • onHover
  • onClick

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

onViewStateChange: ({viewState}) => {
  setViewState(viewState);
}

Этот механизм делает viewState управляемым извне, что позволяет синхронизировать его с состоянием приложения (React, Redux и др.).

Контроллер как state machine

Внутри Deck.gl контроллер работает как конечный автомат состояний:

  • idle (ожидание взаимодействия)
  • dragging (перетаскивание)
  • rotating (вращение сцены)
  • zooming (масштабирование)
  • transitioning (анимированное изменение состояния)

Каждое состояние определяет:

  • допустимые события;
  • реакцию на ввод;
  • изменение viewState.

Такой подход позволяет избежать конфликтов между жестами (например, одновременного pan и rotate).

Кастомизация контроллеров

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

Типичная схема:

  • наследование от MapController или Controller;
  • переопределение методов обработки событий;
  • изменение логики вычисления viewState.

Пример логики обработки:

  • handlePanStart
  • handlePanMove
  • handlePanEnd
  • handleZoom

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

Мульти-тач и жесты

На сенсорных устройствах контроллеры используют жесты:

  • pinch → zoom
  • two-finger drag → pan
  • rotation gesture → bearing

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

Особенности обработки:

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

Связь контроллеров с View системой

Контроллеры не существуют отдельно — они привязаны к View.

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

  • MapView → MapController
  • OrbitView → OrbitController
  • FirstPersonView → FirstPersonController

Это позволяет одной сцене поддерживать несколько режимов навигации.

Пример переключения:

  • 2D карта → MapController
  • 3D модель → OrbitController

При смене View меняется и логика интерпретации viewState.

Анимация переходов и контроллер

Контроллеры могут взаимодействовать с системой переходов (transitions), когда изменения viewState происходят плавно.

Например:

  • плавный zoom к точке;
  • анимированное вращение сцены;
  • перелёт камеры между объектами.

Контроллер инициирует изменение состояния, а система анимации интерполирует значения:

  • линейно;
  • по кривым easing;
  • с физическими моделями движения.

Приоритеты управления состоянием

В системе Deck.gl важно разделение источников управления:

  • пользовательский ввод (контроллер)
  • программные изменения (setProps)
  • анимации переходов

При конфликте приоритет обычно у:

  1. активной анимации transition;
  2. пользовательского взаимодействия;
  3. внешнего обновления viewState.

Это предотвращает «дёргание» камеры при одновременных обновлениях.

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

Контроллеры оптимизированы под высокую частоту событий:

  • pointer events обрабатываются без блокировки UI;
  • используется throttling для viewState обновлений;
  • минимизируются пересчёты матриц до фактического изменения состояния.

Ключевая цель — удержание стабильного FPS при интенсивной навигации.

Практика интеграции с внешним состоянием

В реальных приложениях viewState часто хранится вне DeckGL:

  • React state;
  • глобальное состояние (Redux, Zustand);
  • URL параметры.

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

  • сохранять положение камеры;
  • делиться ссылками на конкретный вид;
  • восстанавливать сессию пользователя.

Контроллер при этом становится лишь источником событий, а не владельцем состояния.

Поведение при отключённом контроллере

Если controller=false, Deck.gl:

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

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

  • статических визуализаций;
  • синхронизированных сцен;
  • кастомных систем управления поверх Deck.gl.