Кластеризация в CesiumJS применяется для оптимизации отображения большого количества точечных объектов на глобусе. При увеличении плотности данных отдельные сущности объединяются в группы (кластеры), что снижает нагрузку на рендеринг и улучшает читаемость сцены.
Основной механизм кластеризации реализован на уровне
DataSource и применяется к сущностям (Entity),
добавленным через GeoJsonDataSource,
KmlDataSource или пользовательские источники данных.
Кластеризация основана на объединении объектов, попадающих в один экранный радиус в пикселях. Cesium использует параметр экранного расстояния, а не географическое, что обеспечивает стабильность визуального результата при разных уровнях масштабирования.
Ключевые характеристики:
ClusteringКластеризация активируется через объект clustering,
доступный у любого DataSource.
const dataSource = new Cesium.GeoJsonDataSource();
viewer.dataSources.add(dataSource);
dataSource.clustering.enabled = true;
dataSource.clustering.pixelRange = 50;
dataSource.clustering.minimumClusterSize = 3;
enabled
booleanpixelRange
minimumClusterSize
При включенной кластеризации Cesium автоматически:
Кластер не является отдельной сущностью сцены, а представляет собой временную визуализацию.
Cesium предоставляет событие clusterEvent, позволяющее
полностью управлять внешним видом кластеров.
const clustering = dataSource.clustering;
clustering.clusterEvent.addEventListener(function(
clusteredEntities,
cluster
) {
cluster.label.show = true;
cluster.label.text = clusteredEntities.length.toString();
cluster.billboard.show = true;
});
clustering.clusterEvent.addEventListener(function(entities, cluster) {
cluster.billboard.image = '/images/cluster.png';
cluster.billboard.scale = 0.8;
});
Возможна генерация иконки в зависимости от размера кластера:
clustering.clusterEvent.addEventListener(function(entities, cluster) {
const count = entities.length;
if (count > 50) {
cluster.billboard.image = '/icons/cluster-large.png';
} else if (count > 10) {
cluster.billboard.image = '/icons/cluster-medium.png';
} else {
cluster.billboard.image = '/icons/cluster-small.png';
}
});
Cesium позволяет создавать изображения кластеров на лету:
function createClusterCanvas(count) {
const canvas = document.createElement('canvas');
canvas.width = 64;
canvas.height = 64;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#2E86AB';
ctx.beginPath();
ctx.arc(32, 32, 28, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#FFFFFF';
ctx.font = 'bold 20px sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(count, 32, 32);
return canvas;
}
clustering.clusterEvent.addEventListener(function(entities, cluster) {
cluster.billboard.image = createClusterCanvas(entities.length);
});
Label внутри кластера используется для отображения количества объектов или дополнительной информации.
clustering.clusterEvent.addEventListener(function(entities, cluster) {
cluster.label.text = `${entities.length}`;
cluster.label.font = 'bold 14px sans-serif';
cluster.label.fillColor = Cesium.Color.WHITE;
cluster.label.style = Cesium.LabelStyle.FILL_AND_OUTLINE;
});
При изменении масштаба кластеры распадаются автоматически, но можно
отследить процесс через повторное срабатывание clusterEvent
и изменение состава массива clusteredEntities.
Структура событий:
clusterEventGeoJSON является наиболее частым источником точек для кластеризации.
const geoJson = new Cesium.GeoJsonDataSource();
viewer.dataSources.add(geoJson);
geoJson.load('points.geojson').then(function() {
geoJson.clustering.enabled = true;
geoJson.clustering.pixelRange = 60;
});
Каждая точка GeoJSON автоматически превращается в
Entity, участвующий в кластеризации.
Для KML используется аналогичный механизм:
const kmlDataSource = new Cesium.KmlDataSource();
viewer.dataSources.add(kmlDataSource);
kmlDataSource.load('data.kml').then(function() {
kmlDataSource.clustering.enabled = true;
kmlDataSource.clustering.pixelRange = 40;
});
KML-структуры с большим количеством placemark особенно выигрывают от кластеризации.
Кластеризация тесно связана с камерой Viewer:
Параметры камеры, влияющие на кластеризацию:
Кластеризация является ключевым инструментом оптимизации при работе с тысячами объектов.
Эффект оптимизации достигается за счёт:
Рекомендуемые настройки:
dataSource.clustering.pixelRange = 50;
dataSource.clustering.minimumClusterSize = 5;
При слишком большом pixelRange:
При слишком маленьком:
Cesium автоматически скрывает отдельные сущности, но их состояние сохраняется.
Можно дополнительно управлять логикой:
clustering.clusterEvent.addEventListener(function(entities, cluster) {
entities.forEach(function(entity) {
entity.show = false;
});
cluster.label.text = String(entities.length);
});
Хотя встроенная кластеризация основана на пиксельном радиусе, можно реализовать расширенную логику:
Пример условной фильтрации:
clustering.clusterEvent.addEventListener(function(entities, cluster) {
const highPriority = entities.filter(e => e.properties.priority === 1);
cluster.label.text = `${highPriority.length}/${entities.length}`;
});
Entity-уровнем данныхPrimitiveПри добавлении новых сущностей кластеризация пересчитывается автоматически:
dataSource.entities.add({
position: Cesium.Cartesian3.fromDegrees(30, 50),
point: { pixelSize: 10 }
});
Новые объекты немедленно участвуют в существующей кластерной структуре без дополнительных вызовов обновления.