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);如何删除?
方法 1:直接从父容器移除(最简单)
// 直接删除你创建的 infoDiv infoDiv.remove();这行代码就能把弹窗从页面上彻底删掉。
方法 2:安全判断式删除(推荐)
防止元素已经被删了导致报错:
if (infoDiv && infoDiv.parentNode) { infoDiv.parentNode.removeChild(infoDiv); }如果要多次开关弹窗
建议把弹窗存成全局变量,方便开关:
// 全局保存 window.infoDiv = infoDiv; // 删除 window.infoDiv?.remove();二、viewer..entities.values作用
viewer.entities.values 是一个数组,里面包含了你在 Cesium 中添加的所有实体(点、线、面、标注、模型等),可以用来遍历、查询、修改、删除全部实体。
核心作用(最常用)
1、遍历所有实体(最常用)
批量修改、隐藏、删除所有实体:
// 遍历场景中所有实体 viewer.entities.values.forEach(entity => { // 示例1:隐藏所有实体 entity.show = false; // 示例2:修改所有点的颜色 if (entity.point) { entity.point.color = Cesium.Color.RED; } });2、获取实体总数
const count = viewer.entities.values.length; console.log('场景中共有实体:', count);3、清空所有实体(替代 removeAll())
// 清空所有实体 viewer.entities.removeAll(); // 等价于遍历删除(不推荐,仅理解用) viewer.entities.values.forEach(entity => { viewer.entities.remove(entity); });4、查找符合条件的实体
// 查找所有名称为 "测试点" 的实体 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.cartesianToCanvasCoordinates()
这是 Cesium 中核心坐标转换 API,专门用来把3D 世界坐标(Cartesian3) 转换成浏览器 2D 屏幕坐标(Canvas 坐标),是实现自定义 DOM 弹窗、标签、跟随鼠标元素的关键方法。
一句话总结:
将 Cesium 三维场景中的点,转换成浏览器画布上的像素坐标(x, y)让你知道:3D 世界里的某个点,在屏幕上显示在哪个位置。
// 1. 定义一个3D世界坐标(比如北京) const position = Cesium.Cartesian3.fromDegrees(116.4, 39.9, 100); // 2. 创建你的自定义DOM弹窗 const infoDiv = document.createElement('div'); infoDiv.style.position = 'absolute'; infoDiv.style.background = 'white'; infoDiv.innerHTML = '我是绑定在3D点上的弹窗'; viewer.cesiumWidget.container.appendChild(infoDiv); // 3. 实时更新弹窗屏幕位置(关键!) viewer.scene.postRender.addEventListener(() => { // 核心:3D坐标 → 屏幕坐标 const canvasPosition = viewer.scene.cartesianToCanvasCoordinates(position); if (Cesium.defined(canvasPosition)) { // 把屏幕坐标赋值给DOM infoDiv.style.left = canvasPosition.x + 'px'; infoDiv.style.top = canvasPosition.y + 'px'; } });输入:
Cartesian3 坐标:Cesium 3D 场景中的点(经纬度转的世界坐标、实体位置、模型位置等)
输出:
Cartesian2 坐标:包含 x、y 属性,单位是像素
x:距离浏览器画布左侧的像素距离
y:距离浏览器画布顶部的像素距离
关键特性 & 注意事项:
必须在渲染循环中调用地球转动、缩放时,屏幕坐标会实时变化,所以要放在 postRender 事件里更新。
坐标原点转换后的 x/y 是相对于 Cesium Canvas 画布,不是整个浏览器窗口。
五、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 content="width=device-width, initial-scale=1.0" /> <title>实体实时流畅移动</title> <!-- 引入Cesium库 --> <link /> <script></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></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: fal