Symbol-placement

Слой типа symbol в Mapbox GL JS предназначен для отображения текстовых подписей (text) и иконок (icon). Одной из ключевых задач при работе с такими слоями является определение места размещения символов относительно геометрии объекта. За это отвечает свойство symbol-placement.

Параметр определяет, каким образом подписи и иконки будут располагаться на карте:

  • в точке;
  • вдоль линии;
  • по центру линии.

От выбора режима зависит внешний вид картографических подписей дорог, рек, маршрутов, границ и других линейных объектов.

Свойство задаётся в блоке layout слоя.

map.addLayer({
    id: 'roads-labels',
    type: 'symbol',
    source: 'roads',
    layout: {
        'symbol-placement': 'line',
        'text-field': ['get', 'name']
    }
});

Возможные значения

Mapbox GL JS поддерживает три значения:

Значение Назначение
point Размещение символов в отдельных точках
line Размещение вдоль всей линии
line-center Размещение в центре линии

Режим point

Значение point используется по умолчанию.

layout: {
    'symbol-placement': 'point'
}

В этом режиме символ размещается в одной конкретной точке.

Для точечных объектов это естественное поведение:

{
    "type": "Point",
    "coordinates": [37.6176, 55.7558]
}

Подпись отображается рядом с координатой объекта.

Использование с точечными объектами

map.addLayer({
    id: 'cities',
    type: 'symbol',
    source: 'cities',
    layout: {
        'symbol-placement': 'point',
        'text-field': ['get', 'city']
    }
});

Такой подход применяется для:

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

Поведение point для линейных объектов

Интересно, что режим point может использоваться и для линий.

Если источник содержит геометрию типа LineString, система выбирает одну подходящую позицию и размещает подпись как отдельный объект.

Пример:

layout: {
    'symbol-placement': 'point',
    'text-field': ['get', 'road_name']
}

Для длинной дороги появится одна подпись вместо множества повторений вдоль маршрута.

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


Режим line

Значение line предназначено специально для линейных объектов.

layout: {
    'symbol-placement': 'line'
}

В этом режиме текст изгибается вдоль геометрии линии.

Это основной способ подписывания:

  • дорог;
  • улиц;
  • рек;
  • железных дорог;
  • маршрутов транспорта;
  • туристических троп.

Пример размещения вдоль дороги

map.addLayer({
    id: 'road-labels',
    type: 'symbol',
    source: 'roads',
    layout: {
        'symbol-placement': 'line',
        'text-field': ['get', 'name']
    }
});

Если линия имеет изгибы, подпись повторяет её форму.

Например:

─────────────
 Main Street
─────────────

или

~~~~~~River~~~~~~

Текст визуально следует за направлением объекта.


Преимущества режима line

Естественное восприятие

Подпись становится частью объекта.

Название реки выглядит как продолжение русла, а название дороги — как элемент дорожной сети.

Экономия пространства

Не требуется искать свободное место рядом с линией.

Текст располагается непосредственно на объекте.

Улучшение читаемости

Пользователь быстрее понимает, к какому объекту относится подпись.


Ограничения режима line

Для корректного размещения требуется достаточная длина линии.

Если объект слишком короткий, подпись может не отображаться.

Например:

{
    "type": "LineString",
    "coordinates": [
        [37.61, 55.75],
        [37.62, 55.75]
    ]
}

Если длина линии меньше длины текста, движок может скрыть подпись.

Это предотвращает наложение символов и ухудшение читаемости карты.


Режим line-center

Значение line-center является промежуточным вариантом между point и line.

layout: {
    'symbol-placement': 'line-center'
}

В этом режиме подпись размещается в центре линии, но не изгибается по всей её длине.


Пример работы line-center

Для дороги:

-----------------------
      Main Street
-----------------------

Подпись будет находиться примерно посередине геометрии.

При этом текст остаётся единым объектом и не повторяет все изгибы линии.


Когда использовать line-center

Режим особенно полезен для:

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

Пример:

layout: {
    'symbol-placement': 'line-center',
    'text-field': ['get', 'name']
}

Сравнение режимов размещения

Рассмотрим одну и ту же линию.

point

Main Street
     |
     |
     |

Подпись существует независимо от геометрии.

line

Main
   Street
      Road

Текст повторяет форму линии.

line-center

──────────────
 Main Street
──────────────

Подпись располагается в центральной части объекта.


Влияние на отображение иконок

Свойство действует не только на текстовые подписи, но и на иконки.

Пример:

layout: {
    'symbol-placement': 'line',
    'icon-image': 'arrow'
}

Иконки начинают размещаться вдоль линии.

Это часто используется для отображения:

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

Совместная работа с symbol-spacing

При использовании режима line особое значение приобретает параметр symbol-spacing.

Он определяет расстояние между повторяющимися символами.

layout: {
    'symbol-placement': 'line',
    'symbol-spacing': 300
}

Большое значение:

'symbol-spacing': 600

создаёт редкие подписи.

Малое значение:

'symbol-spacing': 100

увеличивает частоту появления символов вдоль линии.


Использование с иконками направления

Распространённый сценарий — отображение стрелок вдоль маршрута.

map.addLayer({
    id: 'route-arrows',
    type: 'symbol',
    source: 'route',
    layout: {
        'symbol-placement': 'line',
        'icon-image': 'arrow',
        'symbol-spacing': 100
    }
});

Результатом становится последовательность стрелок, повторяющих направление движения.


Взаимодействие с text-rotation-alignment

При работе с линиями часто применяется свойство text-rotation-alignment.

layout: {
    'symbol-placement': 'line',
    'text-rotation-alignment': 'map'
}

Оно определяет систему координат, относительно которой поворачивается текст.

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


Взаимодействие с icon-rotation-alignment

Для иконок действует аналогичное свойство.

layout: {
    'symbol-placement': 'line',
    'icon-image': 'arrow',
    'icon-rotation-alignment': 'map'
}

Стрелки автоматически следуют форме линии.


Работа с многочастными линиями

Если объект представлен геометрией MultiLineString, поведение зависит от выбранного режима.

Пример:

{
    "type": "MultiLineString",
    "coordinates": [
        [...],
        [...],
        [...]
    ]
}

point

Создаётся одна позиция для символа.

line

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

line-center

Для каждой линии вычисляется отдельный центр.


Масштабирование и размещение символов

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

Для режима line это особенно важно:

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

Такой механизм обеспечивает читаемость на всех уровнях масштабирования.


Коллизии подписей

Mapbox GL JS использует систему обнаружения пересечений символов.

Даже если задано:

'symbol-placement': 'line'

подпись может не появиться, если рядом уже находится другая надпись.

Для управления этим поведением используются свойства:

'text-allow-overlap'

и

'icon-allow-overlap'

Например:

layout: {
    'symbol-placement': 'line',
    'text-field': ['get', 'name'],
    'text-allow-overlap': true
}

Однако чрезмерное отключение коллизий способно привести к перегруженной карте.


Практические рекомендации

Для городов и точек интереса

Используется:

'symbol-placement': 'point'

Для дорог и рек

Используется:

'symbol-placement': 'line'

Для коротких линейных объектов

Используется:

'symbol-placement': 'line-center'

Для стрелок маршрута

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

{
    'symbol-placement': 'line',
    'icon-image': 'arrow',
    'symbol-spacing': 100
}

Для сложных извилистых объектов

Предпочтителен режим:

'symbol-placement': 'line-center'

поскольку чрезмерное искривление текста может ухудшать читаемость.


Полный пример слоя дорожных подписей

map.addLayer({
    id: 'street-labels',
    type: 'symbol',
    source: 'streets',
    layout: {
        'symbol-placement': 'line',
        'text-field': ['get', 'name'],
        'text-size': 12,
        'symbol-spacing': 300,
        'text-rotation-alignment': 'map'
    },
    paint: {
        'text-color': '#333333',
        'text-halo-color': '#ffffff',
        'text-halo-width': 1
    }
});

В данном примере названия улиц располагаются непосредственно вдоль дорожной сети, следуют направлению геометрии, автоматически избегают пересечений и масштабируются вместе с картой.