Система визуализации карты в Mapbox GL JS построена вокруг реактивного механизма отслеживания изменений состояния стиля, источников данных и параметров рендеринга. Любое изменение входных данных не приводит к полному пересозданию карты, вместо этого применяется дифференциальное обновление, затрагивающее только те части сцены, которые действительно изменились.
В основе архитектуры лежит модель неизменяемого стиля. Объект стиля рассматривается как структура, которая не модифицируется напрямую, а заменяется или обновляется через операции высокого уровня.
Изменение стиля инициируется через API:
map.setStyle('mapbox://styles/mapbox/streets-v12');
При вызове происходит:
Ключевая особенность заключается в том, что система не пересоздаёт всю сцену, а вычисляет минимальный набор операций для приведения текущего состояния к новому.
Каждый слой в стиле имеет уникальный идентификатор и набор свойств:
При изменении слоя:
map.setPaintProperty('water-layer', 'fill-color', '#00ffff');
движок выполняет:
Рендеринг всего кадра не блокируется; обновляется только часть GPU-пайплайна, связанная с изменённым свойством.
Источники (sources) являются ключевым триггером изменения сцены. Особенно это касается GeoJSON источников:
map.getSource('cities').setData(geojson);
При вызове setData происходит:
Векторные тайловые источники ведут себя иначе: изменение данных на уровне клиента отсутствует, а change detection сводится к обновлению тайлового кеша и запросу новых тайлов.
Expressions являются реактивным слоем между данными и визуализацией. Они позволяют динамически вычислять значения свойств на основе данных.
map.setPaintProperty('population', 'circle-radius', [
'interpolate',
['linear'],
['get', 'pop'],
0, 2,
1000, 10
]);
При изменении входных данных:
Это снижает стоимость recalculation при большом количестве объектов.
Внутренняя система change detection опирается на флаги состояния:
При любом изменении API вызывается цепочка маркировки:
Эта система предотвращает ненужные вычисления, ограничивая область обновления.
Mapbox GL JS использует событийно-ориентированный render loop. Полный непрерывный цикл отсутствует; рендеринг происходит только при наличии изменений.
Основной триггер:
map.triggerRepaint();
После вызова:
Если изменений нет, карта переходит в состояние idle и прекращает активный рендеринг.
Система отслеживает момент, когда все изменения обработаны. Событие:
map.on('idle', () => {});
срабатывает при выполнении условий:
Idle является важной частью change detection, так как сигнализирует о полной синхронизации состояния карты.
Анимации нарушают статичность сцены и поддерживают непрерывный change detection.
Пример:
map.setPaintProperty('roads', 'line-opacity', 0.5);
map.setLayoutProperty('roads', 'visibility', 'visible');
Также используются:
Каждый frame анимации инициирует частичный diff состояния.
Камера рассматривается как независимый объект состояния:
Изменение камеры не затрагивает стиль напрямую, но влияет на:
Каждое изменение камеры инициирует пересчёт видимой области и частичный reload данных.
Векторные и растровые тайлы обрабатываются отдельно:
Изменение одного источника может затронуть десятки тайлов, но система ограничивает обновление только пересекающимися регионами.
Для оптимизации производительности изменения группируются:
map.batch(function () {
map.setPaintProperty('water', 'fill-color', 'blue');
map.setPaintProperty('land', 'fill-color', 'green');
});
Внутри батча:
Это критически снижает нагрузку при массовых обновлениях.
Система change detection включает приоритизацию:
Это обеспечивает корректное распределение ресурсов между визуально значимыми и вспомогательными изменениями.
Частые причины избыточного change detection:
setData с полным пересозданием
GeoJSONСистема реагирует на каждое такое изменение отдельным diff pass, что увеличивает нагрузку на CPU и GPU.
Контроль change detection достигается через:
Такая модель позволяет удерживать стабильный frame rate даже при большом количестве объектов и сложных стилях.