Интеграция с Mapbox

Mapbox GL JS представляет собой низкоуровневую библиотеку для рендеринга интерактивных карт на основе WebGL. Она тесно связана с экосистемой Mapbox и использует векторные тайлы, стили Mapbox Style Specification и GPU-ускоренный рендеринг для работы с большими наборами геоданных.

Интеграция начинается с подключения библиотеки и стилей:

<link href="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.js"></script>

Контейнер под карту должен иметь фиксированную высоту, иначе WebGL-контекст не будет отображён:

<div id="map" style="width: 100%; height: 600px;"></div>

Ключевой элемент — access token. Он используется для авторизации запросов к API Mapbox:

mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';

Инициализация карты и конфигурация состояния

Создание карты выполняется через конструктор Map:

const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v12',
  center: [69.2401, 53.2145],
  zoom: 10
});

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

  • container — DOM-элемент или его id
  • style — URL стиля Mapbox
  • center — начальные координаты [долгота, широта]
  • zoom — уровень приближения

Важный момент архитектуры Mapbox GL JS — асинхронная загрузка стиля. Все операции добавления слоёв должны выполняться после события load:

map.on('load', () => {
  // безопасное добавление источников и слоёв
});

Стили Mapbox и система визуализации

Стили в Mapbox GL JS описываются через JSON-конфигурацию Mapbox Style Specification. Они включают источники данных, слои, фильтры и визуальные свойства.

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

map.setStyle('mapbox://styles/mapbox/light-v11');

Система стилей основана на концепции слоёв:

  • fill — заливка полигонов
  • line — линии дорог и маршрутов
  • symbol — подписи и иконки
  • circle — точечные данные
  • raster — растровые тайлы

Каждый слой связан с источником данных (source), что делает архитектуру строго разделённой.

Работа с источниками данных (Sources)

Mapbox использует векторные и растровые источники. Наиболее гибкий вариант — GeoJSON:

map.addSource('points', {
  type: 'geojson',
  data: {
    type: 'FeatureCollection',
    features: [
      {
        type: 'Feature',
        geometry: {
          type: 'Point',
          coordinates: [69.2401, 53.2145]
        },
        properties: {
          title: 'Объект'
        }
      }
    ]
  }
});

Источник сам по себе не отображается — он становится видимым только после добавления слоя:

map.addLayer({
  id: 'points-layer',
  type: 'circle',
  source: 'points',
  paint: {
    'circle-radius': 8,
    'circle-color': '#ff5500'
  }
});

Добавление и управление слоями

Слои формируют визуальную структуру карты. Порядок слоёв критически важен, так как они отрисовываются сверху вниз.

Добавление слоя:

map.addLayer({
  id: 'roads',
  type: 'line',
  source: 'composite',
  'source-layer': 'road',
  paint: {
    'line-color': '#888',
    'line-width': 2
  }
});

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

  • setLayoutProperty — изменение структуры отображения
  • setPaintProperty — изменение визуального стиля
  • moveLayer — изменение порядка

Пример динамического изменения прозрачности:

map.setPaintProperty('roads', 'line-opacity', 0.5);

События карты и реактивное поведение

Mapbox GL JS активно использует событийную модель. Основные события:

  • load — завершение загрузки стиля
  • move — изменение положения карты
  • click — взаимодействие с объектами
  • zoom — изменение масштаба

Пример обработки клика по карте:

map.on('click', (e) => {
  console.log(e.lngLat);
});

Обработка клика по слоям:

map.on('click', 'points-layer', (e) => {
  const feature = e.features[0];
  console.log(feature.properties.title);
});

Интеграция с геокодингом Mapbox

Геокодинг позволяет преобразовывать адреса в координаты и обратно. Обычно используется Mapbox Geocoding API.

Пример запроса:

fetch(`https://api.mapbox.com/geocoding/v5/mapbox.places/karaganda.json?access_token=${mapboxgl.accessToken}`)
  .then(res => res.json())
  .then(data => {
    console.log(data.features);
  });

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

map.flyTo({
  center: data.features[0].center,
  zoom: 12
});

Маршрутизация и Directions API

Mapbox Directions API позволяет строить маршруты между точками.

Пример запроса маршрута:

fetch(`https://api.mapbox.com/directions/v5/mapbox/driving/69.2401,53.2145;69.1629,53.2833?geometries=geojson&access_token=${mapboxgl.accessToken}`)
  .then(res => res.json())
  .then(data => {
    const route = data.routes[0].geometry;
  });

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

map.addSource('route', {
  type: 'geojson',
  data: {
    type: 'Feature',
    geometry: route
  }
});

map.addLayer({
  id: 'route-line',
  type: 'line',
  source: 'route',
  paint: {
    'line-color': '#1db7dd',
    'line-width': 4
  }
});

Работа с всплывающими окнами (Popup) и маркерами

Маркер — базовый объект интерфейса:

const marker = new mapboxgl.Marker()
  .setLngLat([69.2401, 53.2145])
  .addTo(map);

Popup используется для отображения информации:

const popup = new mapboxgl.Popup()
  .setLngLat([69.2401, 53.2145])
  .setHTML('<h3>Объект</h3><p>Описание точки</p>')
  .addTo(map);

Связка маркера и popup:

new mapboxgl.Marker()
  .setLngLat([69.2401, 53.2145])
  .setPopup(popup);

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

Mapbox GL JS поддерживает обновление источников без перерисовки всей карты:

const source = map.getSource('points');

source.setData({
  type: 'FeatureCollection',
  features: updatedFeatures
});

Этот механизм позволяет реализовать:

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

Фильтрация и условная визуализация

Фильтры применяются на уровне слоёв:

map.setFilter('points-layer', ['==', 'type', 'restaurant']);

Поддерживаются логические операторы:

  • ==, !=
  • >, <, >=, <=
  • in, all, any

Пример сложного фильтра:

map.setFilter('points-layer', [
  'all',
  ['==', 'type', 'restaurant'],
  ['>', 'rating', 4]
]);

Использование кастомных стилей и тем

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

map.setStyle({
  version: 8,
  sources: {},
  layers: []
});

Кастомные стили позволяют:

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

Оптимизация производительности

Mapbox GL JS использует WebGL, но требует соблюдения практик оптимизации:

  • ограничение количества активных слоёв
  • использование векторных тайлов вместо GeoJSON при больших данных
  • упрощение геометрии
  • кэширование источников

Для больших наборов данных предпочтительны vector tiles:

map.addSource('tiles', {
  type: 'vector',
  url: 'mapbox://mapbox.mapbox-streets-v8'
});

Взаимодействие с DOM и внешними библиотеками

Mapbox GL JS не изолирован от DOM-логики приложения. Он легко интегрируется с UI-фреймворками:

  • обновление состояния React/Vue через события карты
  • синхронизация координат с формами
  • подключение сторонних графиков и аналитики

Пример синхронизации:

map.on('move', () => {
  const center = map.getCenter();
  updateUI(center);
});

Работа с камерой и анимацией

Камера управляет перспективой и положением:

map.flyTo({
  center: [69.2401, 53.2145],
  zoom: 14,
  speed: 1.2
});

Дополнительные методы:

  • easeTo — плавное перемещение
  • jumpTo — мгновенное изменение
  • fitBounds — подгонка под область

Пример адаптации под границы:

map.fitBounds([
  [68.9, 53.1],
  [69.5, 53.4]
]);

Контроль состояния и синхронизация слоёв

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

  • хранение конфигурации слоёв
  • синхронизация с URL
  • восстановление состояния после перезагрузки

Пример сериализации состояния:

const state = {
  center: map.getCenter(),
  zoom: map.getZoom()
};

Интеграция с внешними данными и API

Mapbox GL JS часто используется как визуальный слой поверх:

  • GIS-систем
  • аналитических API
  • потоков IoT данных
  • серверов геоданных

Типичный паттерн — сервер отдаёт GeoJSON, клиент отображает:

fetch('/api/points')
  .then(res => res.json())
  .then(data => {
    map.getSource('points').setData(data);
  });

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