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

相关推荐
秃头网友小李4 天前
前端难点:keep-alive 缓存什么?RouterView 的 key 为什么要带 scopeId?
前端·vue.js
徐小夕4 天前
JitWord 3.0 正式发布,高精度Word异构解析+复杂组件兼容,打造web端协同Word编辑器
前端·vue.js·算法
奋斗吧程序媛4 天前
补充一个小知识点:有关@click.native
前端·vue.js
英勇无比的消炎药5 天前
一行命令背后:TinyRobot CLI 如何重构 AI 对话接入的效率范式
vue.js·aigc
jay神5 天前
基于 FastAPI + Vue 的宠物领养管理系统
前端·vue.js·python·毕业设计·fastapi·宠物
一杯奶茶¥5 天前
水果销售网站 CRM客户信息管理系统 超市管理系 酒店管理系统 健身房管理系统 在线音乐网站 校园招聘系统
java·vue.js·spring boot·mysql·spring·java项目
英勇无比的消炎药5 天前
一站式搞定品牌风格:TinyRobot 主题定制从入门到精通
vue.js
尽欢i5 天前
Vue3 customRef 封神教程:防抖、本地存储、自动埋点一套搞定,模板干干净净
前端·javascript·vue.js
因_崔斯汀5 天前
Vue 模板编译:HTML 是怎么变成 JS 的?
前端·vue.js
英勇无比的消炎药5 天前
样式随心定制:TinyRobot 样式覆写与 CSS 变量实战解析
vue.js