Стандартные контролы OpenLayers

В библиотеке OpenLayers интерфейс карты строится как композиция независимых контролов (controls), каждый из которых отвечает за отдельную функциональность взаимодействия пользователя с картой. Контролы представляют собой DOM-элементы, связанные с экземпляром карты и интегрированные в её жизненный цикл через механизм управления состоянием.

Контролы реализуются как классы, наследующие базовую структуру ol/control/Control, что обеспечивает единообразие поведения, подключение к карте и управление позиционированием в интерфейсе.

Архитектура контролов

Контроль в OpenLayers состоит из трёх ключевых компонентов:

  • DOM-элемент — визуальное представление
  • Логика поведения — обработка событий
  • Интеграция с картой — связь через API ol.Map

Каждый контрол создаётся как независимая единица, но управляется через коллекцию карты controls. Эта коллекция позволяет добавлять, удалять и переопределять стандартные элементы интерфейса.

Базовая структура:

import Control from 'ol/control/Control';

class CustomControl extends Control {
  constructor(options) {
    const button = document.createElement('button');
    button.innerHTML = 'C';

    const element = document.createElement('div');
    element.className = 'custom-control ol-unselectable ol-control';
    element.appendChild(button);

    super({
      element: element,
      target: options.target,
    });

    button.addEventListener('click', this.handleClick.bind(this), false);
  }

  handleClick() {
    console.log('Control activated');
  }
}

Контролы инкапсулируют поведение и не требуют прямого доступа к внутреннему состоянию карты, взаимодействуя через API экземпляра Map.


Контрол Zoom

Контрол увеличения и уменьшения масштаба реализован в модуле ol/control/Zoom. Он добавляет две кнопки: увеличение и уменьшение масштаба карты.

Поведение

  • Увеличивает или уменьшает zoom level
  • Работает с текущей view карты
  • Автоматически ограничивается диапазоном zoom

Конфигурация

import Zoom from 'ol/control/Zoom';

const map = new Map({
  target: 'map',
  controls: [
    new Zoom()
  ],
  view: new View({
    center: [0, 0],
    zoom: 2
  })
});

Особенности реализации

Контрол использует методы view.setZoom() и view.getZoom() для управления состоянием отображения. Каждое нажатие изменяет значение на ±1.


Контрол Rotate

Контрол поворота карты (ol/control/Rotate) предназначен для управления ориентацией карты относительно северного направления.

Основные функции

  • Сброс угла поворота
  • Визуальное отображение текущего угла
  • Плавная анимация возврата к нулевому углу

Пример использования

import Rotate from 'ol/control/Rotate';

const rotateControl = new Rotate({
  autoHide: false
});

const map = new Map({
  controls: [rotateControl]
});

Взаимодействие с View

Контрол работает через свойство rotation объекта View. Изменение угла происходит через:

view.setRotation(angleInRadians);

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


Контрол Attribution

Контрол ol/control/Attribution отображает информацию об источниках данных карты.

Назначение

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

Пример

import Attribution from 'ol/control/Attribution';

const map = new Map({
  controls: [
    new Attribution({
      collapsible: true
    })
  ]
});

Поведение

Контрол анализирует все активные слои карты и собирает их attributions. Эти данные могут поступать из:

  • TileLayer
  • VectorLayer
  • ImageLayer

Динамическое обновление происходит при изменении видимости слоёв.


Контрол FullScreen

Контрол ol/control/FullScreen управляет режимом полноэкранного отображения карты.

Возможности

  • Включение полноэкранного режима
  • Выход из полноэкранного режима
  • Поддержка API браузера Fullscreen

Пример

import FullScreen from 'ol/control/FullScreen';

const fullScreenControl = new FullScreen();

const map = new Map({
  controls: [fullScreenControl]
});

Техническая основа

Контрол использует стандартный Web API:

  • element.requestFullscreen()
  • document.exitFullscreen()

Состояние синхронизируется с картой через события изменения режима отображения.


Контрол ScaleLine

Контрол масштаба (ol/control/ScaleLine) отображает линейный масштаб карты.

Назначение

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

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

import ScaleLine from 'ol/control/ScaleLine';

const scaleLine = new ScaleLine({
  units: 'metric'
});

const map = new Map({
  controls: [scaleLine]
});

Режимы отображения

Поддерживаются следующие единицы:

  • метрические (metric)
  • имперские (imperial)
  • градусы (degrees)
  • nautical

Алгоритм расчёта

Контрол вычисляет масштаб на основе:

  • текущего resolution
  • проекции карты
  • географической широты

Формула пересчёта учитывает нелинейность Web Mercator проекции.


Контрол OverviewMap

Контрол ol/control/OverviewMap создаёт мини-карту, отображающую текущую область основного окна.

Функциональность

  • Отображение общей географии
  • Индикация текущего viewport
  • Перемещение основной карты через мини-карту

Пример

import OverviewMap from 'ol/control/OverviewMap';

const overview = new OverviewMap({
  collapsed: false
});

const map = new Map({
  controls: [overview]
});

Архитектурная особенность

OverviewMap содержит отдельный экземпляр Map, который синхронизируется с основным через события:

  • moveend
  • change:resolution
  • change:center

Таким образом реализуется двусторонняя связь между картами.


Контрол ZoomSlider

Контрол ol/control/ZoomSlider представляет вертикальный ползунок управления масштабом.

Особенности

  • Непрерывное изменение zoom
  • Поддержка drag-событий
  • Интерактивное позиционирование

Пример

import ZoomSlider from 'ol/control/ZoomSlider';

const map = new Map({
  controls: [
    new ZoomSlider()
  ]
});

Логика работы

Ползунок отображает диапазон zoom уровней и преобразует координату положения в значение масштаба:

  • верхняя точка — максимальный zoom
  • нижняя точка — минимальный zoom

Управление набором контролов

Коллекция контролов управляется через map.getControls():

const controls = map.getControls();

Добавление нового контрола:

controls.push(new FullScreen());

Удаление:

controls.removeAt(index);

Полная переинициализация:

const map = new Map({
  controls: defaultControls().extend([
    new ScaleLine()
  ])
});

Отключение стандартных контролов

По умолчанию OpenLayers добавляет набор базовых контролов через defaultControls().

Полное отключение:

import { defaults as defaultControls } from 'ol/control';

const map = new Map({
  controls: []
});

Частичное переопределение:

const map = new Map({
  controls: defaultControls({
    zoom: false,
    rotate: false
  })
});

Позиционирование контролов

Контролы размещаются в DOM через CSS-классы и параметр target.

Основные позиции:

  • ol-top-left
  • ol-top-right
  • ol-bottom-left
  • ol-bottom-right

Пример:

new FullScreen({
  className: 'custom-fullscreen-control'
});

Контролы используют абсолютное позиционирование внутри контейнера карты.


Взаимодействие контролов с событиями карты

Контролы подписываются на события карты:

  • click
  • pointermove
  • moveend
  • change:view

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

Пример подписки:

map.on('moveend', () => {
  console.log('map moved');
});

Контролы могут как инициировать изменения состояния, так и реагировать на них.


Создание кастомных контролов на основе стандартных паттернов

Стандартные контролы служат шаблоном для построения расширений интерфейса.

Типовой паттерн включает:

  1. Создание DOM-элемента
  2. Наследование Control
  3. Подключение событий
  4. Работа с Map и View

Пример контролла переключения слоя:

class LayerToggleControl extends Control {
  constructor(layer) {
    const button = document.createElement('button');
    button.innerText = 'Layer';

    const element = document.createElement('div');
    element.className = 'ol-control';
    element.appendChild(button);

    super({ element });

    button.addEventListener('click', () => {
      const visible = layer.getVisible();
      layer.setVisible(!visible);
    });
  }
}

Такой подход позволяет интегрировать пользовательские элементы в общую архитектуру интерфейса без нарушения внутренней логики библиотеки.