Cesium快速入门到精通系列教程二十三:综合

一、viewer.cesiumWidget.container.appendChild()

把你自定义的 HTML 元素(弹窗、按钮、图标等)添加到 Cesium 画布的容器里,让它显示在 3D 地球场景上。

复制代码
// 1. 创建一个自定义弹窗 div
const infoDiv = document.createElement('div');
infoDiv.style.position = 'absolute';
infoDiv.style.top = '100px';
infoDiv.style.left = '100px';
infoDiv.style.background = 'white';
infoDiv.style.padding = '10px';
infoDiv.innerHTML = '我是显示在地球上的自定义弹窗!';

// 2. 关键:把 div 添加到 Cesium 根容器
viewer.cesiumWidget.container.appendChild(infoDiv);

二、viewer..entities.values作用

viewer.entities.values 是一个数组,里面包含了你在 Cesium 中添加的所有实体(点、线、面、标注、模型等),可以用来遍历、查询、修改、删除全部实体。

核心作用(最常用)

① 遍历所有实体(最常用)

批量修改、隐藏、删除所有实体:

复制代码
// 遍历场景中所有实体
viewer.entities.values.forEach(entity => {
  // 示例1:隐藏所有实体
  entity.show = false;

  // 示例2:修改所有点的颜色
  if (entity.point) {
    entity.point.color = Cesium.Color.RED;
  }
});

② 获取实体总数

复制代码
const count = viewer.entities.values.length;
console.log('场景中共有实体:', count);

③ 清空所有实体(替代 removeAll())

复制代码
// 清空所有实体
viewer.entities.removeAll();

// 等价于遍历删除(不推荐,仅理解用)
viewer.entities.values.forEach(entity => {
  viewer.entities.remove(entity);
});

④ 查找符合条件的实体

复制代码
// 查找所有名称为 "测试点" 的实体
const targetEntities = viewer.entities.values.filter(e => e.name === '测试点');

三、viewer.scene.canvas.height

viewer.scene.canvas.height 用来获取 / 设置 Cesium 3D 地球画布的高度(像素值),直接控制地球显示区域的高度大小。

  • viewer.scene.canvas

→ Cesium 真正渲染 3D 地球的画布元素(就是一个 <canvas> HTML 标签)

  • .height

→ 这个 canvas 元素的高度属性(单位:像素 px)

核心作用

① 获取当前地球画布的真实高度(只读常用)

复制代码
// 获取当前 Cesium 画布高度(像素)
const canvasHeight = viewer.scene.canvas.height;
console.log('地球高度:', canvasHeight); 

② 动态修改地球高度(很少直接用)

复制代码
// 强制把地球高度改成 500px
viewer.scene.canvas.height = 500;

正确获取显示高度:用 offsetHeight

如果你想知道页面上实际显示的地球高度,要用:

复制代码
viewer.scene.canvas.offsetHeight   // 真实显示高度(推荐)

因为:

canvas.height = 绘图分辨率高度(内部渲染尺寸)

canvas.offsetHeight = 页面显示高度(肉眼看到的尺寸)

两者不一定相等!

四、viewer.scene.postRender.addEventListener()

在 Cesium 地球每完成一帧渲染之后 **,自动执行你指定的代码,用来做实时更新、动画、跟随、动态效果等。

1. 它到底是什么?

viewer.scene.postRender

→ 渲染完成事件(每一帧渲染完都会触发一次)

addEventListener()

→ 给这个事件绑定一个监听函数

简单理解:

Cesium 地球每秒会刷新 60 次(60 帧)

每刷新完一帧画面,就立刻执行一次你写的函数

相当于一个无限循环的实时更新器

2. 核心作用(最常用场景)

它专门用来做必须实时更新的功能:

让弹窗 / 标签 跟随 3D 点位移动(最常用!)

动态修改实体属性(位置、颜色、大小)

自定义动画效果

实时计算相机位置

实时更新 UI 数据

3. 最典型使用示例(点位跟随弹窗)

复制代码
// 1. 创建一个自定义 HTML 弹窗
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.color = 'white';
div.innerHTML = '我会跟着点位动';
viewer.cesiumWidget.container.appendChild(div);

// 2. 重点:每帧渲染后都更新弹窗位置
viewer.scene.postRender.addEventListener(() => {
    // 实时把 3D 坐标 → 屏幕坐标
    const canvasPosition = viewer.scene.cartesianToCanvasCoordinates(你的3D坐标);
    
    if (canvasPosition) {
        // 让弹窗跟着点位走
        div.style.left = canvasPosition.x + 'px';
        div.style.top = canvasPosition.y + 'px';
    }
});

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>实体实时流畅移动</title>
    <!-- 引入Cesium库 -->
    <link
      href="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Widgets/widgets.css"
      rel="stylesheet"
    />
    <script src="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js"></script>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font-family: "Arial", sans-serif;
        background-color: #000;
        color: #e0e0e0;
        overflow: hidden;
        height: 100vh;
      }

      #cesiumContainer {
        width: 100%;
        height: 100%;
        position: absolute;
      }
    </style>
  </head>

  <body>
    <!-- Cesium容器 -->
    <div id="cesiumContainer"></div>

    <script>
      // 设置Cesium访问令牌(实际使用中需要替换为自己的token)
      Cesium.Ion.defaultAccessToken =
        "accessToken";

      // 初始化地球视图
      const viewer = new Cesium.Viewer("cesiumContainer", {
        sceneMode: Cesium.SceneMode.SCENE3D,
        animation: false,
        timeline: false,
        fullscreenButton: false,
        homeButton: false,
        geocoder: false,
        baseLayerPicker: false,
        navigationHelpButton: false,
        infoBox: false,
        selectionIndicator: false,
        shadows: true,
        terrainShadows: Cesium.ShadowMode.RECEIVE_ONLY,
        orderIndependentTranslucency: false,
        contextOptions: {
          webgl: {
            preserveDrawingBuffer: true,
          },
        },
      });

      // ========== 1. 创建一个固定的3D点位(实体) ==========
      const position = Cesium.Cartesian3.fromDegrees(116.39748, 39.90882, 100); // 北京坐标

      viewer.entities.add({
        position: position,
        point: {
          color: Cesium.Color.RED,
          pixelSize: 10,
          outlineColor: Cesium.Color.WHITE,
          outlineWidth: 2,
        },
        label: {
          text: "固定点位",
          font: "16px sans-serif",
          fillColor: Cesium.Color.WHITE,
          pixelOffset: new Cesium.Cartesian2(0, -20),
        },
      });

      // ========== 2. 创建自定义 HTML 弹窗 ==========
      const infoDiv = document.createElement("div");
      infoDiv.style.position = "absolute";
      infoDiv.style.background = "rgba(0,0,0,0.7)";
      infoDiv.style.color = "white";
      infoDiv.style.padding = "6px 10px";
      infoDiv.style.borderRadius = "4px";
      infoDiv.style.pointerEvents = "none"; // 不影响鼠标操作地球
      infoDiv.style.fontSize = "14px";
      infoDiv.innerHTML = "我会牢牢跟着3D点位 ✅";

      // 添加到地球容器
      viewer.cesiumWidget.container.appendChild(infoDiv);

      // ========== 3. 每帧渲染 → 弹窗实时跟随 ==========
      function updatePopup() {
        // 把3D坐标 转为 屏幕2D坐标
        const canvasPosition =
          viewer.scene.cartesianToCanvasCoordinates(position);

        if (canvasPosition) {
          // 设置弹窗位置
          infoDiv.style.left = canvasPosition.x + "px";
          infoDiv.style.top = canvasPosition.y + "px";
        }
      }

      // 绑定到每帧渲染后执行
      viewer.scene.postRender.addEventListener(updatePopup);
    </script>
  </body>
</html>

效果:无论地球怎么旋转、缩放,弹窗永远牢牢贴在 3D 点位上。

4. 为什么要用它?

普通代码:只执行一次

postRender:每帧都执行(60 次 / 秒)

所以:

静态内容 → 不用

动态、跟随、实时变化 → 必须用 postRender

5. 重要注意事项

不要写太复杂的逻辑每秒执行 60 次,代码太卡会掉帧、卡顿。

不用时记得移除监听(避免内存泄漏)

复制代码
// 移除监听
viewer.scene.postRender.removeEventListener(你的函数);

和 requestAnimationFrame 作用一样,但更适配 Cesium。

相关推荐
青山Coding1 天前
Cesium应用(四):全球台风气象可视化实现
前端·vue.js·cesium
李剑一1 天前
Cesium 实现园区水景!3 种水面效果,Water 材质 5 分钟搞定
前端·vue.js·cesium
koiy.cc1 天前
Cesium:基于cesium-plot-js的标绘
cesium
用户43761190302152 天前
让 AI 用自然语言操控三维地球 -- Cesium MCP 开源实践
gis·cesium
李剑一2 天前
数字孪生大屏必看:Cesium 3D 模型选中交互,3 种高亮效果拿来就用!
前端·vue.js·cesium
李剑一3 天前
解决 Cesium 网络卡顿!5 分钟加载天地图,内网也能流畅用,附完整代码
前端·vue.js·cesium
GISBox3 天前
GISBox 2.1.7 版本更新:新增批量矢量导入功能,多项问题修复
gis·cesium·属性表·矢量·gisbox·场景编辑·切片转换
李剑一6 天前
超实用!数字孪生 Cesium 园区 3D 模型加载,一次学会的保姆级教程
前端·vue.js·cesium
李剑一13 天前
拿来就用!Vue3+Cesium 飞入效果封装,3D大屏多场景直接复用
前端·vue.js·cesium