河北省网站建设_网站建设公司_API接口_seo优化
2026/1/17 12:05:25 网站建设 项目流程

View Post

第五篇:给地球加点“魔法”——帧率、截图、底图控制,统统安排!

📘 专栏说明

本专栏旨在手把手带你从零开始,基于开源三维地球引擎 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.enableLighting
  • shadows

我们把它合并成一个开关:

/*** 地球光源阴影* @type {Boolean}*/
set lightShadow(bool: boolean) {this.scene.globe.enableLighting = boolthis.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.canvasreturn { 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-ignoreconst layers = this.imageryLayers._layersconst baseLayer = layers.find((layer: any) => layer._isBaseLayer)return baseLayer
}
set baseImagery(imagery: Cesium.ImageryLayer) {//@ts-ignoreconst 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.sizeparams.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.imageconst img = document.createElement("img")img.id = "screenshot"img.src = base64img.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 年伊始,与你共添一行魔法代码。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询