Кластеризация в Mapbox GL JS представляет собой механизм группировки большого количества точечных объектов на карте в обобщённые агрегированные элементы — кластеры. Это позволяет существенно снизить визуальную перегрузку карты и повысить производительность при работе с десятками тысяч объектов.
С точки зрения визуализации, кластер — это динамически вычисляемая сущность, которая заменяет набор близко расположенных точек единым представлением. При увеличении масштаба карта «разбивает» кластеры обратно на отдельные точки, обеспечивая плавную детализацию данных.
Ключевая идея заключается в том, что кластеризация выполняется на стороне клиента с использованием алгоритма пространственной индексации, позволяющего быстро перераспределять точки при изменении масштаба или границ отображения.
В основе кластеризации Mapbox GL JS лежит алгоритм Supercluster — высокопроизводительный метод пространственной агрегации точек, оптимизированный для интерактивных карт.
Алгоритм работает по принципу иерархической группировки:
Главная особенность Supercluster заключается в том, что он заранее вычисляет кластеры для всех уровней зума, что позволяет быстро получать результат без пересчёта всей выборки при каждом движении карты.
Кластеризация включается на уровне GeoJSON-источника. Базовая конфигурация выглядит следующим образом:
map.addSource('points', {
type: 'geojson',
data: geojsonData,
cluster: true
});
После включения параметра cluster: true Mapbox GL JS
автоматически начинает группировать точки при отрисовке.
Дополнительно источник может содержать параметры, влияющие на поведение кластеризации:
Параметр clusterRadius определяет расстояние в пикселях,
в пределах которого точки считаются частью одного кластера.
clusterRadius: 50
Чем больше значение радиуса:
Чем меньше значение:
Оптимальный выбор зависит от плотности данных и масштаба карты.
Параметр clusterMaxZoom задаёт максимальный зум, на
котором выполняется кластеризация.
clusterMaxZoom: 14
После достижения указанного уровня зума точки перестают объединяться в кластеры и отображаются как отдельные объекты.
Это важно для сценариев, где:
Одной из наиболее мощных возможностей является вычисление агрегированных свойств кластера.
clusterProperties: {
sum: ['+', ['get', 'value']],
maxValue: ['max', ['get', 'value']]
}
Данный механизм позволяет:
Это делает возможным построение аналитических визуализаций непосредственно на карте без дополнительной обработки данных.
После включения кластеризации данные в источнике делятся на два типа:
cluster: true)cluster: false)Для их отображения используются отдельные слои.
map.addLayer({
id: 'clusters',
type: 'circle',
source: 'points',
filter: ['has', 'point_count'],
paint: {
'circle-radius': 20,
'circle-color': '#51bbd6'
}
});
Ключевой фильтр:
['has', 'point_count']
он отделяет кластеры от одиночных точек.
map.addLayer({
id: 'cluster-count',
type: 'symbol',
source: 'points',
filter: ['has', 'point_count'],
layout: {
'text-field': ['get', 'point_count_abbreviated'],
'text-size': 12
}
});
Свойство point_count_abbreviated автоматически
форматирует число (например, 1500 → 1.5k), что упрощает визуальное
восприятие.
map.addLayer({
id: 'unclustered-point',
type: 'circle',
source: 'points',
filter: ['!', ['has', 'point_count']],
paint: {
'circle-radius': 5,
'circle-color': '#f28cb1'
}
});
Основной сценарий взаимодействия — раскрытие кластера при клике.
Mapbox GL JS предоставляет метод
getClusterExpansionZoom, который вычисляет уровень зума,
необходимый для «разворачивания» кластера.
map.on('click', 'clusters', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['clusters']
});
const clusterId = features[0].properties.cluster_id;
map.getSource('points').getClusterExpansionZoom(clusterId, (err, zoom) => {
map.easeTo({
center: features[0].geometry.coordinates,
zoom: zoom
});
});
});
Этот механизм обеспечивает плавный переход от агрегированного представления к детализированному.
Кластеризация тесно связана с фильтрацией данных. При изменении фильтров источник пересчитывает кластеры на лету.
Типовые сценарии:
Важно учитывать, что любая фильтрация влияет на структуру кластеров, так как изменяется исходный набор точек.
Кластеризация часто применяется при работе с большими наборами данных (десятки и сотни тысяч объектов). Основные факторы производительности:
1. Размер GeoJSON
Большие JSON-файлы увеличивают время загрузки и инициализации.
2. Частота обновления данных
Полное обновление источника пересчитывает кластеры заново, что может быть дорогостоящим.
3. Радиус кластеризации
Слишком маленький радиус приводит к большому количеству кластеров и увеличению нагрузки на рендеринг.
4. Использование vector tiles
Для больших наборов данных предпочтительнее использовать векторные тайлы вместо GeoJSON, так как они позволяют распределить нагрузку между сервером и клиентом.
Существует два основных подхода:
Преимущества:
Недостатки:
Преимущества:
Недостатки:
В реальных интерфейсах кластеризация редко используется в «голом» виде. Часто применяются комбинированные подходы:
Пример зависимости цвета от количества элементов:
'circle-color': [
'step',
['get', 'point_count'],
'#51bbd6',
100,
'#f1f075',
750,
'#f28cb1'
]
Кластеризация имеет ряд особенностей, которые необходимо учитывать при проектировании картографических интерфейсов:
Также важно учитывать, что кластеризация не является географически точной группировкой — это визуально-алгоритмическая оптимизация, основанная на экранных координатах, а не на реальных расстояниях в метрах.