cesium编程中级(十七) label 遮挡?3种情况+解决方案全在这里

CesiumJS label 遮挡?3种情况+解决方案全在这里

写在前面

CesiumJS 项目中,label 压盖是个常见问题。但很多人不知道的是,压盖其实分三种情况:聚合压盖、地形压盖、线段压盖。每种情况的成因不同,解决方案也不同。今天把解决方案系统整理出来,建议收藏。


一、聚合压盖:多个标注挤在一起

问题表现

当标注点过于密集时,文字全部堆叠在一起,根本分不清谁是谁。比如智慧城市几千个建筑标注,缩放到城市级别时全部重叠。

解决方案:聚类(Clustering)

这是 CesiumJS 内置功能,当标注过于密集时自动合并显示。

00

// 创建数据源
const dataSource = new Cesium.CustomDataSource('equipment');

// 添加设备点位
dataSource.entities.add({
    position: Cesium.Cartesian3.fromDegrees(116.4, 39.9, 10),
    name: '设备A',
    label: {
        text: '设备A',
        font: '14px sans-serif',
        fillColor: Cesium.Color.WHITE,
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 2,
        style: Cesium.LabelStyle.FILL_AND_OUTLINE
    }
});

// 启用聚类
dataSource.clustering.enabled = true;
dataSource.clustering.pixelRange = 15;      // 像素范围
dataSource.clustering.minimumClusterSize = 3;  // 最小聚类数量

// 自定义聚类样式
dataSource.clustering.clusterEvent.addEventListener(function(cluster, entity) {
    entity.label = {
        text: cluster.length + '个设备',
        font: '16px sans-serif',
        fillColor: Cesium.Color.WHITE,
        pixelOffset: new Cesium.Cartesian2(0, 0)
    };
    entity.point = {
        pixelSize: 10,
        color: Cesium.Color.ORANGE
    };
    entity.billboard = {
        image: '/images/cluster.png',
        scale: 1.0
    };
});

viewer.dataSources.add(dataSource);

效果:缩放地图时,密集点位自动合并为一个数字标注,点击展开。

适用场景:数据量大、需要概览展示的场景,如智慧城市、港口调度、电力线路巡检。

“一个好的 CesiumJS 应用,不是它能加载多少数据,而是它在有限的资源下呈现得多好。”


二、地形压盖标注:标注消失在山体里

问题表现

开启了地形(Terrain)后,标注突然消失或者半截藏在地形里。这是因为 depthTestAgainstTerrain 默认开启,地形会遮挡标注。

这是 CesiumJS 官方都头疼的问题(GitHub Issue #2694),至今没有完美解决方案。

00

解决方案

方案1:禁用深度测试(最常用)

// 全局禁用地形深度测试(不推荐,会影响3D模型)
viewer.scene.globe.depthTestAgainstTerrain = false;

// 推荐:针对单个 label 禁用深度测试
entity.label = {
    text: '设备A',
    disableDepthTestDistance: Number.POSITIVE_INFINITY,  // 始终显示在最上层
    heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
};

disableDepthTestDistance 参数说明:

  • Number.POSITIVE_INFINITY:永远不参与深度测试,始终显示在最上层
  • 具体数值(如 5000):距离相机小于该值时不参与深度测试
// 智能深度测试:距离远时允许遮挡,近距离时始终显示
entity.label = {
    text: '设备A',
    disableDepthTestDistance: new Cesium.NearFarScalar(500, 0, 5000, Number.POSITIVE_INFINITY)
};

方案2:通过 position 设置高度

// 不使用 CLAMP_TO_GROUND,而是直接设置一个高于地面的固定高度
entity.label = {
    text: '设备A',
    position: Cesium.Cartesian3.fromDegrees(116.4, 39.9, 50),  // 距离地表 50 米
    // 这样标注不会贴地,而是悬浮在一定高度
};

注意:这种方式适合平坦区域,如果地形起伏大,固定高度可能仍然被遮挡。


三、线段压盖标注:标注被线遮挡

问题表现

标注在多边形(Polygon)或折线(Polyline)附近时,被它们遮挡。这是 WebGL 渲染顺序的问题,后添加的 entity 会先渲染。

00

解决方案

使用 labelCollection 置顶显示

let labelCollection = new Cesium.LabelCollection();
scene.primitives.add(labelCollection);
scene.primitives.raiseToTop(labelCollection); 

labelCollection.add({
  position: midpoint,
  text: `${distance.toFixed(2)} m`,
  font: "14px monospace",
  showBackground: true,
  horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
  verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
  pixelOffset: new Cesium.Cartesian2(0, 0),
  disableDepthTestDistance: Number.POSITIVE_INFINITY,
  eyeOffset: new Cesium.Cartesian3(0, 0, -1),
  fillColor: Cesium.Color.WHITE,
});

00


总结

  1. 聚合压盖:用聚类功能,自动合并密集点位
  2. 地形压盖:设置 disableDepthTestDistance,或关闭 depthTestAgainstTerrain
  3. 线段压盖:禁用深度测试 + 使用LabelCollection,调整添加顺序

推荐阅读


📮 联系我

如果你有 CesiumJS 项目开发需求,或者需要:

  • 数据处理:GeoJSON、Shapefile、KML 等格式转换,坐标系统转换,模型转3dtiles
  • 三维特效:粒子效果、动态标注、路径动画
  • 性能优化:大规模数据加载、渲染优化
  • 定制开发:行业可视化解决方案

欢迎联系,共同探讨解决方案。

发表评论