Rotate

В OpenLayers вращение карты реализуется на уровне представления (View) и дополняется набором интеракций и UI-контролов. Базовая сущность — свойство rotation, задающее угол поворота карты в радианах. Вся система взаимодействий строится вокруг преобразования координат и матрицы отображения слоя.

Модель вращения View

Ключевым элементом является объект представления карты:

import View from 'ol/View';

const view = new View({
  center: [0, 0],
  zoom: 2,
  rotation: 0
});

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

Изменение вращения динамически:

view.setRotation(Math.PI / 4);

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

const angle = view.getRotation();

Внутренне OpenLayers применяет аффинные преобразования к canvas/WebGL контексту, сохраняя географические координаты неизменными и вращая только визуальное представление.


Ограничения и нормализация угла

Вращение нормализуется внутри диапазона [-2π, 2π], однако логически удобнее работать в пределах [-π, π]. Это особенно важно при вычислениях пользовательского взаимодействия.

function normalizeRotation(angle) {
  return ((angle + Math.PI) % (2 * Math.PI)) - Math.PI;
}

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


Интеракция DragRotate

Интеракция DragRotate позволяет вращать карту при зажатой модифицирующей клавише (по умолчанию Alt + левый клик мыши).

import DragRotate from 'ol/interaction/DragRotate';

const dragRotate = new DragRotate();
map.addInteraction(dragRotate);

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

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

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

Интеракция PinchRotate

Для сенсорных устройств используется PinchRotate, реализующий вращение двумя пальцами.

import PinchRotate from 'ol/interaction/PinchRotate';

const pinchRotate = new PinchRotate();
map.addInteraction(pinchRotate);

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

Ключевые особенности:

  • работа через touch-события;
  • вычисление угла между касаниями;
  • синхронизация с масштабированием (часто используется вместе с pinch zoom);
  • сглаживание резких изменений угла.

Контрол Rotate (UI-кнопка вращения)

UI-компонент вращения реализуется через ol/control/Rotate. Он предоставляет кнопку сброса вращения или плавного возврата к нулевому углу.

import Rotate from 'ol/control/Rotate';

const rotateControl = new Rotate({
  autoHide: false,
  label: '↻',
  resetNorth: () => {
    view.animate({
      rotation: 0,
      duration: 300
    });
  }
});

map.addControl(rotateControl);

Поведение по умолчанию:

  • отображение кнопки при отклонении от нулевого угла;
  • плавный возврат к северу;
  • скрытие при отсутствии вращения (опционально).

Анимация вращения

Плавное вращение реализуется через механизм view.animate, использующий интерполяцию значений.

view.animate({
  rotation: Math.PI,
  duration: 1000
});

Анимация работает через линейную или easing-интерполяцию, обеспечивая непрерывное изменение угла. При этом учитывается кратчайший путь вращения (по часовой или против часовой стрелки).


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

Изменение угла поворота сопровождается событием change:rotation.

view.on('change:rotation', () => {
  const current = view.getRotation();
});

Дополнительно доступно событие propertychange, позволяющее отслеживать любые изменения состояния View.


Влияние вращения на проекцию и координаты

Вращение не изменяет географическую проекцию, но влияет на экранные координаты. Все вычисления пересчёта выполняются через матрицу преобразования:

  • географические координаты → проекционные;
  • проекционные → экранные с учётом rotation;
  • применение обратного преобразования при событиях мыши.

Это критично для корректной работы взаимодействий, таких как:

  • выбор объектов;
  • кластеризация в экранных координатах;
  • измерения расстояний на экране.

Сочетание вращения с другими взаимодействиями

В OpenLayers взаимодействия комбинируются, что позволяет создавать сложные жесты:

  • DragPan + DragRotate
  • MouseWheelZoom + фиксированный rotation
  • PinchZoom + PinchRotate

Конфликты жестов решаются через приоритеты интеракций и условия активации (например, модификатор клавиши).


Стабилизация вращения и ограничения

Для предотвращения неконтролируемого вращения применяются ограничения:

import {defaults as defaultInteractions} from 'ol/interaction';

const map = new Map({
  interactions: defaultInteractions({
    altShiftDragRotate: false,
    pinchRotate: true
  })
});

Отключение или настройка стандартных интеракций позволяет контролировать UX, особенно в приложениях навигационного типа.


Производительность при вращении

Вращение карты приводит к перерасчёту всей сцены рендеринга. Производительность зависит от:

  • количества слоёв;
  • типа рендерера (Canvas/WebGL);
  • сложности стилей;
  • использования изображений высокого разрешения.

WebGL-рендерер значительно снижает стоимость поворота за счёт аппаратного ускорения, тогда как Canvas требует перерисовки каждого слоя.


Практика синхронизации состояния вращения

В сложных приложениях угол вращения часто синхронизируется с внешним состоянием:

view.on('change:rotation', () => {
  const state = {
    rotation: view.getRotation()
  };
});

Такой подход используется для:

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

Преобразования координат при вращении

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

map.getEventCoordinate(event);

Внутри выполняется:

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

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