告别冗余代码!Cesium点位图标模糊、重叠?自适应参数调优攻略,一次封装终身复用!

之前已经实现了在 Cesium 地图上加载模型# 数字孪生大屏必看:Cesium 3D 模型选中交互,3 种高亮效果拿来就用!,但是不可能所有的设备都以模型呈现出来,所以这里一些小的设备采用图标的形式进行展示。

最常见的就是监控类的图标,这里也是以监控类的图标为例,代码一把梭实现一下。

渲染图标的代码我这里也进行了简单的封装。

实现方案

Cesium 中实现自定义图标展示,核心依赖 Entity API + Billboard 组件

Entity用来封装地理空间数据,适合业务层点位管理。

另外Billboard 是Entity的子组件,专门用于渲染屏幕对齐的图像/图标

使用Billboard能够实现无论相机如何旋转,图标始终面向屏幕。

实现代码

建议图标使用 PNG 图片,而不是 SVG,在Cesium中png表现更好。

另外图标需要放在 public 文件夹下,避免出现打包丢失的情况。

有条件可以直接使用在线图标,更稳定。

javascript 复制代码
/**
 * 地图生成图标公共方法(封装)
 * @param {Object} options - 图标配置项
 * @param {Number} options.longitude - 图标经度
 * @param {Number} options.latitude - 图标纬度
 * @param {Number} options.height - 图标高度 (米)
 * @param {String} options.iconWidth - 图标宽度 (像素),默认值为32
 * @param {String} options.iconHeight - 图标高度 (像素),默认值为32
 * @param {String} options.iconUrl - 图标 URL
 * @param {Number} [options.scale=1.0] - 图标缩放比例
 * @param {String} [options.label] - 图标标签
 * @param {String} [options.id] - 图标唯一标识符(可选)
 * @returns {Cesium.Entity} 创建的图标实体
 */
const createIcon = (options) => {
    // 校验Viewer实例是否存在
    if (!viewer.value) {
        console.warn('Viewer 实例不存在,无法创建图标')
        return null
    }

    // 图标路径自动处理(兼容相对路径/绝对路径)
    let fullIconUrl = iconUrl
    if (!iconUrl.startsWith('http') && !iconUrl.startsWith('/')) {
        fullIconUrl = `/${iconUrl}`
    }

    const entity = viewer.value.entities.add({
        // 唯一ID
        id: id || `icon_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
        // 经纬度+高度转笛卡尔坐标
        position: Cesium.Cartesian3.fromDegrees(longitude, latitude, height),
        billboard: {
            image: fullIconUrl,                // 图标图片路径
            scale: scale,                      // 缩放比例
            width: options.iconWidth || 32,    // 图标宽度
            height: options.iconHeight || 32,  // 图标高度
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 底部对齐坐标点
            pixelOffset: new Cesium.Cartesian2(0, 0),     // 像素偏移
            eyeOffset: new Cesium.Cartesian3(0, 0, 0),    // 视点偏移
            // 距离自适应缩放
            scaleByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 1.5e7, 0.5),
            translucencyByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 1.5e7, 0.0),
            // 关闭深度检测,图标始终显示在最前面
            disableDepthTestDistance: Number.POSITIVE_INFINITY
        }
    })

    // 图标标签(可选)
    if (label) {
        entity.label = {
            text: label,                      // 标签文字
            font: '14px sans-serif',          // 字体样式
            fillColor: Cesium.Color.WHITE,    // 文字填充色
            outlineColor: Cesium.Color.BLACK,// 文字描边色
            outlineWidth: 2,                 // 描边宽度
            style: Cesium.LabelStyle.FILL_AND_OUTLINE, // 填充+描边
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            pixelOffset: new Cesium.Cartesian2(0, -40), // 标签向上偏移
            showBackground: true,            // 显示背景底板
            backgroundColor: new Cesium.Color(0.165, 0.165, 0.165, 0.8), // 背景色
            backgroundPadding: new Cesium.Cartesian2(7, 5),
            disableDepthTestDistance: Number.POSITIVE_INFINITY // 标签置顶
        }
    }

    return entity
};

注意:这里其实我是建议将生成图标的方法写入 cesium-view 这种 cesium地图 自己封装的组件中的。

如果将生成图标的放在放在组件外,需要考虑加载时机等问题。

javascript 复制代码
// 业务层调用
const loadCameraIcon = () => {
    // 摄像头点位数据(可替换为后端接口返回数据)
    const cameraList = [
        {
            longitude: 117.106447,
            latitude: 36.436758,
            height: 3,
            label: '摄像头1',
            iconUrl: '/images/枪形摄像头.png',
        },
        {
            longitude: 117.106590,
            latitude: 36.437983,
            height: 3,
            label: '摄像头2',
            iconUrl: '/images/球形摄像头.png',
        },
    ];
    cameraList.forEach((camera) => {
        cesiumViewRef.value.createIcon(camera);
    });
};

可优化部分

还可以增加 距离自适应 效果。避免出现远距离图标密集重叠、渲染性能损耗大等情况。

javascript 复制代码
// 缩放:150米内正常大小,1500万米外缩小为0.5倍
scaleByDistance: new Cesium.NearFarScalar(150, 1.0, 15000000, 0.5)
// 透明度:150米内完全显示,1500万米外完全透明
translucencyByDistance: new Cesium.NearFarScalar(150, 1.0, 15000000, 0.0)

除此之外有需求的话可以添加图标置顶显示。让图标始终显示在地形、三维模型前方,不会被遮挡。

javascript 复制代码
disableDepthTestDistance: Number.POSITIVE_INFINITY

总结

地图上实现图标是常见需求,毕竟不可能每一个设备一个模型,加载就是个大问题。

更不要说模型本身也是需要花钱的。

如果有需要可以增加距离自适应效果,或者可以等一下后期我实现的图标聚合效果。

相关推荐
sz_denny2 小时前
chrome os 如何进入开发者模式
前端·chrome
踩着两条虫2 小时前
🔥 实测对比:VTJ.PRO凭啥让头部企业放弃自研低代码?
前端·vue.js·ai编程
han_2 小时前
JavaScript 检测网络连接状态,以及网络测速方案
前端·javascript
小李子呢02112 小时前
JavaScript 中 Map 的完整解析
前端·javascript·vue.js
木梓辛铭2 小时前
关于Chrome无法上网的问题2
前端·chrome
Shirley~~2 小时前
ElementUI Carousel 取消hover暂停轮播的默认行为
前端·javascript·vue.js
品克缤2 小时前
解决 SVG 作为 CSS 背景图无法 background-size: 100% 100% 拉伸的问题
前端·css·vue.js·css3
小彭努力中2 小时前
190.Vue3 + OpenLayers 实战:实现地图旋转移动动画 + CSS缩放动画(详解 animate 用法)
前端·css·openlayers·cesium·webgis
Mintopia2 小时前
从架构起步:如何在软件开发初期决定交付速度与质量
前端·架构