cesium实现点聚合效果

该博客介绍了如何使用Cesium的EntityCluster接口实现地图上的点聚合功能,包括官方API的使用、自定义聚合图标的方法。通过调整像素范围和最小聚合数量,实现不同级别的聚合效果。同时,根据聚合数量动态合成新图标,提供了代码示例展示如何结合图片和文字生成聚合图标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Cesium实战系列文章总目录传送门

1.实现效果

在这里插入图片描述

2.实现方法

2.1官方API

Cesium官方提供了EntityCluster接口,可以实现广告牌、点、标签的聚合效果。
官方API:传送门
在这里插入图片描述官方文档中EntityCluster的配置项参数:

属性说明
enabled是否开启聚合功能
pixelRange开启聚合的像素边界范围大小
minimumClusterSize最少聚合对象的数量
clusterBillboards是否聚合广告牌
clusterLabels是否聚合标签
clusterPoints是否聚合点
shows即聚合后是否显示

官方沙盒聚合例子参考:传送门

2.2聚合图标

2.2.1原始图标

Cesium提供的图标,由PinBuilder类提供
官方API:传送门
在这里插入图片描述
可以在原始图标中添加新图标或者文字的形式生成新图标,但新图标的外形样式是固定的。

2.2.2 自定义图片

也可以根据聚合数量进行分级设置不同的聚合图标。

2.2.3 图片文字合成新图标

本文使用固定的分级图标与聚合点位数量实时合成新图标的方式。

具体将图片与文字合成新图标的方法可以参考上一篇博客:传送门

2.3代码实现:

总体实现代码如下:

/**
 * @description: 点聚合功能效果
 * @param {*} viewer
 * @return {*}
 */
function initCluster(viewer) {
    new Cesium.GeoJsonDataSource().load("./data/sz_poi.geojson").then(dataSource => {
        viewer.dataSources.add(dataSource);

        // 设置聚合参数
        dataSource.clustering.enabled = true;
        dataSource.clustering.pixelRange = 60;
        dataSource.clustering.minimumClusterSize = 2;

        // foreach用于调用数组的每个元素,并将元素传递给回调函数。
        dataSource.entities.values.forEach(entity => {
            // 将点拉伸一定高度,防止被地形压盖
            entity.position._value.z += 50.0;
            // 使用大小为64*64的icon,缩小展示poi
            entity.billboard = {
                image: './icons/poi.png',
                width: 32,
                height: 32,
            };
            entity.label = {
                text: 'POI',
                font: 'bold 15px Microsoft YaHei',
                // 竖直对齐方式
                verticalOrigin: Cesium.VerticalOrigin.CENTER,
                // 水平对齐方式
                horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
                // 偏移量
                pixelOffset: new Cesium.Cartesian2(15, 0),
            }
        });

        // 添加监听函数
        dataSource.clustering.clusterEvent.addEventListener(
            function(clusteredEntities, cluster) {
                // 关闭自带的显示聚合数量的标签
                cluster.label.show = false;
                cluster.billboard.show = true;
                cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;

                // 根据聚合数量的多少设置不同层级的图片以及大小
                if (clusteredEntities.length >= 20) {
                    cluster.billboard.image = combineIconAndLabel('./icons/cluster_4.png', clusteredEntities.length, 64);
                    cluster.billboard.width = 72;
                    cluster.billboard.height = 72;
                } else if (clusteredEntities.length >= 12) {
                    cluster.billboard.image = combineIconAndLabel('./icons/cluster_3.png', clusteredEntities.length, 64);
                    cluster.billboard.width = 56;
                    cluster.billboard.height = 56;
                } else if (clusteredEntities.length >= 8) {
                    cluster.billboard.image = combineIconAndLabel('./icons/cluster_2.png', clusteredEntities.length, 64);
                    cluster.billboard.width = 48;
                    cluster.billboard.height = 48;
                } else {
                    cluster.billboard.image = combineIconAndLabel('./icons/cluster_1.png', clusteredEntities.length, 64);
                    cluster.billboard.width = 40;
                    cluster.billboard.height = 40;
                }
            }
        )
    });
}


/**
 * @description: 将图片和文字合成新图标使用(参考Cesium源码)
 * @param {*} url:图片地址
 * @param {*} label:文字
 * @param {*} size:画布大小
 * @return {*} 返回canvas
 */
function combineIconAndLabel(url, label, size) {
    // 创建画布对象
    let canvas = document.createElement('canvas');
    canvas.width = size;
    canvas.height = size;
    let ctx = canvas.getContext("2d");

    let promise = new Cesium.Resource.fetchImage(url).then(image => {
        // 异常判断
        try {
            ctx.drawImage(image, 0, 0);
        } catch (e) {
            console.log(e);
        }

        // 渲染字体
        // font属性设置顺序:font-style, font-variant, font-weight, font-size, line-height, font-family
        ctx.fillStyle = Cesium.Color.WHITE.toCssColorString();
        ctx.font = 'bold 20px Microsoft YaHei';
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText(label, size / 2, size / 2);

        return canvas;
    });
    return promise;
}

### 如何在 Cesium实现聚合效果 #### 使用 `Entity` 图元进行简单聚合 对于较小规模的数据集,可以直接利用 Cesium 的 `Entity` 来创建聚类效果。这种方式易于上手,适合初学者快速构建应用。 ```javascript // 创建一个 viewer 对象 const viewer = new Cesium.Viewer('cesiumContainer'); // 定义要聚集的实体数组 let entities = []; for (let i = 0; i < 100; ++i) { let position = Cesium.Cartesian3.fromDegrees( -75.59774 + Math.random() * 0.2, 40.03726 + Math.random() * 0.2 ); // 添加单个 entity 到集合中 entities.push(viewer.entities.add({ name : 'Random point', position : position, billboard : { image : './path/to/icon.png', // 自定义图标路径 scale : 0.5 } })); } // 应用 EntityCluster 插件来处理这些实体 viewer.scene.primitives.add(new Cesium.EntityCluster()); ``` 此方法适用于展示少量位置标记的情况[^2]。然而当面对成千上万个地理坐标时,则需考虑更高效的解决方案以保持良好的交互体验。 #### 大规模数据下的高性能聚合方案 针对海量数据场景,推荐使用原始几何体 (`Primitive`) 或者 Web Worker 技术来进行离屏渲染与计算密集型任务分离,从而减轻主线程负担并提高整体效率。 通过引入第三方库如 `supercluster` 可进一步优化大规模空间数据分析流程: ```bash npm install supercluster --save ``` 接着可以在 JavaScript 文件内集成如下逻辑片段完成高效的空间索引建立及可视化呈现: ```javascript import Supercluster from 'supercluster'; // 初始化超级集群实例 const index = new Supercluster({ radius: 40, // 聚合半径大小(px) maxZoom: 16 // 最大缩放级别 }); // 准备输入特征列表 const features = [ { type: "Feature", geometry: {type:"Point", coordinates:[lon,lat]}, properties:{ count:1 } }, ... ]; index.load(features); function renderClusters(zoomLevel){ const clusters = index.getClusters([-180,-85,180,85], zoomLevel); // 清除现有图形元素... while (viewer.entities.values.length > 0){ viewer.entities.removeById(viewer.entities.values[0].id); } // ...重新绘制新的聚合结果 for(const cluster of clusters){ if(cluster.properties.cluster){ addClusterMarker(cluster.geometry.coordinates, cluster.properties.point_count_abbreviated || ''); }else{ addSingleMarker(cluster.geometry.coordinates); } } } ``` 上述代码展示了如何借助外部工具提升性能的同时维持良好用户体验的方法[^1]。 #### 常见问题及其解决办法 有时开发者可能会遇到某些特定情况下的异常现象,比如自定义图像未能正常显示的问题。这通常是因为未指定正确的材质属性所致。确保在初始化阶段就指定了合适的纹理资源能够有效规避此类难题[^4]。
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

右弦GISer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值