Встроенные контролы

В Mapbox GL JS контролы представляют собой готовые элементы пользовательского интерфейса, которые добавляются прямо на карту и обеспечивают стандартные функции взаимодействия: навигацию, поиск, геолокацию, масштабирование, отображение атрибуции и переключение стилей. Контролы реализованы как независимые компоненты, подключаемые через API карты и работающие поверх WebGL-рендера.

Архитектура контролов унифицирована: каждый контрол реализует минимальный интерфейс с методами onAdd(map) и onRemove(), что позволяет интегрировать как встроенные, так и кастомные элементы управления.


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

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

map.addControl(control, position);

Где control — объект, реализующий интерфейс контроля, а position задаёт расположение на карте:

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

Пример добавления стандартного управления навигацией:

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

Каждый контрол автоматически помещается в контейнер карты и получает доступ к экземпляру map.


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

  • увеличение и уменьшение масштаба
  • вращение карты
  • наклон (pitch)
map.addControl(new mapboxgl.NavigationControl());

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

Контрол можно настроить:

const nav = new mapboxgl.NavigationControl({
  showZoom: true,
  showCompass: true,
  visualizePitch: true
});

map.addControl(nav);

showZoom отвечает за кнопки масштабирования, showCompass включает вращение и сброс направления, visualizePitch отображает управление наклоном.


GeolocateControl

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

map.addControl(new mapboxgl.GeolocateControl({
  positionOptions: {
    enableHighAccuracy: true
  },
  trackUserLocation: true
}));

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

Контрол поддерживает два основных режима:

  • Single position — получение одной точки
  • Tracking — постоянное обновление позиции

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

  • geolocate
  • trackuserlocationstart
  • trackuserlocationend
  • error
const geolocate = new mapboxgl.GeolocateControl();

geolocate.on('geolocate', (e) => {
  console.log(e.coords.latitude, e.coords.longitude);
});

FullscreenControl

Контрол полноэкранного режима переключает контейнер карты в fullscreen.

map.addControl(new mapboxgl.FullscreenControl());

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

  • использует Fullscreen API браузера
  • может применяться только к контейнеру карты
  • автоматически добавляет кнопку выхода из режима

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


ScaleControl

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

map.addControl(new mapboxgl.ScaleControl({
  maxWidth: 120,
  unit: 'metric'
}));

Поддерживаемые единицы

  • metric — метры и километры
  • imperial — футы и мили
  • nautical — морские мили

Динамическое обновление

Масштаб автоматически пересчитывается при:

  • изменении уровня zoom
  • перемещении карты
  • изменении широты (для корректного проекционного масштаба)

AttributionControl

Контрол атрибуции отображает обязательные ссылки на источники данных карты.

map.addControl(new mapboxgl.AttributionControl({
  compact: true
}));

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

  • expanded — полное отображение ссылок
  • compact — свернутый режим с раскрытием

Контрол является обязательным в большинстве случаев использования Mapbox GL JS, так как обеспечивает соблюдение лицензии данных.


LogoControl

Контрол логотипа отображает брендинг Mapbox в интерфейсе карты.

map.addControl(new mapboxgl.LogoControl());

В современных версиях SDK его поведение ограничено условиями лицензирования, и он часто интегрирован в AttributionControl.


Scale и единицы измерения в реальном времени

ScaleControl использует геодезические вычисления для отображения реальных расстояний на плоскости Web Mercator. Пересчёт происходит при каждом изменении состояния камеры карты.

Модель вычисления учитывает:

  • широту центра карты
  • текущий zoom
  • проекцию Mercator

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


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

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

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

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

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

В этом случае fullscreen-контрол окажется ниже навигационного.


Удаление контролов

Любой контрол можно удалить динамически:

map.removeControl(control);

Удаление вызывает:

  • вызов onRemove()
  • удаление DOM-элементов
  • освобождение ссылок на карту

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


Создание кастомного контрола

Интерфейс контролов предельно минимален:

class CustomControl {
  onAdd(map) {
    this.map = map;
    this.container = document.createElement('div');
    this.container.className = 'custom-control';
    this.container.textContent = 'Action';
    return this.container;
  }

  onRemove() {
    this.container.parentNode.removeChild(this.container);
    this.map = undefined;
  }
}

Добавление:

map.addControl(new CustomControl());

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

  • onAdd должен возвращать DOM-элемент
  • onRemove обязан освобождать ресурсы
  • доступ к карте сохраняется через ссылку this.map

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

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

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

Пример контролируемого изменения масштаба:

class ZoomControl {
  onAdd(map) {
    this.map = map;

    this.container = document.createElement('div');

    const btn = document.createElement('button');
    btn.textContent = 'Zoom +';

    btn.oncl ick = () => {
      this.map.zoomIn();
    };

    this.container.appendChild(btn);
    return this.container;
  }

  onRemove() {
    this.container.remove();
    this.map = undefined;
  }
}

Контролы и жизненный цикл карты

Контролы подключаются после создания карты и привязываются к её экземпляру.

const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v12'
});

map.on('load', () => {
  map.addControl(new mapboxgl.NavigationControl());
});

Хотя добавление возможно и до события load, большинство сложных контролов используют готовую структуру карты, которая становится доступной после инициализации.


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

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

  • NavigationControl изменяет camera state
  • GeolocateControl обновляет center и marker
  • ScaleControl реагирует на zoom
  • FullscreenControl изменяет контейнер rendering context

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


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

Контролы используют стандартные CSS классы Mapbox:

  • .mapboxgl-ctrl
  • .mapboxgl-ctrl-group
  • .mapboxgl-ctrl-icon

Переопределение стилей:

.mapboxgl-ctrl button {
  width: 36px;
  height: 36px;
}

Контролы можно полностью переоформить, сохраняя DOM-структуру.


Расположение контролов в адаптивных интерфейсах

В мобильных интерфейсах контролы часто перераспределяются:

  • уменьшается размер кнопок
  • отключается часть функций (например, compass)
  • используется compact-режим

ScaleControl и AttributionControl автоматически адаптируются к ширине экрана.


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

При изменении style (map.setStyle) все контролы сохраняются, но:

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

NavigationControl и FullscreenControl не зависят от стиля и продолжают работать без изменений.


Производительность контролов

Контролы практически не влияют на производительность карты, так как:

  • работают в DOM, а не в WebGL
  • не участвуют в рендеринге слоёв
  • реагируют только на события

Исключение составляют кастомные контролы с частыми обновлениями интерфейса или подписками на события move и render.


Расширенные сценарии использования контролов

Контролы часто используются как контейнеры для сложных UI-компонентов:

  • фильтры слоёв
  • таймлайны анимации данных
  • переключатели источников
  • панели аналитики

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