Символьные слои (symbol layers) в Mapbox GL JS позволяют
отображать на карте текстовые подписи и графические значки. За
отображение изображений отвечает свойство icon-image, а за
их масштабирование — icon-size. Эти параметры входят в
группу настроек layout и используются при визуализации
маркеров, категорий объектов, точек интереса, транспортной
инфраструктуры и любых других объектов, представленных в виде
иконок.
icon-imageСвойство icon-image определяет изображение, которое
будет использовано в качестве значка для объекта.
Значение свойства представляет собой имя изображения, предварительно
добавленного в стиль карты через метод addImage() либо уже
существующего в используемом стиле.
Простейший пример:
map.addImage('restaurant-icon', image);
map.addLayer({
id: 'restaurants',
type: 'symbol',
source: 'restaurants',
layout: {
'icon-image': 'restaurant-icon'
}
});
В данном случае каждый объект слоя будет отображаться с
использованием изображения restaurant-icon.
Перед использованием изображения его необходимо зарегистрировать.
Загрузка изображения из файла:
map.loadImage('/images/restaurant.png', (error, image) => {
if (error) throw error;
map.addImage('restaurant-icon', image);
map.addLayer({
id: 'restaurants',
type: 'symbol',
source: 'restaurants',
layout: {
'icon-image': 'restaurant-icon'
}
});
});
Последовательность работы:
addImage().icon-image.Многие стили Mapbox содержат собственный набор значков в спрайте (sprite).
Пример:
map.addLayer({
id: 'poi',
type: 'symbol',
source: 'places',
layout: {
'icon-image': 'museum-15'
}
});
Значение museum-15 соответствует имени изображения
внутри спрайта стиля.
Подобные иконки обычно используются для:
Очень часто разные объекты должны отображаться разными значками.
Например, набор данных содержит поле type:
{
"type": "Feature",
"properties": {
"type": "restaurant"
}
}
Можно выбрать изображение на основании значения свойства объекта.
layout: {
'icon-image': [
'match',
['get', 'type'],
'restaurant', 'restaurant-icon',
'hotel', 'hotel-icon',
'park', 'park-icon',
'default-icon'
]
}
Результат:
| Значение type | Иконка |
|---|---|
| restaurant | restaurant-icon |
| hotel | hotel-icon |
| park | park-icon |
| другое | default-icon |
Такой подход позволяет отображать тысячи объектов одним слоем.
getЕсли имя иконки уже хранится в данных объекта, выбор изображения становится ещё проще.
Данные:
{
"type": "Feature",
"properties": {
"icon": "restaurant-icon"
}
}
Настройка слоя:
layout: {
'icon-image': ['get', 'icon']
}
Mapbox GL JS будет автоматически получать имя изображения из свойства объекта.
Это особенно удобно при работе с большими GeoJSON-источниками.
Свойство icon-image часто используется вместе с
текстовыми подписями.
map.addLayer({
id: 'places',
type: 'symbol',
source: 'places',
layout: {
'icon-image': 'place-icon',
'text-field': ['get', 'name'],
'text-offset': [0, 1.5],
'text-anchor': 'top'
}
});
Результат:
icon-sizeСвойство icon-size управляет масштабом изображения.
Значение представляет собой множитель относительно исходного размера иконки.
Пример:
layout: {
'icon-image': 'restaurant-icon',
'icon-size': 1
}
Масштаб 1 означает использование исходного размера
изображения.
Для увеличения используется коэффициент больше единицы.
layout: {
'icon-image': 'restaurant-icon',
'icon-size': 2
}
Если исходный размер составляет:
32 × 32 px
то фактически на карте будет отображаться:
64 × 64 px
Для уменьшения применяется коэффициент меньше единицы.
layout: {
'icon-image': 'restaurant-icon',
'icon-size': 0.5
}
Если исходное изображение имеет размер:
32 × 32 px
то отображаемый размер станет:
16 × 16 px
icon-sizeНа практике чаще всего используются следующие коэффициенты:
| Значение | Результат |
|---|---|
| 0.5 | уменьшение в 2 раза |
| 0.75 | небольшое уменьшение |
| 1 | исходный размер |
| 1.25 | умеренное увеличение |
| 1.5 | заметное увеличение |
| 2 | увеличение в 2 раза |
| 3 | крупные маркеры |
Чрезмерно большие значения могут ухудшать читаемость карты и увеличивать количество пересечений символов.
Разные категории объектов можно отображать различным размером.
layout: {
'icon-image': ['get', 'icon'],
'icon-size': [
'match',
['get', 'importance'],
'high', 1.8,
'medium', 1.2,
'low', 0.8,
1
]
}
В результате наиболее важные объекты становятся визуально заметнее.
Одно из наиболее полезных применений icon-size —
изменение размеров при изменении масштаба карты.
Пример через интерполяцию:
layout: {
'icon-image': 'city-icon',
'icon-size': [
'interpolate',
['linear'],
['zoom'],
5, 0.5,
10, 1,
15, 2
]
}
Поведение:
| Zoom | Размер |
|---|---|
| 5 | 0.5 |
| 10 | 1 |
| 15 | 2 |
Иконки постепенно увеличиваются при приближении карты.
Для более плавного изменения размера применяется экспоненциальная функция.
layout: {
'icon-size': [
'interpolate',
['exponential', 1.5],
['zoom'],
5, 0.4,
15, 2.5
]
}
Такой вариант часто используется в профессиональных картографических проектах.
Размер значка может зависеть от состояния объекта.
Например, выбранный объект отображается крупнее остальных.
layout: {
'icon-image': 'marker',
'icon-size': [
'case',
['boolean', ['feature-state', 'selected'], false],
2,
1
]
}
После установки состояния:
map.setFeatureState(
{
source: 'places',
id: 15
},
{
selected: true
}
);
объект станет больше остальных.
icon-image и icon-size вместеНаиболее распространённый сценарий:
map.addLayer({
id: 'shops',
type: 'symbol',
source: 'shops',
layout: {
'icon-image': [
'match',
['get', 'category'],
'food', 'food-icon',
'electronics', 'electronics-icon',
'clothing', 'clothing-icon',
'default-icon'
],
'icon-size': [
'interpolate',
['linear'],
['zoom'],
8, 0.5,
12, 1,
16, 2
]
}
});
Здесь одновременно решаются две задачи:
Если указанное имя отсутствует в спрайте или не было зарегистрировано
через addImage(), значок не будет отображён.
Некорректный пример:
layout: {
'icon-image': 'unknown-icon'
}
Свойство icon-size масштабирует уже существующую
картинку.
Если маленькое изображение увеличить слишком сильно:
'icon-size': 4
могут появиться:
Для крупных значков рекомендуется использовать изображения высокого разрешения.
Mapbox GL JS учитывает размеры иконок при предотвращении наложений.
Чем больше значение icon-size, тем выше вероятность
скрытия соседних символов.
Например:
layout: {
'icon-size': 3
}
может привести к тому, что часть объектов перестанет отображаться на плотных участках карты.
Само изменение icon-size практически не влияет на
производительность.
Однако большое количество одновременно отображаемых крупных иконок:
map.addLayer({
id: 'attractions',
type: 'symbol',
source: 'attractions',
layout: {
'icon-image': [
'match',
['get', 'category'],
'museum', 'museum-icon',
'park', 'park-icon',
'hotel', 'hotel-icon',
'default-icon'
],
'icon-size': [
'interpolate',
['linear'],
['zoom'],
6, 0.6,
10, 1,
14, 1.8,
18, 2.5
],
'icon-allow-overlap': false
}
});
Такой подход позволяет: