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

В MapLibre GL JS интерфейс управления картой построен вокруг модульной системы контролов, которые добавляются в фиксированные зоны контейнера карты. Каждый контрол реализует интерфейс IControl и интегрируется в DOM карты через единый механизм addControl.

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

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

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

Ключевая особенность: система не использует абсолютные координаты или grid-раскладку. Вместо этого применяется предсказуемая композиция DOM-узлов с управляемым порядком вставки.


API добавления и управления позиционированием

Основной механизм интеграции контролов реализуется через метод:

map.addControl(control, position)

Параметры:

  • control — объект, реализующий интерфейс IControl
  • position — строка одной из четырёх допустимых зон

Пример размещения навигационного контрола:

map.addControl(new maplibregl.NavigationControl(), 'top-right');

Повторное добавление контролов в одну и ту же зону приводит к их вертикальному стеку в порядке регистрации.

Удаление выполняется через:

map.removeControl(control)

Контрол удаляется из DOM независимо от позиции, так как связь хранится на уровне экземпляра.


Структура DOM-контейнеров контролов

Каждая зона создаёт отдельный контейнер с классами:

  • maplibregl-ctrl-top-left
  • maplibregl-ctrl-top-right
  • maplibregl-ctrl-bottom-left
  • maplibregl-ctrl-bottom-right

Внутри располагаются группы:

maplibregl-ctrl-group

Эта структура обеспечивает единообразие визуального стиля и позволяет применять глобальные CSS-правила без привязки к конкретным контролам.

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

  • порядок элементов соответствует порядку добавления
  • новые контролы добавляются либо сверху, либо снизу в зависимости от зоны
  • элементы группируются в отдельные блоки при необходимости (например, NavigationControl)

Встроенные контролы и их стандартные позиции

Контрол масштабирования и вращения карты. Обычно размещается в верхнем правом углу:

map.addControl(new maplibregl.NavigationControl(), 'top-right');

Функции:

  • zoom in / zoom out
  • rotation reset
  • tilt управление (если поддерживается)

GeolocateControl

Контрол геолокации пользователя:

map.addControl(new maplibregl.GeolocateControl(), 'top-right');

Часто группируется с навигацией, образуя единый стек интерактивных элементов.


ScaleControl

Масштабная линейка чаще размещается в нижних зонах:

map.addControl(new maplibregl.ScaleControl(), 'bottom-left');

Причина размещения — минимизация визуального конфликта с основными элементами управления.


AttributionControl

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

map.addControl(new maplibregl.AttributionControl(), 'bottom-right');

Также может быть отключён через параметры и заменён кастомной реализацией.


Порядок наложения и приоритеты

Контролы внутри одной зоны имеют строгую последовательность DOM-вставки:

  1. первый добавленный элемент располагается выше (или ниже — зависит от зоны)
  2. каждый последующий занимает следующую позицию в стеке

Приоритеты визуального наложения определяются не z-index контролов напрямую, а структурой контейнера и CSS-контекстом карты.

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

  • зоны не пересекаются по умолчанию
  • перекрытие возможно только при кастомных стилях
  • порядок добавления критичен для UX-композиции

Позиционирование через конфигурацию карты

Некоторые контролы могут быть заданы при инициализации карты через опции:

const map = new maplibregl.Map({
  container: 'map',
  style: 'style.json',
  attributionControl: false
});

Далее контрол добавляется вручную:

map.addControl(new maplibregl.AttributionControl(), 'bottom-right');

Это позволяет централизованно управлять интерфейсом без автоматических вставок.


Кастомные контролы и интерфейс IControl

Контролы в MapLibre GL JS не ограничены встроенными компонентами. Любой объект, реализующий интерфейс:

  • onAdd(map)
  • onRemove()
  • getDefaultPosition() (опционально)

может быть интегрирован в систему позиционирования.

Пример структуры:

class CustomControl {
  onAdd(map) {
    this._map = map;
    this._container = document.createElement('div');
    this._container.className = 'maplibregl-ctrl maplibregl-ctrl-group';
    this._container.textContent = 'Custom';
    return this._container;
  }

  onRemove() {
    this._container.parentNode.removeChild(this._container);
    this._map = undefined;
  }
}

Добавление:

map.addControl(new CustomControl(), 'top-left');

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

Система контролов опирается на набор базовых CSS-классов:

  • maplibregl-ctrl
  • maplibregl-ctrl-group
  • контейнеры зон

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

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

При необходимости возможно переопределение:

.maplibregl-ctrl-top-right {
  margin-top: 20px;
}

или изменение поведения групп:

.maplibregl-ctrl-group {
  border-radius: 8px;
}

Комбинирование контролов в одной зоне

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

  • сокращения визуального шума
  • логического объединения функций
  • унификации UX

Пример:

map.addControl(new maplibregl.NavigationControl(), 'top-right');
map.addControl(new maplibregl.GeolocateControl(), 'top-right');
map.addControl(new maplibregl.FullscreenControl(), 'top-right');

Результат — вертикальный стек интерактивных элементов в одной зоне, управляемый порядком добавления.


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

Контрол может быть перемещён только через удаление и повторное добавление:

map.removeControl(control);
map.addControl(control, 'bottom-left');

Внутреннего метода setPosition не предусмотрено, что делает модель предсказуемой и исключает побочные эффекты перерасчёта DOM.


Ограничения модели позиционирования

Система контролов имеет ряд архитектурных ограничений:

  • фиксированное число зон (4)
  • отсутствие свободной координатной сетки
  • невозможность частичного перекрытия без кастомного CSS
  • зависимость порядка от последовательности добавления

Эти ограничения компенсируются стабильностью DOM-структуры и предсказуемостью поведения интерфейса при изменении состояния карты.