Принципы кластеризации

Основы кластеризации точек

Кластеризация в Mapbox GL JS представляет собой механизм группировки большого количества точечных объектов на карте в обобщённые агрегированные элементы — кластеры. Это позволяет существенно снизить визуальную перегрузку карты и повысить производительность при работе с десятками тысяч объектов.

С точки зрения визуализации, кластер — это динамически вычисляемая сущность, которая заменяет набор близко расположенных точек единым представлением. При увеличении масштаба карта «разбивает» кластеры обратно на отдельные точки, обеспечивая плавную детализацию данных.

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


Алгоритмическая основа: Supercluster

В основе кластеризации Mapbox GL JS лежит алгоритм Supercluster — высокопроизводительный метод пространственной агрегации точек, оптимизированный для интерактивных карт.

Алгоритм работает по принципу иерархической группировки:

  • все точки индексируются в пространственной сетке
  • создаются промежуточные кластеры на разных уровнях зума
  • используется дерево пространственного разбиения
  • перерасчёт происходит инкрементально при изменении масштаба

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


Настройка источника данных

Кластеризация включается на уровне GeoJSON-источника. Базовая конфигурация выглядит следующим образом:

map.addSource('points', {
  type: 'geojson',
  data: geojsonData,
  cluster: true
});

После включения параметра cluster: true Mapbox GL JS автоматически начинает группировать точки при отрисовке.

Дополнительно источник может содержать параметры, влияющие на поведение кластеризации:

  • радиус кластеризации
  • максимальный зум кластеризации
  • пользовательские свойства кластеров

Радиус кластеризации (clusterRadius)

Параметр clusterRadius определяет расстояние в пикселях, в пределах которого точки считаются частью одного кластера.

clusterRadius: 50

Чем больше значение радиуса:

  • тем меньше кластеров на карте
  • тем более «агрессивно» происходит объединение
  • тем выше плотность данных внутри кластера

Чем меньше значение:

  • кластеры становятся более детализированными
  • увеличивается количество визуальных объектов
  • повышается нагрузка на рендеринг

Оптимальный выбор зависит от плотности данных и масштаба карты.


Максимальный уровень кластеризации (clusterMaxZoom)

Параметр clusterMaxZoom задаёт максимальный зум, на котором выполняется кластеризация.

clusterMaxZoom: 14

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

Это важно для сценариев, где:

  • на высоких масштабах требуется точная географическая детализация
  • кластеризация теряет смысл из-за редкого расположения объектов
  • необходимо показать индивидуальные элементы (например, здания или события)

Пользовательские свойства кластеров (clusterProperties)

Одной из наиболее мощных возможностей является вычисление агрегированных свойств кластера.

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, так как они позволяют распределить нагрузку между сервером и клиентом.


Серверная и клиентская кластеризация

Существует два основных подхода:

Клиентская кластеризация

Преимущества:

  • простота реализации
  • динамическая адаптация к фильтрам
  • отсутствие серверной логики

Недостатки:

  • ограничение по объёму данных
  • нагрузка на браузер

Серверная кластеризация

Преимущества:

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

Недостатки:

  • сложность инфраструктуры
  • менее гибкая интерактивность

Практические паттерны отображения

В реальных интерфейсах кластеризация редко используется в «голом» виде. Часто применяются комбинированные подходы:

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

Пример зависимости цвета от количества элементов:

'circle-color': [
  'step',
  ['get', 'point_count'],
  '#51bbd6',
  100,
  '#f1f075',
  750,
  '#f28cb1'
]

Особенности поведения и распространённые ограничения

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

  • кластеры пересчитываются при каждом изменении зума
  • точность кластеров зависит от текущей проекции и радиуса
  • при высокой плотности данных возможны «скачки» кластеров при зуме
  • порядок отображения слоёв влияет на восприятие кластеров и точек

Также важно учитывать, что кластеризация не является географически точной группировкой — это визуально-алгоритмическая оптимизация, основанная на экранных координатах, а не на реальных расстояниях в метрах.