Получение данных из тайлов

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

Тайлы векторного типа представляют собой бинарные фрагменты (обычно формата MVT — Mapbox Vector Tile), содержащие геометрию и атрибуты объектов. Каждый тайл описывает фиксированную область мира в координатной системе плитки (z/x/y).

Источники данных задаются в стиле карты через sources:

map.addSource('cities', {
  type: 'vector',
  tiles: [
    'https://example.com/tiles/{z}/{x}/{y}.pbf'
  ],
  minzoom: 0,
  maxzoom: 14
});

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

  • tiles — шаблон URL для загрузки тайлов
  • minzoom / maxzoom — диапазон уровней детализации
  • type — тип источника (vector, raster, geojson и др.)

Система Mapbox GL JS интерпретирует {z}/{x}/{y} как координаты тайла в глобальной пирамиде.

Жизненный цикл тайла внутри Mapbox GL JS

При изменении состояния карты (панорамирование, масштабирование) происходит пересчет видимой области. Далее выполняется:

  1. Определение необходимых тайлов по текущему viewport
  2. Проверка кэша уже загруженных тайлов
  3. Запрос отсутствующих тайлов через сеть
  4. Декодирование бинарного формата PBF
  5. Передача данных в Web Worker для обработки
  6. Триангуляция и подготовка геометрии для WebGL

Каждый тайл разбивается на слои внутри векторного источника. Эти слои соответствуют логическим наборам данных (например, roads, buildings, water).

Координатная система тайлов

Векторные тайлы используют координатную систему с фиксированным экстентом, чаще всего 4096 единиц на сторону:

  • (0, 0) — левый верхний угол тайла
  • (4096, 4096) — правый нижний угол

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

Mapbox GL JS преобразует географические координаты в координаты тайла через проекцию Web Mercator.

Запрос данных из уже загруженных тайлов

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

queryRenderedFeatures

Этот метод извлекает данные, которые уже попали в текущий рендеринг WebGL:

map.on('click', (e) => {
  const features = map.queryRenderedFeatures(e.point, {
    layers: ['cities-layer']
  });

  console.log(features);
});

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

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

Параметр point соответствует пиксельной координате внутри canvas, а не географической.

Также возможно запросить область:

const features = map.queryRenderedFeatures([
  [0, 0],
  [300, 300]
]);

Запрос исходных данных тайлов

Для получения данных до стадии рендеринга используется querySourceFeatures:

const features = map.querySourceFeatures('cities', {
  sourceLayer: 'urban_areas'
});

Отличие от рендеренного запроса:

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

Важно учитывать, что querySourceFeatures работает только с уже загруженными тайлами и не инициирует сетевые запросы.

Слои внутри векторных тайлов

Векторный тайл содержит набор слоёв, определённых на стороне генерации данных. Каждый слой имеет:

  • имя (например, roads)
  • геометрию (Point, LineString, Polygon)
  • свойства (properties)

Пример обращения к слою:

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

Фильтрация данных тайлов

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

Фильтр слоя

map.setFilter('roads-line', ['==', ['get', 'type'], 'highway']);

Фильтрация при запросе

map.queryRenderedFeatures(e.point, {
  layers: ['roads-line'],
  filter: ['==', ['get', 'class'], 'primary']
});

Фильтры используют expression language Mapbox Style Specification.

Feature State и связь с тайлами

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

map.setFeatureState(
  { source: 'cities', id: 123 },
  { selected: true }
);

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

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

Для корректной работы требуется наличие promoteId или id в данных источника.

Идентификаторы объектов и оптимизация доступа

Для эффективной работы с тайловыми данными важно наличие стабильных идентификаторов:

map.addSource('cities', {
  type: 'vector',
  tiles: ['https://example.com/{z}/{x}/{y}.pbf'],
  promoteId: 'id'
});

Без идентификаторов невозможно корректно использовать feature-state и оптимизированные обновления.

Границы и пересечение тайлов

При запросе данных Mapbox GL JS учитывает пересечение тайлов с viewport. Геометрия может быть разбита между несколькими тайлами, поэтому один и тот же объект может появляться в нескольких запросах.

Для обработки таких случаев:

  • используются объединённые идентификаторы
  • применяется дедупликация по id
  • учитывается zoom level при агрегации

Особенности работы с растровыми тайлами

Хотя основное внимание уделяется векторным данным, растровые тайлы также участвуют в системе:

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

В отличие от векторных, растровые тайлы:

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

Кэширование тайлов

Mapbox GL JS использует многоуровневый кэш:

  • сетевой кэш браузера
  • внутренний кэш тайлов
  • кэш геометрии в Web Worker

Это позволяет:

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

При повторном посещении области тайлы часто берутся из памяти без сетевого запроса.

Взаимодействие с Web Workers

Обработка тайловых данных вынесена в отдельные потоки:

  • декодирование PBF
  • генерация геометрии
  • подготовка буферов для WebGL

Основной поток отвечает только за управление состоянием карты и пользовательские события.

Географические запросы и экранные координаты

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

const lngLat = map.unproject([x, y]);
const point = map.project([lng, lat]);

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

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

При изменении источника данных:

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

или при вызове:

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

происходит перерасчет тайлового дерева и перезагрузка затронутых областей.

Влияние уровня масштабирования на данные

Каждый уровень zoom определяет плотность и детализацию данных:

  • низкий zoom — агрегированные объекты
  • средний zoom — региональные структуры
  • высокий zoom — детализированная геометрия

Источник может возвращать разные наборы данных в зависимости от {z} в URL шаблоне.

Работа с перекрывающимися тайлами и приоритетами

При отрисовке нескольких источников важен порядок слоёв:

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

Это позволяет комбинировать несколько наборов тайлов в единую карту.

Ограничения работы с тайловыми данными

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

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