cesium聚合效果(一):dataSource

1、概述

通过cesium中dataSource自带的clustering来实现billboard数据的聚合显示效果,并根据数据类别设置显示不同的billboard图标。

2、数据处理

将后端返回的json数据处理成标准的geojson格式,如果后端返回的数据或者使用的测试数据已是geojson格式,请忽略此处。

javascript 复制代码
//数据处理--后端返回数据转换成geojson数据
const data2Geojson = (data) => {
    const geojson = {
        "type": "FeatureCollection",
        "features": []
    }
    data.forEach(item => {
        geojson.features.push({
            "type": "Feature",
            "geometry": {
                "type": "Point",
                "icon": item.icon,
                "coordinates": [parseFloat(item.longitude), parseFloat(item.latitude)]
            },
            "properties": {
                ...item
            }
        })
    })
    return geojson;
}

3、聚合实现

加载geojson数据,完成聚合效果的显示和清除操作。

ini 复制代码
import pic from "@/assets/clusterIcon/facility.gif";  //默认billboard
import cluster1 from "@/assets/clusterIcon/cluster1.png";  
import cluster2 from "@/assets/clusterIcon/cluster2.png";  
import cluster3 from "@/assets/clusterIcon/cluster3.png";  
//实现聚合效果
let dataSourceCollection = null;
let dataSourcePromise = null;
const setEntityCluster = async(data) => {
    await removeEntityCluster(); //清除上一次绘制的聚合效果
    let geojson = await data2Geojson(data); //数据转换为geojson格式
    //读取geojson,并将数据源添加至DataSourceCollection
    dataSourceCollection = new Cesium.DataSourceCollection();
    dataSourcePromise = dataSourceCollection.add(Cesium.GeoJsonDataSource.load(geojson));
    dataSourcePromise.then(dataSource =>{
        // 加载geojson
        viewer.dataSources.add(dataSource);
        //命名用于后续删除
        dataSource.name = 'entityClusterGeojson';
        // 视角切换到geojson
        viewer.flyTo(dataSource.entities.values);
        //设置entity属性
        dataSource.entities.values.forEach(entity => {
            let properties = entity.properties;
            let icon = pic;
            if(properties.type._value == "1"){
                icon = cluster1;
            }else if(properties.type._value == "2"){
                icon = cluster2;
            }else{
                icon = cluster3;
            }
            entity.uuid = properties.id._value;
            entity.name = properties.name._value;
            entity.billboard = {
                image: icon,
                width: 36,
                height: 36,
            };
            entity.label = {
                show: true,
               text: properties.name._value || 'test',
                font: 'bold 15px Microsoft YaHei', 
                verticalOrigin: Cesium.VerticalOrigin.CENTER,// 竖直对齐方式
                horizontalOrigin: Cesium.HorizontalOrigin.LEFT,  // 水平对齐方式
                pixelOffset: new Cesium.Cartesian2(15, 0),// 偏移量
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,//贴地
                disableDepthTestDistance: Number.POSITIVE_INFINITY,//一直显示,不被地形等遮挡
            };
            entity.type = properties.type._value;
        })
        //聚合参数设置
        dataSource.clustering.enabled = true;  //开启聚合功能
        dataSource.clustering.pixelRange = 46;  //聚合像素范围
        dataSource.clustering.minimumClusterSize = 1; //最小聚合数量
        let removeListener;
         const customStyle = () => {
            if (Cesium.defined(removeListener)) {
                removeListener();
                removeListener = undefined;
            } else {
                removeListener = dataSource.clustering.clusterEvent.addEventListener(
                    (clusteredEntities, cluster) => {
                        if (cluster.label.id.length == 0 || !cluster.label.id[0]) {
                            cluster.label.show = false;
                            cluster.billboard.show = false;
                            return;
                        }
                        //设置聚合后billboard样式,当有多个图标时,显示第一个图标和对应label
                        const img = cluster.label.id[0].billboard.image._value;
                        cluster.label.show = true;
                        cluster.label.text = cluster.label.id[0].label.text._value || "";
                        cluster.label.showBackground = true;
                        cluster.label.verticalOrigin = Cesium.VerticalOrigin.CENTER;
                        cluster.label.horizontalOrigin = Cesium.HorizontalOrigin.CENTER;
                        cluster.label.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND;
                        cluster.label.disableDepthTestDistance = Number.POSITIVE_INFINITY;
                        cluster.label.pixelOffset = new Cesium.Cartesian2(0, 10);
                        cluster.label.font = " bold 15px Microsoft YaHei";
                        cluster.label.backgroundColor = Cesium.Color.ORANGE.withAlpha(0.2);
                        cluster.billboard.show = true;
                        cluster.billboard.id = cluster.label.id;
                        cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
                        cluster.billboard.width = 36;
                        cluster.billboard.height = 36;
                        cluster.billboard.image = img;
                        cluster.entityType = "entityCluster";
                        cluster.billboard.horizontalOrigin = Cesium.HorizontalOrigin.CENTER;
                        cluster.billboard.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND;
                        cluster.billboard.disableDepthTestDistance = Number.POSITIVE_INFINITY;
                    }
                )
            }
            const pixelRange = dataSource.clustering.pixelRange;
            dataSource.clustering.pixelRange = 0;
            dataSource.clustering.pixelRange = pixelRange;
        }
        //设置鼠标点击事件
        let isFirst = true; //设置标识,避免重复执行点击事件
        viewer.screenSpaceEventHandler.setInputAction((click) => {
            const pickedObject = viewer.scene.pick(click.position);
            if (pickedObject && pickedObject.id && pickedObject.id instanceof Array){
                //获取点击数据对象
                let obj = data.find((item) => item.id == pickedObject.id[0].uuid);
                if(obj && isFirst){
                    isFirst = false;
                    //自定义后续操作逻辑...
                    setTimeout(() => {
                        isFirst = true;
                    }, 1000)
                }  
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
        customStyle();//调用聚合监听事件
    })
    
   
}
//清除聚合
const removeEntityCluster = () =>{
    dataSourceCollection = dataSourceCollection && dataSourceCollection.destroy();
    if(dataSourcePromise){
        viewer.dataSources.remove(viewer.dataSources.getByName("entityClusterGeojson")[0])
    }
},

4、实现效果

项目地址:github.com/DLFouge/vue...

欢迎指正与star

相关推荐
猫猫不是喵喵.10 小时前
Vue3 Props 属性
前端·javascript·vue.js
小罗水17 小时前
第17章 后台管理端与演示支持
javascript·vue.js·ecmascript
猫猫不是喵喵.20 小时前
Vue3 中 computed 计算属性与 watch、watchEffect 监听
前端·javascript·vue.js
En^_^Joy20 小时前
Vue项目创建与入口配置全攻略
前端·vue.js·arcgis
猫猫不是喵喵.21 小时前
Vue2 的 Vuex 状态管理与 Vue3 的 Pinia 状态管理
前端·javascript·vue.js
林焱_RPAAI2 天前
影刀RPA技术深度:CSS选择器高级实战指南——伪类属性选择器与性能对比完全解析
vue.js·react.js
陳陈陳2 天前
🚀 前端流式输出革命:SSE + BFF 架构从零到一实战指南
vue.js·架构·node.js
黄泉路醉s2 天前
在Vant+Vue+TypeScript的H移动前端使用UnoCSS
前端·vue.js·typescript
我要两颗404西柚2 天前
Stage three:VUE工程化与实战工具
前端·javascript·vue.js
看昭奚恤哭2 天前
基于 RuoYi-Vue-Pro 定制了一个后台管理系统 magic-admin , 开源出来!
前端·vue.js·开源