В Mapbox GL JS управление коллизиями определяет поведение текстовых иконок и подписей при конкуренции за ограниченное экранное пространство. Коллизия возникает, когда два или более визуальных элемента (подписи, иконки, маркеры символов) претендуют на одну и ту же область карты.
Система рендеринга использует геометрическую модель занятости пространства, в которой каждый символ слоя представляется ограничивающим прямоугольником (collision box). Эти области проверяются на пересечения в процессе размещения на каждом кадре отрисовки карты.
Основные принципы:
Основной системой, отвечающей за коллизии, является symbol layer. Он объединяет текст и иконки в единый слой, где применяется общий алгоритм размещения.
Каждый объект слоя проходит несколько этапов:
Ключевое поведение определяется свойствами layout:
map.addLayer({
id: 'cities',
type: 'symbol',
source: 'places',
layout: {
'text-field': ['get', 'name'],
'text-size': 14,
'icon-image': 'marker',
}
});
Текст и иконки обрабатываются как независимые, но связанные сущности. Для каждого типа существует собственная система коллизий:
Поведение задаётся через свойства:
text-allow-overlapicon-allow-overlaptext-ignore-placementicon-ignore-placementЕсли allow-overlap отключён, элемент может быть скрыт
при пересечении с любым другим объектом.
Пример:
layout: {
'text-field': ['get', 'name'],
'text-allow-overlap': false,
'icon-allow-overlap': false
}
Каждый символ имеет расширенную область столкновения. Она включает:
Параметры управления:
text-paddingicon-paddinglayout: {
'text-field': ['get', 'name'],
'text-padding': 2,
'icon-padding': 1
}
Padding увеличивает вероятность блокировки соседних объектов, снижая плотность подписей.
Система коллизий опирается на иерархию приоритетов. При равных условиях конфликт разрешается по следующим правилам:
symbol-sort-keyПример задания приоритета:
layout: {
'symbol-sort-key': ['get', 'priority']
}
Объекты с более высоким значением получают преимущество при размещении.
Коллизии динамически пересчитываются при изменении:
При увеличении масштаба:
При наклоне карты происходит деформация bounding box в экранных координатах, что изменяет геометрию пересечений.
Свойства text-optional и icon-optional
позволяют системе не блокировать более важные элементы,
даже если текущий объект не может быть размещён.
layout: {
'text-field': ['get', 'name'],
'text-optional': true
}
В этом режиме объект считается второстепенным и может быть скрыт без влияния на приоритет других элементов.
При высокой плотности данных используется автоматическое прореживание:
Часто применяется совместно с:
minzoom,
maxzoom)Для текстовых слоёв доступны дополнительные параметры, влияющие на коллизии:
text-keep-upright — сохраняет ориентацию текста при
наклоне картыtext-anchor — точка привязки (center, top, bottom,
left, right)text-offset — смещение относительно геометрииtext-radial-offset — радиальное смещение вдоль
направления линииПример:
layout: {
'text-field': ['get', 'name'],
'text-anchor': 'top',
'text-offset': [0, 1],
'text-keep-upright': true
}
Эти параметры напрямую влияют на форму collision box.
При совместном использовании текста и иконок формируется единый блок размещения. Возможны три стратегии:
Поведение зависит от комбинации:
icon-allow-overlaptext-allow-overlapicon-ignore-placementtext-ignore-placementАлгоритм коллизий является одной из наиболее затратных частей рендеринга. Оптимизация достигается через:
minzoom для скрытия мелких объектовТакже важную роль играет:
Коллизии пересчитываются при изменениях:
При этом используется инкрементальная модель: пересчитываются только затронутые тайлы и символы, что снижает нагрузку на GPU и CPU.
Высокая плотность (городские карты):
layout: {
'text-field': ['get', 'name'],
'text-size': 12,
'text-allow-overlap': false,
'text-padding': 2,
'symbol-sort-key': ['get', 'importance']
}
Средняя плотность (региональные карты):
layout: {
'text-field': ['get', 'name'],
'text-size': 14,
'text-optional': true,
'text-padding': 1
}
Низкая плотность (обзорные карты):
layout: {
'text-field': ['get', 'name'],
'text-allow-overlap': true,
'icon-allow-overlap': true
}