Icon-image и icon-size

Символьные слои (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'
        }
    });
});

Последовательность работы:

  1. Загрузка файла изображения.
  2. Регистрация изображения через addImage().
  3. Использование зарегистрированного имени в 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 практически не влияет на производительность.

Однако большое количество одновременно отображаемых крупных иконок:

  • увеличивает объём рендеринга;
  • повышает нагрузку на GPU;
  • может снижать частоту кадров на мобильных устройствах.

Практический пример слоя с адаптивными иконками

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
    }
});

Такой подход позволяет:

  • автоматически выбирать иконку по категории объекта;
  • увеличивать её при приближении карты;
  • сохранять читаемость интерфейса;
  • уменьшать количество пересечений символов;
  • поддерживать единый стиль отображения пространственных данных.