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。

相关推荐
阿琳a_3 天前
在github上部署个人的vitepress文档网站
前端·vue.js·github·网站搭建·cesium
云上飞476369624 天前
glb模型在Cesium中发黑的机理分析
cesium·glb模型发黑
ct9785 天前
Cesium的Primitive API
gis·webgl·cesium
Irene19916 天前
OpenLayers 和 Cesium 都是流行的开源 JavaScript 库,用于在网页上构建地图和地理空间应用
openlayers·cesium
fxshy6 天前
前端直连模型 vs 完整 MCP:大模型驱动地图的原理与实践(技术栈Vue + Cesium + Node.js + WebSocket + MCP)
前端·vue.js·node.js·cesium·mcp
棋鬼王7 天前
Cesium(十) 动态修改白模颜色、白模渐变色、白模光圈特效、白模动态扫描光效、白模着色器
前端·javascript·vue.js·智慧城市·数字孪生·cesium
duansamve7 天前
Cesium快速入门到精通系列教程二十四:限制相机在特定的Level之间展示地图
cesium
duansamve10 天前
Vue3的Vite项目中直接引入的方式使用Cesium
cesium
WebGISer_白茶乌龙桃11 天前
基于 Cesium 的 GLB 建筑模型分层分房间点击拾取技术实现
前端·javascript·vue.js·webgl·cesium
小彭努力中12 天前
195.Vue3 + OpenLayers:监听瓦片地图加载情况(200、403及异常处理)
前端·css·openlayers·cesium·webgis