GetClusterExpansionZoom

При работе с большими наборами геоданных в Mapbox GL JS ключевой механизм оптимизации отображения — кластеризация точек через GeoJSON source. Кластеры объединяют близко расположенные точки в единые объекты, уменьшая нагрузку на рендеринг и повышая читаемость карты при низких масштабах.

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


Конфигурация кластеризованного источника

Кластеризация включается на уровне источника данных:

map.addSource('points', {
  type: 'geojson',
  data: 'data.geojson',
  cluster: true,
  clusterRadius: 50,
  clusterMaxZoom: 14
});

Ключевые параметры:

  • cluster — активирует группировку точек
  • clusterRadius — радиус объединения точек в пикселях
  • clusterMaxZoom — максимальный zoom, на котором происходит кластеризация

После активации источника Mapbox автоматически создаёт три типа данных:

  • отдельные точки
  • кластерные объекты
  • метаданные кластеров (count, cluster_id)

Назначение GetClusterExpansionZoom

Метод getClusterExpansionZoom возвращает масштаб (zoom level), на котором выбранный кластер «раскроется» и разделится на более мелкие кластеры или отдельные точки.

Это значение вычисляется динамически на основе внутреннего индекса кластеризации и текущей структуры данных.

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


Сигнатура метода

Метод вызывается через источник данных:

map.getSource('points').getClusterExpansionZoom(clusterId, callback);

Где:

  • clusterId — уникальный идентификатор кластера (cluster_id)
  • callback — функция, получающая результат

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

Частый сценарий — обработка клика по кластеру и плавное приближение к уровню раскрытия:

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) => {
    if (err) return;

    map.easeTo({
      center: features[0].geometry.coordinates,
      zoom: zoom
    });
  });
});

Принцип работы метода

Внутренне Mapbox GL JS:

  1. Определяет кластер по cluster_id
  2. Обращается к индексу кластеров Supercluster
  3. Рассчитывает минимальный zoom, при котором кластер перестаёт существовать как единый объект
  4. Возвращает это значение в callback

Важно понимать: возвращаемый zoom не является фиксированным значением данных, он вычисляется динамически в зависимости от текущей конфигурации источника.


Поведение при разных уровнях zoom

Кластеры существуют только в диапазоне от minZoom до clusterMaxZoom.

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

Использование с flyTo и easeTo

На практике метод часто комбинируется с анимацией камеры:

map.getSource('points').getClusterExpansionZoom(clusterId, (err, zoom) => {
  map.flyTo({
    center: coordinates,
    zoom: zoom
  });
});

Разница между методами анимации:

  • easeTo — плавное изменение без ускорения
  • flyTo — анимация с эффектом полёта и кривой движения

Взаимодействие с clusterLeaves и clusterChildren

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

  • getClusterLeaves(clusterId, limit, offset, callback) — получение объектов внутри кластера
  • getClusterChildren(clusterId, callback) — получение непосредственных дочерних элементов

Однако в отличие от них, getClusterExpansionZoom не возвращает данные, а только вычисляет оптимальный масштаб для раскрытия структуры.


Практическая модель данных кластеров

Каждый кластер в GeoJSON источнике содержит свойства:

{
  "cluster": true,
  "cluster_id": 123,
  "point_count": 45,
  "point_count_abbreviated": 45
}

cluster_id является ключом для всех операций кластерного API, включая getClusterExpansionZoom.


Поведение при ошибках

В callback первым аргументом может быть ошибка:

(err, zoom) => {}

Возможные причины:

  • неверный cluster_id
  • источник не содержит кластеров
  • данные ещё не загружены
  • источник не поддерживает кластеризацию

Производительность и особенности расчёта

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

Особенности:

  • вычисление происходит на основе precomputed tiles
  • не требует повторного прохода по всем данным
  • работает в рамках текущего состояния источника
  • зависит от параметров clusterRadius и clusterMaxZoom

Изменение этих параметров полностью меняет поведение результата.


Типичные сценарии применения

Центрирование на кластер с автоматическим раскрытием

map.on('click', 'clusters', (e) => {
  const cluster = map.queryRenderedFeatures(e.point, {
    layers: ['clusters']
  })[0];

  const clusterId = cluster.properties.cluster_id;

  map.getSource('points').getClusterExpansionZoom(clusterId, (err, zoom) => {
    map.easeTo({
      center: cluster.geometry.coordinates,
      zoom
    });
  });
});

Интеграция с интерфейсом списка объектов

При выборе элемента списка можно синхронизировать карту:

function zoomToCluster(clusterId, coordinates) {
  map.getSource('points').getClusterExpansionZoom(clusterId, (err, zoom) => {
    map.flyTo({
      center: coordinates,
      zoom
    });
  });
}

Использование для предварительного расчёта навигации

Метод применяется для построения логики UI:

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

Связь с внутренним алгоритмом Supercluster

Кластеризация Mapbox GL JS базируется на пространственном индексе, где:

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

getClusterExpansionZoom фактически запрашивает минимальный уровень, при котором кластер перестаёт существовать как агрегат.


Ограничения метода

  • работает только с источниками типа GeoJSON с включённой кластеризацией
  • не применим к non-clustered слоям
  • зависит от уже загруженных данных источника
  • не возвращает геометрию или дочерние элементы

Поведение при высокой плотности данных

При большом количестве точек:

  • кластер может сохраняться на высоких zoom уровнях
  • значение expansion zoom может быть близко к clusterMaxZoom
  • возможны ситуации, когда кластер распадается только при максимальном увеличении

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


Использование в сложных интерфейсах

В более сложных системах метод применяется как часть связки:

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

Он выступает как связующее звено между пространственной структурой данных и логикой UI-слоя карты