Управление камерой и viewport

Система визуализации Deck.gl разделяет понятия данных, слоёв, камеры и viewport. Такое разделение позволяет независимо управлять отображением объектов и параметрами наблюдения сцены.

Камера (View State) определяет положение наблюдателя относительно визуализируемых данных:

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

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

Схематически процесс выглядит следующим образом:

Данные → Слой → Камера (View State)
                    ↓
                 Viewport
                    ↓
                Canvas

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


Понятие View State

В Deck.gl состояние камеры обычно хранится в объекте viewState.

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

const viewState = {
  longitude: 37.6176,
  latitude: 55.7558,
  zoom: 10,
  pitch: 45,
  bearing: 0
};

Основные свойства

Свойство Назначение
longitude Центральная долгота
latitude Центральная широта
zoom Масштаб
pitch Наклон камеры
bearing Поворот карты
position Смещение камеры
maxZoom Максимальный масштаб
minZoom Минимальный масштаб

Передача состояния камеры выполняется через экземпляр Deck:

new Deck({
  initialViewState: {
    longitude: 37.6176,
    latitude: 55.7558,
    zoom: 10
  },
  controller: true,
  layers: []
});

InitialViewState и ViewState

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

Неконтролируемый режим

Камера управляется самим Deck.gl.

new Deck({
  initialViewState: {
    longitude: -122.4,
    latitude: 37.8,
    zoom: 12
  },
  controller: true
});

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


Контролируемый режим

Состояние камеры хранится во внешнем приложении.

new Deck({
  viewState,
  controller: true
});

Обновление осуществляется вручную:

deck.setProps({
  viewState: {
    longitude: 30,
    latitude: 50,
    zoom: 8
  }
});

Такой подход широко используется в React-приложениях.


Интерактивное управление камерой

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

controller: true

Пример:

new Deck({
  initialViewState,
  controller: true,
  layers
});

После активации контроллера становятся доступны:

  • масштабирование колесом мыши;
  • перетаскивание карты;
  • вращение;
  • изменение наклона;
  • сенсорные жесты на мобильных устройствах.

Событие изменения камеры

При каждом изменении положения камеры вызывается обработчик onViewStateChange.

new Deck({
  controller: true,

  onViewStateChange: ({viewState}) => {
    console.log(viewState);
  }
});

Получаемый объект содержит актуальные параметры:

{
  longitude: 37.6,
  latitude: 55.7,
  zoom: 11,
  pitch: 30,
  bearing: 15
}

Это позволяет синхронизировать камеру с состоянием приложения.


Управление камерой в React

Наиболее распространённый подход заключается в хранении состояния через React Hooks.

const [viewState, setViewState] = useState({
  longitude: -122.4,
  latitude: 37.8,
  zoom: 11
});

Передача в DeckGL:

<DeckGL
  viewState={viewState}
  controller={true}
  onViewStateCha nge={({viewState}) => {
    setViewState(viewState);
  }}
>
</DeckGL>

В этом случае React становится единственным источником состояния камеры.


Ограничение области навигации

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

Пример ограничения масштаба:

new Deck({
  initialViewState: {
    longitude: 37.6,
    latitude: 55.7,
    zoom: 10,
    minZoom: 5,
    maxZoom: 18
  },
  controller: true
});

Дополнительный контроль можно реализовать через onViewStateChange.

onViewStateChange: ({viewState}) => {
  viewState.longitude = Math.max(
    -180,
    Math.min(180, viewState.longitude)
  );

  return viewState;
}

Подобная техника применяется для ограничения камеры территорией страны, города или промышленного объекта.


Плавное перемещение камеры

Резкое изменение координат ухудшает восприятие визуализации. Deck.gl поддерживает анимированные переходы.

Простейший пример:

deck.setProps({
  viewState: {
    longitude: 2.3522,
    latitude: 48.8566,
    zoom: 12,
    transitionDuration: 3000
  }
});

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


Интерполяторы переходов

Для управления характером анимации используются специальные интерполяторы.

Наиболее популярный вариант — FlyToInterpolator.

import {FlyToInterpolator} from '@deck.gl/core';

Использование:

deck.setProps({
  viewState: {
    longitude: 139.6917,
    latitude: 35.6895,
    zoom: 13,
    transitionInterpolator:
      new FlyToInterpolator(),
    transitionDuration: 4000
  }
});

Эффект напоминает перелёт камеры между точками на карте.


Fly-To анимация

Технология Fly-To автоматически рассчитывает:

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

Пример:

{
  longitude: -74.006,
  latitude: 40.7128,
  zoom: 14,
  transitionInterpolator:
    new FlyToInterpolator(),
  transitionDuration: 'auto'
}

При значении "auto" длительность вычисляется автоматически на основе расстояния между точками.


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

Настройка времени выполняется через:

transitionDuration

Пример:

{
  transitionDuration: 2000
}

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

Для сложных презентационных визуализаций используются интервалы от 3 до 8 секунд.


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

Deck.gl поддерживает несколько независимых viewport одновременно.

Пример конфигурации:

views: [
  new MapView({
    id: 'main'
  }),

  new MapView({
    id: 'mini'
  })
]

Для каждого представления задаётся собственное состояние камеры.

viewState: {
  main: {
    longitude: 37,
    latitude: 55,
    zoom: 10
  },

  mini: {
    longitude: 37,
    latitude: 55,
    zoom: 4
  }
}

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

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

Класс View

Абстракция View описывает правила построения viewport.

Базовый импорт:

import {
  MapView
} from '@deck.gl/core';

Создание:

const view = new MapView({
  repeat: true
});

Каждый объект View отвечает за:

  • тип проекции;
  • размеры области отображения;
  • положение внутри canvas;
  • параметры камеры.

MapView

Наиболее распространённый тип представления.

new MapView()

Подходит для:

  • OpenStreetMap;
  • MapLibre;
  • Mapbox;
  • геопространственных слоёв Deck.gl.

Пример:

views: new MapView()

FirstPersonView

Режим обзора от первого лица.

Импорт:

import {
  FirstPersonView
} from '@deck.gl/core';

Создание:

views: new FirstPersonView()

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

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

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


OrbitView

OrbitView применяется для просмотра объектов со всех сторон.

import {
  OrbitView
} from '@deck.gl/core';
views: new OrbitView()

Камера вращается вокруг центральной точки сцены.

Типичные области применения:

  • CAD-системы;
  • научная визуализация;
  • трёхмерные модели;
  • цифровые двойники объектов.

OrthographicView

Ортографическая проекция исключает перспективные искажения.

import {
  OrthographicView
} from '@deck.gl/core';
views: new OrthographicView()

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

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

Подходит для инженерных схем и аналитических панелей.


Viewport и преобразование координат

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

Основные этапы:

Географические координаты
           ↓
Мировые координаты
           ↓
Координаты камеры
           ↓
Экранные координаты

В результате объект:

[37.6176, 55.7558]

может быть отображён в конкретной точке canvas:

[512, 348]

Именно viewport отвечает за подобное преобразование.


Получение текущего viewport

Доступ к активному viewport можно получить через объект Deck.

const viewport =
  deck.getViewports()[0];

Полученный экземпляр содержит:

viewport.width
viewport.height
viewport.zoom
viewport.latitude
viewport.longitude

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


Преобразование координат в экранные пиксели

Метод:

viewport.project()

Преобразует координаты карты в координаты экрана.

const pixel =
  viewport.project([
    37.6176,
    55.7558
  ]);

Результат:

[524, 301]

Это полезно при интеграции пользовательских HTML-элементов поверх canvas.


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

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

viewport.unproject()

Пример:

const coordinates =
  viewport.unproject([
    500,
    300
  ]);

Результат:

[
  37.6176,
  55.7558
]

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


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

Нередко требуется отображать несколько карт с общей камерой.

Пример общего состояния:

const sharedViewState = {
  longitude: 37.6176,
  latitude: 55.7558,
  zoom: 10
};

Обе визуализации используют один объект:

<DeckGL
  viewState={sharedViewState}
/>

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

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


Практические рекомендации

Для обычных картографических приложений

controller: true
initialViewState: {...}

Для React-приложений

viewState
onViewStateChange

Для презентационных сценариев

FlyToInterpolator
transitionDuration

Для многовидовых интерфейсов

views
viewState

Для точного контроля навигации

minZoom
maxZoom
onViewStateChange

Грамотное управление камерой и viewport является фундаментом любой интерактивной визуализации в Deck.gl. Именно эти механизмы определяют способ перемещения по данным, плавность навигации, корректность преобразования координат и качество взаимодействия пользователя с двумерными и трёхмерными сценами.