Symbol

Символьный слой (Symbol layer) в Mapbox GL JS предназначен для отображения точечных и линейных объектов в виде иконок и подписей. Это один из наиболее сложных и функционально насыщенных типов слоёв, так как он объединяет визуализацию текста, растровых и векторных иконок, а также систему предотвращения наложений (collision detection), которая критически влияет на читаемость карты.

Основная особенность символов заключается в том, что они всегда зависят от набора данных источника (source), но их визуальное поведение определяется одновременно через layout- и paint-свойства. Layout отвечает за геометрию и правила размещения, а paint — за визуальные параметры отрисовки.


Символьный слой объявляется через тип symbol и работает с любым векторным источником данных (vector source, geojson source).

Ключевые поля:

  • source — источник данных
  • source-layer — слой внутри векторного тайла
  • type: "symbol"

Пример конфигурации:

map.addLayer({
  id: "cities",
  type: "symbol",
  source: "places",
  layout: {
    "icon-image": "marker-15",
    "text-field": ["get", "name"],
    "text-size": 14
  }
});

Символьный слой всегда строится вокруг двух основных сущностей:

  • icon-image — графическая иконка
  • text-field — текстовая подпись

Иконки: icon-image и sprite-система

Иконки в Mapbox GL JS не загружаются напрямую как URL в каждом слое. Вместо этого используется sprite atlas — единый набор изображений, загружаемый через стиль карты.

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

  • icon-image — имя иконки из sprite
  • icon-size — масштабирование иконки
  • icon-rotate — вращение
  • icon-offset — смещение относительно точки
  • icon-anchor — точка привязки (center, top, bottom и т.д.)
layout: {
  "icon-image": "airport-15",
  "icon-size": 1.2,
  "icon-rotate": 45
}

Особенность SDF-иконок

SDF (Signed Distance Field) иконки позволяют:

  • перекрашивать иконку через icon-color
  • изменять прозрачность
  • применять динамические стили без пересборки спрайта
paint: {
  "icon-color": "#ff0000"
}

Текстовые подписи: text-field и форматирование

Текст формируется через text-field. Это не просто строка, а expression-система Mapbox.

Простейший вариант:

"text-field": ["get", "name"]

Конкатенация:

"text-field": ["concat", "Город: ", ["get", "name"]]

Форматирование строк:

Mapbox поддерживает форматированные строки:

"text-field": [
  "format",
  ["get", "name"],
  { "font-scale": 1.2, "text-color": "#000" }
]

Динамическая логика:

"text-field": [
  "case",
  ["==", ["get", "type"], "capital"],
  "Столица",
  ["get", "name"]
]

Управление столкновениями (Collision Detection)

Одной из ключевых задач symbol-слоя является предотвращение наложения подписей и иконок.

Основные свойства:

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

Приоритет отображения

Можно управлять приоритетом:

"text-priority": ["get", "rank"]

Чем выше значение — тем выше шанс отображения.


Размещение символов: symbol-placement

Определяет, как символы располагаются относительно геометрии.

Варианты:

  • point — только точки
  • line — вдоль линии
  • line-center — по центру линии
layout: {
  "symbol-placement": "line"
}

Размещение вдоль линии

Используется для дорог, рек, маршрутов:

layout: {
  "symbol-placement": "line",
  "text-field": "Route",
  "text-rotation-alignment": "map"
}

Контроль ориентации

text-rotation-alignment

  • map — текст следует ориентации карты
  • viewport — всегда ориентирован вверх

icon-rotation-alignment

layout: {
  "text-rotation-alignment": "viewport",
  "icon-rotation-alignment": "map"
}

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

Символьные слои поддерживают интерполяцию по zoom.

text-size с интерполяцией:

"text-size": [
  "interpolate",
  ["linear"],
  ["zoom"],
  10, 12,
  15, 18
]

icon-size:

"icon-size": [
  "interpolate",
  ["linear"],
  ["zoom"],
  8, 0.5,
  16, 1.5
]

Это позволяет адаптировать карту под разные уровни детализации.


Data-driven styling в symbol слоях

Символьные слои активно используют свойства данных.

Пример изменения цвета текста:

"text-color": [
  "match",
  ["get", "category"],
  "park", "#2ecc71",
  "water", "#3498db",
  "#333333"
]

Размер в зависимости от значения:

"text-size": [
  "interpolate",
  ["linear"],
  ["get", "population"],
  1000, 10,
  1000000, 24
]

Управление смещениями и якорями

icon-anchor:

  • center
  • top
  • bottom
  • left
  • right
"icon-anchor": "bottom"

text-offset:

"text-offset": [0, 1.5]

Позволяет позиционировать подпись относительно иконки.


Многоуровневые символы (icon + text)

Часто используется комбинация:

layout: {
  "icon-image": "marker",
  "text-field": ["get", "name"],
  "text-offset": [0, 1.2],
  "text-anchor": "top"
}

Это создаёт стандартные маркеры с подписями.


Производительность symbol-слоёв

Символьные слои — одни из самых дорогих по вычислениям, поскольку включают:

  • collision detection
  • layout calculation
  • glyph rasterization
  • sprite lookup

Оптимизационные подходы:

  • уменьшение количества символов через фильтры
  • использование minzoom и maxzoom
  • отключение лишних подписей
  • кластеризация данных на уровне source
"minzoom": 10,
"maxzoom": 18

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

Text rendering зависит от glyph atlas.

В стиле задаётся:

"glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf"

Шрифты подгружаются по диапазонам символов, что снижает нагрузку и ускоряет рендеринг.


Приоритизация и фильтрация символов

Фильтры применяются для ограничения отображаемых объектов:

"filter": ["==", ["get", "type"], "city"]

Сложные фильтры позволяют строить многоуровневые системы подписей (например, показывать города только на определённых зумах).


Поворот текста вдоль линии

Для маршрутов и трасс используется автоматическая ориентация:

layout: {
  "symbol-placement": "line",
  "text-rotation-alignment": "map",
  "text-field": ["get", "name"]
}

Это обеспечивает чтение текста вдоль геометрии линии.


Сложные выражения в text-field

Поддерживаются составные конструкции:

"text-field": [
  "concat",
  ["get", "name"],
  "\n",
  ["get", "country"]
]

Можно строить многострочные подписи.


Взаимодействие с событиями

Символьные слои участвуют в интерактивности карты:

map.on("click", "cities", (e) => {
  const feature = e.features[0];
});

Также доступны:

  • mouseenter
  • mouseleave
  • mousemove

Управление видимостью символов

Через paint:

"icon-opacity": 0.8,
"text-opacity": 1

И через zoom:

"text-opacity": [
  "interpolate",
  ["linear"],
  ["zoom"],
  10, 0,
  12, 1
]

Типичные архитектурные паттерны

Символьные слои обычно используются в связке:

  • base map (дороги, водоёмы)
  • symbol layer (POI, города)
  • label hierarchy (разные уровни подписей)

Иерархия строится через:

  • zoom ranges
  • rank properties
  • separate layers для разных категорий

Ошибки проектирования symbol-слоёв

Распространённые проблемы:

  • перегрузка карты текстом
  • отсутствие контроля collision
  • слишком мелкие зум-диапазоны
  • отсутствие приоритизации данных
  • чрезмерное использование сложных expressions

Эти ошибки приводят к визуальному шуму и падению производительности рендеринга.


Особенности поведения при наклоне и вращении карты

Symbol layer адаптируется к:

  • pitch (наклон)
  • bearing (поворот)
"icon-pitch-alignment": "auto",
"text-pitch-alignment": "auto"

Это позволяет сохранять читаемость при 3D-визуализации.