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

相关推荐
2301_322414280418 小时前
活力孕康复APP 47737- 原创(免费领源码+部署教程+开发环境)
java·vue.js·spring boot·mysql·微信小程序·idea·微信开发者工具
专业程序开发源20 小时前
springbootLivehouse票务系统-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·django·课程设计·pygame
leoZ23120 小时前
2026-09-10-静态扫描连错三次-用运行环境当裁判
前端·javascript·vue.js·人工智能·opencv·机器学习·数据挖掘
卓怡学长20 小时前
w233基于vue和springboot的宠物管理系统的设计与实现
java·vue.js·spring boot·spring·intellij-idea
梨涡泥窝1 天前
JavaWeb——基于 Spring Boot + Vue 的图书管理系统的设计与实现
vue.js·spring boot·后端
huali1 天前
vue-split-screen:让 Vue Router 的导航轨迹变成两个页面
前端·javascript·vue.js
雪芽蓝域zzs1 天前
第三十六节:keep-alive 页面缓存(Vue3 + 后台管理系统)
前端·vue.js·缓存
边境悍匪1 天前
蜗牛学苑 Java 智能体学习 Day41|ElementPlus 布局、Vue‑Router 登录、Axios 思维导图复盘
java·vue.js·学习
志尊宝1 天前
Vue3 零基础每日笔记(017):事件处理进阶——$event、多事件与事件修饰符全家桶
javascript·vue.js·笔记
Bs_MoneyMagnet2 天前
基于springboot+vue的医疗健康便民服务平台的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring