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

Контролы в OpenLayers представляют собой независимые UI-компоненты, привязанные к карте и предназначенные для взаимодействия пользователя с визуализацией. Они не являются частью слоя данных и не участвуют в отрисовке геометрии — их задача ограничена интерфейсной логикой: масштабирование, полноэкранный режим, масштабная линейка, подписи атрибуции и пользовательские элементы управления.

Контролы реализуются через базовый класс ol/control/Control, который задаёт фундаментальную модель поведения: DOM-элемент, связанный с картой, и набор методов жизненного цикла (setMap, dispose, управление состоянием активности).


Базовый механизм размещения контролов

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

  • DOM-элемент (element) — визуальное представление
  • контейнер карты — специальная зона интерфейса, куда вставляется элемент

При добавлении на карту происходит следующее:

  1. Создаётся DOM-узел контролла
  2. Он помещается в контейнер контролов карты
  3. Контейнер позиционируется поверх карты через CSS

Контейнеры делятся на области:

  • ol-overlaycontainer-stopevent
  • ol-overlaycontainer
  • ol-control

Они обеспечивают корректное наложение UI поверх тайлов и геометрии.


Стандартные позиции контролов

OpenLayers использует CSS-классы для закрепления контролов в углах карты:

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

Каждый контрол при создании может быть помещён в одну из этих зон через параметр target или через управление коллекцией контролов карты.

Пример логики:

  • масштаб (Zoom) чаще располагается сверху слева
  • полноэкранный режим (FullScreen) — сверху справа
  • атрибуция (Attribution) — снизу справа
  • масштабная линейка (ScaleLine) — снизу слева

Параметр target и перенос контролов

Ключевой механизм позиционирования — свойство target.

Контрол может быть привязан не к стандартному контейнеру карты, а к произвольному DOM-элементу:

new Control({
  element: myElement,
  target: document.getElementById('sidebar')
});

В этом случае:

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

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

  • выноса панели инструментов за пределы карты
  • создания интерфейсов типа sidebar / toolbar
  • интеграции с UI-фреймворками

Управление коллекцией контролов карты

Контролы хранятся в коллекции:

map.getControls()

Коллекция поддерживает операции:

  • push() — добавление
  • remove() — удаление
  • clear() — очистка

Порядок в коллекции влияет на порядок DOM-элементов внутри контейнера, что косвенно влияет на визуальную компоновку (особенно при использовании flex или absolute-стилей).


Встроенные контролы и их размещение

OpenLayers поставляется с набором стандартных контролов:

Zoom

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

  • кнопки «+» и «−»
  • изменение zoom level карты

Позиционируется через CSS класс контейнера, обычно:

  • ol-zoom

FullScreen

Переключает карту в полноэкранный режим:

  • использует Fullscreen API браузера
  • требует поддержки document.fullscreenElement

ScaleLine

Отображает масштабную линейку:

  • автоматически пересчитывается при изменении разрешения
  • зависит от проекции карты

Attribution

Отображает копирайты и источники данных:

  • часто закреплён снизу справа
  • может быть сворачиваемым

CSS-модель позиционирования

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

.ol-control {
  position: absolute;
}

Каждый угол задаёт своё смещение:

.ol-top-left {
  top: 0;
  left: 0;
}

.ol-bottom-right {
  bottom: 0;
  right: 0;
}

Контролы внутри этих контейнеров выстраиваются вертикально или горизонтально в зависимости от CSS правил конкретного компонента.


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

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

import Control from 'ol/control/Control';

class MyControl extends Control {
  constructor(opt_options) {
    const button = document.createElement('button');
    button.innerHTML = 'X';

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

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

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

  • классом ol-control
  • родительским контейнером
  • параметром target (если используется)

Порядок отображения и стек наложения

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

  • порядок в коллекции влияет на DOM-последовательность
  • CSS z-index управляет перекрытием слоёв
  • контейнер карты имеет более высокий слой, чем тайлы

Важно учитывать:

  • элементы с pointer-events перехватывают взаимодействие
  • ol-overlaycontainer-stopevent блокирует события карты под контролом

Группировка и композиция контролов

Контролы могут быть объединены в логические блоки:

  • панель инструментов (zoom + rotate + fullscreen)
  • информационная панель (scale + attribution)
  • пользовательские наборы действий

Такое объединение достигается:

  • общим контейнером DOM
  • кастомным контролом-обёрткой
  • управлением коллекцией внутри одного элемента

Динамическое изменение позиции

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

  • перенос между top-left и top-right
  • переключение между встроенной зоной и target
  • условное отображение в зависимости от масштаба карты

Пример логики:

  • при малом масштабе контролы сворачиваются
  • при широком экране распределяются по углам
  • при мобильном режиме перемещаются в единый контейнер

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

Контролы получают доступ к карте через setMap:

  • подписка на события moveend, change:resolution
  • реакция на изменения центра и масштаба
  • обновление DOM при изменении состояния карты

Контейнер ol-overlaycontainer-stopevent предотвращает распространение событий на карту, обеспечивая независимое взаимодействие интерфейса.


Особенности адаптивного поведения

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

  • контролы не пересоздаются
  • пересчитываются только CSS-позиции
  • DOM остаётся стабильным

Это снижает нагрузку и позволяет использовать контролы в высокодинамичных интерфейсах (анимации, WebGL-слои, тайловая подгрузка).


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

Контролы могут быть скрыты без удаления:

  • через CSS display: none
  • через изменение класса состояния
  • через изменение opacity и pointer-events

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