第五篇:给地球加点“魔法”——帧率、截图、底图控制,统统安排!
📘 专栏说明
本专栏旨在手把手带你从零开始,基于开源三维地球引擎 Cesium 封装一套功能完善、可复用的 WebGIS 增强型 SDK。内容涵盖核心封装思路、关键代码实现、常用 GIS 功能抽象,以及基于该 SDK 构建的 UI 组件库开发。如果你更关注结果而非实现过程,也可直接使用已发布的成果:
🌟 GitHub仓库 📦 NPM 包 ✨ 公众号:经纬码客(欢迎关注)
💡 建议:即便你打算直接使用 SDK,也推荐订阅本专栏 -- 理解设计思路,才能更灵活地扩展属于你自己的专属 GIS 能力!
由于作者需兼顾全职工作,更新主要安排在晚间或节假日,无法保证高频发布,但会持续迭代,直至 SDK 达到实际项目落地标准。届时将完整开源所有源码,供学习与商用(遵循许可证协议)。
大家好,我是 Cesium 酱(也可以叫我“本猿”),一名在 WebGIS 领域摸爬滚打多年的前端开发者。上一篇,我们一起封装了 Arc3DLab.Viewer,实现了“一行代码创建三维地球”。
但一个真正好用的 SDK,不能只停留在“能跑”,还要让开发者用得爽。
这一期,我们就来给 Viewer 类加几个超实用的小功能:
- ✅ 动态开关帧率显示(FPS)
- ✅ 一键开启/关闭地球光照与阴影
- ✅ 获取当前地图尺寸(width / height)
- ✅ 导出当前地图场景为 Base64 图片
- ✅ 灵活替换底图(ImageryLayer)
这些功能看似简单,但原生 Cesium 要么藏得深,要么写法啰嗦。
我们造轮子的目标:把复杂留给自己,把简洁留给用户。
准备好了吗?打开你的 Viewer.ts,我们继续敲代码!
🔧 第一步:添加帧率控制 —— fps 属性
很多Cesium开发者调试时需要看帧率,肯定每次都要写:
viewer.scene.debugShowFramesPerSecond = true
太麻烦!
我们在 Viewer 类中添加 getter/setter:
// src/core/Viewer.ts
/**
* 控制帧率显示
* @type {Boolean}
*/
get fps() {
return this.scene.debugShowFramesPerSecond
}
set fps(show: boolean) {
this.scene.debugShowFramesPerSecond = show
}
✅ 使用方式:
viewer.fps = true // 开启帧率
console.log(viewer.fps) // 读取当前状态
是不是清爽多了?
💡 第二步:一键控制地球光影 —— lightShadow 属性
想让地球有明暗变化?需要同时开启两个设置:
globe.enableLightingshadows
我们把它合并成一个开关:
/**
* 地球光源阴影
* @type {Boolean}
*/
set lightShadow(bool: boolean) {
this.scene.globe.enableLighting = bool
this.shadows = bool
}
✅ 使用方式:
viewer.lightShadow = true // 开启真实光照 + 阴影
viewer.lightShadow = false // 关闭,性能更优
🌍 小知识:开启光照后,地形起伏会更真实,但对 GPU 要求更高。本猿一般是关闭的...没办法,小破本...
📏 第三步:获取地图尺寸 —— size 只读属性
有时候我们需要知道当前画布大小(比如做截图适配),原生要写:
const { width, height } = viewer.canvas
我们封装成一个只读属性,并提取为独立函数(便于复用):
先创建工具函数 src/utils/Scene.ts(后续场景相关的方法都将在此文件扩充):
// src/utils/Scene.ts
import { Viewer } from "../core/Viewer"
/**
* 获取地图尺寸
*/
export function mapSize(viewer: Viewer) {
const { width, height } = viewer.canvas
return { width, height }
}
然后在 Viewer.ts 中引用:
import { mapSize } from "../utils/Scene"
/**
* 地图画布大小,例如:{width:1920,height:1080}
* @type {Object}
* @readonly
*/
get size() {
return mapSize(this)
}
✅ 使用方式:
console.log(viewer.size) // { width: 1920, height: 1080 }
📸 第四步:一键导出场景图片 —— image 只读属性
想把当前地球画面保存为图片?原生 toDataURL() 有时会导出黑屏(因为未渲染完成)。
我们加个保险,同样是在 src/utils/Scene.ts:
// src/utils/Scene.ts
import { Viewer } from "../core/Viewer"
/**
* 获取地图图片(Base64)
*/
export function mapImg(viewer: Viewer) {
viewer.render() // 强制渲染一帧,避免黑屏
return viewer.scene.canvas.toDataURL("image/png")
}
在 Viewer.ts 中添加:
import { mapImg } from "../utils/mapImg"
/**
* 当前地图场景图片,base64格式
* @type {String}
* @readonly
*/
get image() {
return mapImg(this)
}
✅ 使用方式:
const base64 = viewer.image
const img = document.createElement('img')
img.src = base64
document.body.appendChild(img)
💡 提示:功能不大,但常用,用于生成报告、分享截图、自动化测试等场景。

🌐 第五步:灵活控制底图 —— baseImagery 属性
Cesium 的底图机制有点“隐晦”,没有明确的定义:
- 最底层的图层会被标记为
_isBaseLayer - 替换它需要先移除旧图层,再用
lowerToBottom()放到底部,反正挺烦人的设置
我们把它封装成一个属性:
/**
* 场景底图
* Cesium机制是最底层的图层为_isBaseLayer,通过lowerToBottom来控制
* @type {Cesium.ImageryLayer}
*/
get baseImagery() {
//@ts-ignore
const layers = this.imageryLayers._layers
const baseLayer = layers.find((layer: any) => layer._isBaseLayer)
return baseLayer
}
set baseImagery(imagery: Cesium.ImageryLayer) {
//@ts-ignore
const baseLayer = this.imageryLayers._layers.find(
(layer: any) => layer._isBaseLayer
)
if (baseLayer) {
this.imageryLayers.remove(baseLayer)
}
this.imageryLayers.lowerToBottom(imagery)
}
✅ 使用方式:
// 创建一个天地图影像图层
const tianditu = new Cesium.WebMapTileServiceImageryProvider({
url: "http://t0.tianditu.gov.cn/img_w/wmts?tk=你的密钥",
layer: "img",
style: "default",
format: "tiles",
tileMatrixSetID: "w",
maximumLevel: 18,
})
const imageryLayer = new Cesium.ImageryLayer(tianditu)
// 一键替换底图!
viewer.baseImagery = imageryLayer
⚠️ 注意:使用第三方地图服务请遵守其许可协议。
🧪 本地测试:试试这些新能力!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>004-场景设置</title>
<script src="./Cesium/Cesium.js"></script>
<link rel="stylesheet" href="./Cesium/Widgets/widgets.css" />
<script src="./lib/arc3dlab.umd.js"></script>
<script src="./assests/dat.gui.min.js"></script>
<style>
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#cesiumContainer {
width: 100%;
height: 100%;
position: relative;
}
#gui-box {
position: absolute;
left: 5px;
top: 5px;
z-index: 99;
display: flex;
}
</style>
</head>
<body>
<div id="cesiumContainer">
<div id="gui-box"></div>
</div>
<script>
const viewer = new Arc3DLab.Viewer("cesiumContainer")
initGui()
function initGui() {
const params = {
message: "GUI面板-场景设置",
fps: false,
mapSize: "width:--,height:--",
获取尺寸: function () {
const { width, height } = viewer.size
params.mapSize = `width:${width},height:${height}`
mapSizeController.updateDisplay()
},
场景截图: function () {
const guiBox = document.getElementById("gui-box")
const existingScreenshots = guiBox.querySelector("#screenshot")
if (existingScreenshots) existingScreenshots.remove()
const base64 = viewer.image
const img = document.createElement("img")
img.id = "screenshot"
img.src = base64
img.style.width = "300px"
img.style.border = "1px solid #ccc"
guiBox.appendChild(img)
},
}
const gui = new dat.GUI({ autoPlace: false })
const customContainer = document.getElementById("gui-box")
customContainer.appendChild(gui.domElement)
gui.add(params, "message")
const boolFps = gui.add(params, "fps")
boolFps.onFinishChange((val) => {
viewer.fps = val
})
const mapSizeController = gui.add(params, "mapSize")
gui.add(params, "获取尺寸")
gui.add(params, "场景截图")
}
</script>
</body>
</html>
刷新页面,你会看到:
- 右上角显示 FPS
- 地球出现明暗变化
- 点击显示尺寸,点击插入截图!
🌟 项目开源,欢迎Star✨!
GitHub:https://github.com/jianlei-wang/Arc3DLab_SDK
NPM:https://www.npmjs.com/package/arc3dlab
Cesium 酱の百宝箱 · 第 5 篇
功能不在多,而在刚刚好。
2026 年伊始,与你共添一行魔法代码。
本专栏旨在手把手带你从零开始,基于开源三维地球引擎 **Cesium** 封装一套功能完善、可复用的 **WebGIS 增强型 SDK**。内容涵盖核心封装思路、关键代码实现、常用 GIS 功能抽象,以及基于该 SDK 构建的 UI 组件库开发。
浙公网安备 33010602011771号