Работа с данными

В Mapbox GL JS архитектура отображения карты строится вокруг концепции источников данных (sources) и слоёв (layers). Источник определяет, откуда поступают географические данные, а слой отвечает за их визуализацию. Разделение этих сущностей обеспечивает гибкость, масштабируемость и возможность динамического обновления карты без перерисовки всей сцены.

Основные типы источников:

  • GeoJSON — векторные данные в формате GeoJSON
  • Vector tiles — векторные тайлы Mapbox Vector Tile (MVT)
  • Raster tiles — растровые тайлы изображений
  • Image source — одиночные изображения с геопривязкой
  • Video source — видео, наложенное на географическую область
  • Canvas source — HTML canvas как источник данных

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


Регистрация источников через addSource

Добавление источника выполняется через метод карты:

map.addSource('cities', {
  type: 'geojson',
  data: {
    type: 'FeatureCollection',
    features: []
  }
});

Ключевые параметры:

  • type — тип источника
  • data — данные (для GeoJSON)
  • url — ссылка на удалённый ресурс (например, tileset или GeoJSON-файл)
  • tiles — массив URL-шаблонов тайлов (для vector/raster sources)
  • cluster — включение кластеризации (GeoJSON)

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


GeoJSON как основной формат динамических данных

GeoJSON используется для интерактивных и часто обновляемых данных: маркеры, события, пользовательские объекты, аналитические слои.

Структура GeoJSON:

{
  type: "Feature",
  geometry: {
    type: "Point",
    coordinates: [30.5, 50.5]
  },
  properties: {
    name: "Object A"
  }
}

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

map.getSource('cities').setData(newData);

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

  • полная замена набора данных
  • автоматический ре-рендер связанных слоёв
  • выполнение в Web Worker для минимизации блокировки UI

Векторные тайлы и масштабируемые наборы данных

Vector tiles обеспечивают высокую производительность при работе с большими датасетами. Данные разбиваются на квадраты (тайлы), загружаемые по мере необходимости.

Пример подключения:

map.addSource('roads', {
  type: 'vector',
  url: 'mapbox://examples.road-tiles'
});

Использование:

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

Ключевое свойство source-layer определяет слой внутри тайлсета.


Растровые источники

Raster sources применяются для отображения изображений, спутниковых снимков и тепловых карт.

map.addSource('satellite', {
  type: 'raster',
  tiles: [
    'https://tiles.example.com/{z}/{x}/{y}.png'
  ],
  tileSize: 256
});

Параметр tileSize влияет на масштабирование и производительность.


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

Обновление данных является ключевым механизмом интерактивных приложений. GeoJSON-источники позволяют изменять содержимое без пересоздания слоя.

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

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

При обновлении:

  • сохраняются стили слоёв
  • пересчитываются выражения (expressions)
  • выполняется дифференциальный рендеринг

Кластеризация данных

GeoJSON поддерживает встроенную кластеризацию, оптимизирующую отображение больших наборов точек.

map.addSource('points', {
  type: 'geojson',
  data: pointsData,
  cluster: true,
  clusterMaxZoom: 14,
  clusterRadius: 50
});

Параметры:

  • clusterMaxZoom — максимальный зум для группировки
  • clusterRadius — радиус кластеризации в пикселях

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

map.addLayer({
  id: 'clusters',
  type: 'circle',
  source: 'points',
  filter: ['has', 'point_count']
});

Фильтрация данных на уровне слоёв

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

map.addLayer({
  id: 'cities-layer',
  type: 'circle',
  source: 'cities',
  filter: ['>', ['get', 'population'], 1000000]
});

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

  • ['==', key, value]
  • ['!=', key, value]
  • ['>', value1, value2]
  • ['all', ...]
  • ['any', ...]

Фильтрация выполняется на GPU-ориентированном этапе подготовки данных.


Выражения (Expressions) и data-driven styling

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

paint: {
  'circle-radius': [
    'interpolate',
    ['linear'],
    ['get', 'mag'],
    1, 5,
    10, 20
  ],
  'circle-color': [
    'case',
    ['>', ['get', 'mag'], 5],
    '#f00',
    '#0f0'
  ]
}

Ключевые категории выражений:

  • математические (+, -, *, /)
  • условные (case, match)
  • интерполяционные (interpolate)
  • доступ к данным (get, has)
  • работа с массивами и строками

Обновление геометрии без перезагрузки слоя

Mapbox GL JS позволяет изменять только геометрию или свойства объектов:

const data = map.getSource('cities');
data.setData({
  type: 'FeatureCollection',
  features: [
    {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [10, 10]
      },
      properties: {
        id: 1
      }
    }
  ]
});

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


Использование URL-источников и удалённых данных

Источники могут ссылаться на удалённые GeoJSON-файлы:

map.addSource('earthquakes', {
  type: 'geojson',
  data: 'https://example.com/earthquakes.geojson'
});

При загрузке:

  • выполняется кэширование запроса
  • данные проходят валидацию
  • создаётся внутренний индекс пространственного поиска

Производительность при работе с большими наборами данных

При работе с тысячами и миллионами объектов важны следующие оптимизации:

  • использование vector tiles вместо GeoJSON
  • включение кластеризации для точек
  • минимизация количества слоёв
  • использование фильтров вместо предобработки данных
  • упрощение геометрии (simplification)

GeoJSON остаётся удобным, но не масштабируется так же эффективно, как тайловые источники.


Связь источников и слоёв

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

map.addLayer({
  id: 'layer-id',
  type: 'fill',
  source: 'source-id'
});

Один источник может использоваться несколькими слоями одновременно. Это позволяет:

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

Обновление свойств источников

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

map.getSource('tiles').setTiles([
  'https://new-url/{z}/{x}/{y}.pbf'
]);

Для GeoJSON аналогом является setData, который заменяет содержимое полностью.


Canvas и Image sources для нестандартных сценариев

Canvas source:

map.addSource('custom-canvas', {
  type: 'canvas',
  canvas: 'canvas-id',
  coordinates: [
    [0, 0],
    [10, 0],
    [10, 10],
    [0, 10]
  ]
});

Image source:

map.addSource('overlay', {
  type: 'image',
  url: 'overlay.png',
  coordinates: [
    [-10, 10],
    [10, 10],
    [10, -10],
    [-10, -10]
  ]
});

Такие источники применяются для тепловых карт, спутниковых слоёв и кастомных визуализаций.


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

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

  • sourcedata
  • data
  • dataloading

Пример обработки загрузки:

map.on('data', (e) => {
  if (e.sourceId === 'cities') {
    // обработка обновления данных
  }
});

События позволяют синхронизировать внешние системы с состоянием карты.