Иконки и символы

В MapLibre GL JS иконки и текстовые метки формируются через слой symbol, который объединяет два независимых, но часто используемых визуальных элемента: графические символы (icon) и подписи (text). Их совместное использование позволяет строить сложные картографические представления — от простых маркеров до насыщенных информационных слоёв с динамической стилизацией.

Symbol layer является центральным механизмом отображения иконок и текста. Он работает поверх векторных данных и использует свойства стиля для управления визуализацией каждого элемента.

Ключевые свойства:

  • icon-image — ссылка на изображение иконки
  • text-field — текстовая подпись
  • icon-size — масштаб иконки
  • text-size — размер шрифта
  • icon-offset, text-offset — смещение относительно геометрии
  • icon-anchor, text-anchor — точка привязки

Пример базового слоя:

map.addLayer({
  id: 'points',
  type: 'symbol',
  source: 'places',
  layout: {
    'icon-image': 'marker-15',
    'text-field': ['get', 'name'],
    'text-offset': [0, 1.2],
    'text-anchor': 'top'
  }
});

В этом примере иконка и подпись привязываются к координате точки и отображаются совместно.

Управление иконками через sprite

MapLibre GL JS использует спрайты — наборы изображений, объединённых в один файл PNG или JSON-описание. Спрайты загружаются через стиль карты и становятся доступными как именованные ресурсы.

Структура подключения спрайта задаётся в стиле:

"sprite": "https://example.com/sprite"

После загрузки каждый элемент становится доступным по имени:

'icon-image': 'airport-15'

Спрайты оптимизируют производительность, уменьшая количество HTTP-запросов и ускоряя отрисовку.

Добавление кастомных иконок

Помимо спрайтов можно динамически добавлять изображения в стиль карты через addImage.

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

Этот механизм позволяет подгружать пользовательские иконки во время выполнения, что особенно важно для интерактивных приложений.

SDF-иконки и их стилизация

Signed Distance Field (SDF) иконки — это особый тип изображений, которые позволяют изменять цвет и прозрачность через стиль без необходимости иметь несколько версий одного изображения.

При добавлении изображения задаётся параметр:

map.addImage('pin-sdf', image, { sdf: true });

Далее можно управлять цветом:

'icon-color': '#ff0000',
'icon-halo-color': '#000000',
'icon-halo-width': 2

SDF-подход обеспечивает гибкость стилизации и снижает количество графических ресурсов.

Управление отображением текста

Текстовые метки задаются через text-field. Это выражение может ссылаться на свойства GeoJSON или использовать константные значения.

'text-field': ['get', 'title']

Также поддерживаются составные выражения:

'text-field': ['concat', ['get', 'name'], ' — ', ['get', 'type']]

Типографика регулируется через:

  • text-font
  • text-size
  • text-letter-spacing
  • text-line-height

Конфликты и приоритеты символов

При плотном расположении объектов возникает конфликт между метками. MapLibre GL JS использует систему приоритетов и правил размещения.

Основные параметры:

  • text-allow-overlap
  • icon-allow-overlap
  • text-ignore-placement
  • icon-ignore-placement
layout: {
  'text-allow-overlap': false,
  'icon-allow-overlap': false
}

Алгоритм размещения пытается минимизировать перекрытия, учитывая важность объектов и их размеры.

Смещение и привязка

Позиционирование иконок и текста управляется системой якорей.

icon-anchor

Определяет точку привязки иконки:

  • center
  • top
  • bottom
  • left
  • right
  • комбинации вроде top-left
'icon-anchor': 'bottom'

icon-offset

Позволяет сместить иконку относительно координаты:

'icon-offset': [0, -10]

Это часто используется для размещения маркеров над точкой геометрии.

Масштабирование и зависимость от зума

Иконки и текст могут изменять размер в зависимости от уровня масштаба карты.

'icon-size': [
  'interpolate',
  ['linear'],
  ['zoom'],
  5, 0.5,
  10, 1,
  15, 1.5
]

Такой подход позволяет адаптировать визуализацию под разные уровни детализации: от регионального обзора до уличного уровня.

Условная визуализация и выражения

MapLibre GL JS поддерживает мощную систему выражений (expressions), позволяющую менять иконки и текст динамически.

Пример выбора иконки по типу объекта:

'icon-image': [
  'match',
  ['get', 'type'],
  'restaurant', 'restaurant-15',
  'hotel', 'lodging-15',
  'default-marker'
]

Это позволяет строить универсальные слои без разделения на множество источников.

Производительность символов

Отрисовка иконок и текста требует оптимизации, особенно при большом количестве объектов. Основные факторы влияния:

  • количество символов на экране
  • сложность спрайтов
  • использование SDF
  • частота перерисовки при анимации

Рекомендуется ограничивать плотность отображения через:

  • minzoom / maxzoom
  • фильтрацию данных
  • кластеризацию на уровне источника
'minzoom': 10,
'maxzoom': 18

Работа с шрифтами (glyphs)

Текстовые метки используют растровые или SDF-глифы, загружаемые через glyphs в стиле карты.

"glyphs": "https://example.com/fonts/{fontstack}/{range}.pbf"

Font stack определяет набор шрифтов, используемых для рендеринга текста:

'text-font': ['Open Sans Regular', 'Arial Unicode MS Regular']

Поддержка Unicode позволяет отображать многоязычные подписи без дополнительных настроек.

Комбинирование иконок и текста

Часто иконка и текст объединяются в единую композицию:

layout: {
  'icon-image': 'poi-15',
  'text-field': ['get', 'name'],
  'text-offset': [0, 1],
  'text-anchor': 'top',
  'icon-text-fit': 'none'
}

В таких случаях важно учитывать порядок отрисовки и приоритет слоёв, чтобы текст не перекрывал важные элементы карты.

Динамическое изменение стиля иконок

MapLibre GL JS позволяет изменять стиль слоя во время выполнения:

map.setLayoutProperty('points', 'icon-image', 'new-icon');
map.setPaintProperty('points', 'icon-opacity', 0.8);

Это используется для реактивных интерфейсов, где визуализация зависит от пользовательских действий или данных в реальном времени.

Состояния и интерактивность

Иконки могут изменять внешний вид при взаимодействии:

map.on('click', 'points', (e) => {
  map.setFeatureState(
    { source: 'points', id: e.features[0].id },
    { selected: true }
  );
});

И в стиле:

'icon-opacity': [
  'case',
  ['boolean', ['feature-state', 'selected'], false],
  1,
  0.5
]

Такой механизм позволяет создавать интерактивные карты без перерисовки всего слоя.

Ограничения и особенности рендеринга

Символы в MapLibre GL JS подчиняются ряду ограничений WebGL-рендеринга:

  • фиксированное количество символов в кадре
  • зависимость качества от device pixel ratio
  • ограничение на размер спрайта
  • необходимость предварительной загрузки ресурсов

Эти особенности требуют проектирования стиля с учётом масштаба данных и сценариев использования.