В Mapbox GL JS изображения используются как самостоятельные ресурсы
стиля и как часть слоёв типа symbol. Любое изображение,
которое должно применяться в стиле карты, сначала регистрируется в
объекте карты через загрузку и добавление в атлас изображений.
Базовый механизм основан на двух шагах: загрузка ресурса и регистрация имени изображения в стиле.
map.loadImage('/images/marker.png', (error, image) => {
if (error) throw error;
map.addImage('custom-marker', image);
});
После добавления изображение становится доступным внутри стиля и
может использоваться в слоях через icon-image.
map.addLayer({
id: 'points',
type: 'symbol',
source: 'points-source',
layout: {
'icon-image': 'custom-marker',
'icon-size': 1
}
});
Ключевым моментом является то, что изображение становится частью внутреннего реестра стиля и кешируется в WebGL-контексте.
Обновление изображения в Mapbox GL JS не выполняется «на месте» в смысле изменения пикселей уже зарегистрированного объекта. Вместо этого применяется перезапись ресурса в стиле.
Начиная с современных версий Mapbox GL JS, поддерживается переопределение изображения через повторный вызов регистрации с флагом перезаписи.
map.loadImage('/images/marker-v2.png', (error, image) => {
if (error) throw error;
map.addImage('custom-marker', image, { overwrite: true });
});
Механизм работает следующим образом:
Перерисовка происходит через WebGL без необходимости пересоздания слоя.
Если требуется частое обновление изображения (например, динамический
маркер или состояние объекта), используется повторная загрузка и
регистрация без промежуточного removeImage.
function updateMarker(url) {
map.loadImage(url, (error, image) => {
if (error) return;
map.addImage('dynamic-marker', image, { overwrite: true });
});
}
Такой подход исключает необходимость ручного управления жизненным циклом ресурса.
removeImage перед обновлениемВ более старых архитектурах или при необходимости строгого контроля состояния применяется явное удаление ресурса перед добавлением нового.
if (map.hasImage('custom-marker')) {
map.removeImage('custom-marker');
}
map.loadImage('/images/marker-v3.png', (error, image) => {
if (error) throw error;
map.addImage('custom-marker', image);
});
Этот подход полезен при отладке и при сложной логике переключения наборов иконок.
Изображение, используемое в слое symbol, определяется не
напрямую через слой, а через свойство icon-image. Поэтому
изменение изображения часто сводится к изменению этого свойства или
имени ресурса.
map.setLayoutProperty('points', 'icon-image', 'custom-marker-new');
При таком подходе предварительно должно быть зарегистрировано новое изображение:
map.loadImage('/images/marker-new.png', (error, image) => {
if (error) return;
map.addImage('custom-marker-new', image);
});
Этот механизм позволяет переключать визуальные состояния без модификации источника данных.
В сценариях, где визуальный вид зависит от данных, применяется комбинация свойств GeoJSON и выражений стиля.
Источник данных содержит признак состояния:
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [30, 50]
},
properties: {
status: 'active'
}
}
Слой использует выражение выбора изображения:
map.addLayer({
id: 'devices',
type: 'symbol',
source: 'devices-source',
layout: {
'icon-image': [
'match',
['get', 'status'],
'active', 'icon-active',
'inactive', 'icon-inactive',
'icon-default'
]
}
});
В этом случае «обновление изображения» фактически становится обновлением данных источника:
source.setData(updatedGeojson);
Изображения остаются неизменными, меняется только привязка.
При необходимости периодического обновления визуального состояния применяется комбинированная схема: загрузка изображения + перезапись ресурса.
async function refreshIcon() {
map.loadImage(`/images/icon-${Date.now()}.png`, (error, image) => {
if (error) return;
map.addImage('live-icon', image, { overwrite: true });
});
}
setInterval(refreshIcon, 5000);
Такая модель используется в задачах мониторинга, когда визуальные элементы должны отражать изменяющиеся параметры системы.
Внутренний механизм Mapbox GL JS основан на спрайтах. Все изображения компонуются в единый атлас, оптимизированный для WebGL.
При обновлении изображения:
При массовом обновлении изображений предпочтительно минимизировать
количество вызовов addImage, так как каждое обновление
может вызывать перерасчёт GPU-ресурсов.
При загрузке изображений по URL важную роль играет HTTP-кэш. Часто обновление не отражается визуально из-за кеширования ресурса браузером.
Распространённый метод обхода — добавление параметра версии:
map.loadImage('/images/marker.png?v=3', (error, image) => {
if (error) return;
map.addImage('custom-marker', image, { overwrite: true });
});
Такой подход гарантирует получение нового бинарного содержимого без необходимости ручного сброса кэша.
Для слоёв типа raster изображение не обновляется
напрямую через addImage, так как используется внешний
тайловый источник. Однако возможно переключение URL источника:
map.getSource('raster-source').setTiles([
'https://tiles.server.com/new/{z}/{x}/{y}.png'
]);
При этом перезагрузка тайлов приводит к обновлению визуального изображения на карте.
Каждое добавленное изображение занимает память GPU. При частых обновлениях важно учитывать утечки ресурсов.
Стратегия управления включает:
hasImageremoveImageif (map.hasImage('temp-icon')) {
map.removeImage('temp-icon');
}
Для псевдоанимированных эффектов применяется последовательная замена текстур под одним идентификатором.
const frames = ['/f1.png', '/f2.png', '/f3.png'];
let index = 0;
function animate() {
map.loadImage(frames[index], (error, image) => {
if (error) return;
map.addImage('animated-icon', image, { overwrite: true });
index = (index + 1) % frames.length;
});
}
setInterval(animate, 100);
Такой подход создаёт эффект кадровой анимации без использования canvas или shader-логики.
Идентификатор изображения является ключевым связующим элементом между стилем и ресурсом. Все обновления должны учитывать, что:
Поэтому архитектура обновления изображений строится вокруг стабильных идентификаторов и контролируемой перезаписи ресурсов.