В Mapbox GL JS иконки не существуют как отдельные DOM-элементы. Все
графические элементы рендерятся внутри WebGL-контекста и являются частью
стиля карты. Иконки подключаются через систему спрайтов или загружаются
как отдельные изображения, после чего используются в слоях типа
symbol.
Ключевая особенность подхода заключается в том, что иконка — это ресурс стиля, а не UI-объект. Она попадает в общий атлас (sprite) или регистрируется вручную через API карты, после чего становится доступной по имени.
Стандартный способ хранения иконок в Mapbox GL JS — sprite sheet. Спрайт представляет собой два файла:
Стиль карты указывает базовый URL:
{
"sprite": "mapbox://sprites/your-style-id"
}
Каждая иконка получает уникальное имя, например:
restaurant-15airport-11marker-blueДалее эти имена используются в слоях:
map.addLayer({
id: 'points',
type: 'symbol',
source: 'places',
layout: {
'icon-image': 'restaurant-15'
}
});
addImageПомимо спрайтов, Mapbox GL JS позволяет динамически добавлять изображения в стиль карты.
map.on('load', () => {
map.loadImage('/icons/custom-marker.png', (error, image) => {
if (error) throw error;
map.addImage('custom-marker', image);
});
});
После регистрации изображение становится доступным как часть стиля:
map.addLayer({
id: 'custom-points',
type: 'symbol',
source: 'points',
layout: {
'icon-image': 'custom-marker'
}
});
Важный момент: имя изображения должно быть уникальным в пределах стиля. Повторная регистрация без удаления приведёт к ошибке.
Иконки могут добавляться и удаляться динамически:
if (map.hasImage('custom-marker')) {
map.removeImage('custom-marker');
}
Это особенно важно при:
Удаление изображения автоматически влияет на все слои, которые его используют.
SVG-подобная гибкость достигается через SDF (Signed Distance Field). Такие иконки позволяют менять цвет и прозрачность без повторной загрузки изображения.
При добавлении изображения:
map.addImage('pin-sdf', image, { sdf: true });
После этого иконка становится стилизуемой через
icon-color:
layout: {
'icon-image': 'pin-sdf'
},
paint: {
'icon-color': '#ff0000'
}
SDF особенно полезен для:
Иконки часто должны изменять размер в зависимости от масштаба карты.
Для этого используется свойство icon-size.
Простейший вариант:
'icon-size': 1.2
Более гибкий подход — выражения:
'icon-size': [
'interpolate',
['linear'],
['zoom'],
5, 0.5,
10, 1,
15, 1.5
]
Это создаёт плавное увеличение иконок при приближении карты, предотвращая визуальную перегрузку на низких масштабах.
Иконка не просто рисуется в точке координат — она имеет точку привязки.
Основные параметры:
layout: {
'icon-anchor': 'bottom',
'icon-offset': [0, -10]
}
icon-anchor задаёт точку якоря:
centertopbottomleftrighttop-lefticon-offset позволяет тонко смещать позицию относительно
якоря.
Это критично при работе с:
При большом количестве объектов иконки начинают конкурировать за пространство. Mapbox GL JS предоставляет инструменты управления коллизиями:
layout: {
'icon-allow-overlap': false,
'icon-ignore-placement': false
}
Если включить icon-allow-overlap, иконки могут
перекрывать друг друга. В противном случае движок будет скрывать менее
приоритетные элементы.
Также важно свойство:
'icon-optional': true
Оно позволяет отображать текст даже без иконки, если она не прошла проверку коллизий.
Символьные слои часто объединяют изображение и подпись:
layout: {
'icon-image': 'restaurant-15',
'text-field': ['get', 'name'],
'text-offset': [0, 1.2],
'text-anchor': 'top'
}
При этом важно учитывать порядок рендеринга: иконка и текст принадлежат одному слою и подчиняются одинаковым правилам размещения.
Mapbox GL JS позволяет изменять иконки в зависимости от данных:
'icon-image': [
'match',
['get', 'type'],
'restaurant', 'restaurant-15',
'airport', 'airport-15',
'default-marker'
]
Такой подход позволяет строить универсальные слои без создания множества отдельных конфигураций.
Иконки напрямую влияют на производительность WebGL-рендеринга. Основные принципы оптимизации:
addImage в рантаймеОсобенно критично количество draw calls: каждый уникальный набор изображений увеличивает нагрузку на GPU.
Метод loadImage асинхронен и требует обработки
ошибок:
map.loadImage(url, (error, image) => {
if (error) return;
map.addImage('icon-name', image);
});
При работе с внешними источниками важно учитывать:
Визуальные стили часто формируются заранее в редакторе стиля, где иконки добавляются в sprite. Однако даже после публикации стиля они могут быть переопределены на клиенте через API.
Это создаёт двухуровневую систему:
Именно сочетание этих уровней позволяет строить интерфейсы с адаптивной картографией без пересборки стиля.
При вращении и наклоне карты иконки могут сохранять ориентацию или поворачиваться вместе с картой:
'icon-rotation-alignment': 'map'
или
'icon-rotation-alignment': 'viewport'
Первый вариант фиксирует ориентацию относительно карты, второй — относительно экрана.
Это особенно важно для:
Часто встречаются следующие проблемы:
load события карты, что приводит к
ошибкам стиляaddImageКаждая из этих ошибок приводит либо к падению производительности, либо к нестабильному поведению рендера.
Параметр icon-image не хранит само изображение. Он лишь
ссылается на ключ в sprite или registry изображений карты. При рендере
WebGL получает уже подготовленный атлас текстур, где каждая иконка — это
UV-координаты внутри общей текстуры.
Такой подход обеспечивает: