尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Cesium 键盘漫游教程
键盘漫游 ·Keyboard Roam· ▶ 在线运行案例案例合集三维可视化功能案例threehub.cn开源仓库github地址https://github.com/z2586300277/three-cesium-examples400个案例代码:网盘链接你将学到什么flags 状态表跟踪按键按下clock.onTick每帧根据 flags 移动相机禁用screenSpaceCameraController避免与鼠标冲突移动速率随相机高度自适应效果说明GUI「启动键盘漫游」后WASDQE 调姿态IJKLUO 平移1234 观察方向方向键驱动地球自转「停止」恢复鼠标控制。核心概念按键 → flag 映射document.addEventListener(keydown, (e) {const flagName getFlagFromKeyboard(e); // moveForward, pitchUp ... if (flagName) flags[flagName] true; }); document.addEventListener(keyup, (e) { if (flagName) flags[flagName] false; });onTick 更新viewer.clock.onTick.addEventListener(() {const moveRate (cameraHeight / 150.0) * setStep; if (flags.moveForward) camera.moveForward(moveRate); if (flags.headingLeft) camera.setView({ orientation: { heading: heading - 0.005 } }); // ... });禁用默认交互viewer.scene.screenSpaceCameraController.enableTranslate false;viewer.scene.screenSpaceCameraController.enableTilt false;退出漫游时记得removeEventListener并 re-enable。实现步骤定义flags对象与keyboardRoamObjGUIstartKeyboardRoam(step)注册 keydown/keyup/onTickgetFlagFromKeyboard映射键码quitKeyboardRoam清理监听、恢复 controller按键一览| 键 | 作用 | |----|------| | WASDQE | 俯仰 / 偏航 / 翻滚 | | IJKLUO | 前后左右上下平移 | | 1234 | 观察方向微调 | | 方向键 | 地球自转 |代码要点import * as Cesium from cesium;import { GUI } from dat.gui;// 获取用于渲染Cesium场景的容器元素 const box document.getElementById(box)// 初始化区域 /**初始化Cesium Viewertype {Cesium.Viewer}*/ const viewer new Cesium.Viewer(box, { animation: false, // 是否创建动画小器件左下角仪表 baseLayerPicker: false, // 是否显示图层选择器右上角图层选择按钮 baseLayer: Cesium.ImageryLayer.fromProviderAsync(Cesium.ArcGisMapServerImageryProvider.fromUrl(https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer)), fullscreenButton: false, // 是否显示全屏按钮右下角全屏选择按钮 timeline: false, // 是否显示时间轴 infoBox: false, // 是否显示信息框 });// 隐藏Cesium Logo viewer._cesiumWidget._creditContainer.style.display none;/**创建GUI控制面板type {dat.GUI}*/ const gui new GUI(); // 添加瓦片坐标信息 viewer.imageryLayers.addImageryProvider(new Cesium.TileCoordinatesImageryProvider());// 状态管理区域 // 定义事件组 - 用于跟踪键盘按键状态 let flags { // 相机姿态控制相关标志 pitchUp: false, // 俯仰角向上 pitchDown: false, // 俯仰角向下 rollLeft: false, // 翻滚角向左 rollRight: false, // 翻滚角向右 headingLeft: false, // 偏航角向左 headingRight: false, // 偏航角向右// 相机位置移动相关标志 moveForward: false, // 相机自身向前平移 moveBackward: false, // 相机自身向后平移 moveLeft: false, // 相机自身向左平移 moveRight: false, // 相机自身向右平移 moveUp: false, // 相机自身向上平移 moveDown: false, // 相机自身向下平移 key1: false, // 相机视角向上旋转 key2: false, // 相机视角向下旋转 key3: false, // 相机视角向左旋转 key4: false, // 相机视角向右旋转 // 新增的控制标志 arrowUp: false, // 地球沿经度向北自转 arrowDown: false, // 地球沿经度向南自转 arrowLeft: false, // 地球沿纬度向东自转 arrowRight: false, // 地球沿纬度向西自转 };// 相机相关变量 let cameraHeight; // 相机高度 let heading; // 相机偏航角 let pitch; // 相机俯仰角 let roll; // 相机翻滚角// 事件处理器引用 - 用于后续移除事件监听器 let tickHandler; // 帧更新事件处理器 let keyDownHandler; // 键盘按下事件处理器 let keyUpHandler; // 键盘释放事件处理器// 启用地形深度测试确保正确渲染 viewer.scene.globe.depthTestAgainstTerrain true;// GUI控制区域 /**定义键盘漫游操作对象namespace keyboardRoamObj*/ const keyboardRoamObj { 启动键盘漫游: () { if (viewer) { startKeyboardRoam(1); } }, 停止键盘漫游: () { quitKeyboardRoam(); }, 重置视角: () { // 重置相机到默认视角 viewer.camera.flyHome(1); }, 使用说明: () { const instructions 键盘控制说明: 相机姿态控制 (WASDQE): W : 向上俯仰视角 S : 向下俯仰视角 A : 向左偏航视角 D : 向右偏航视角 Q : 向左翻滚视角 E : 向右翻滚视角 相机位置移动 (IJKLUO): I : 向前移动相机 K : 向后移动相机 J : 向左移动相机 L : 向右移动相机 U : 向上移动相机 O : 向下移动相机 观察方向控制 (数字键1234): 1 : 向上观察 2 : 向下观察 3 : 向左观察 4 : 向右观察 地球自转控制 (方向键): ↑ : 地球向北自转 ↓ : 地球向南自转 ← : 地球向西自转 → : 地球向东自转; alert(instructions); } };// 将操作对象添加到GUI控制面板 for (const key in keyboardRoamObj) gui.add(keyboardRoamObj, key)// 功能操作区域 /**键盘漫游加载方法param {Number} setStep - 相机视角移动步长*/ function startKeyboardRoam(setStep) { // 如果已经存在漫游功能先停止它 if (tickHandler) { quitKeyboardRoam(); }// 添加键盘按下事件监听器 document.addEventListener( keydown, keyDownHandler function (e) { let flagName getFlagFromKeyboard(e); if (typeof flagName ! undefined) { flags[flagName] true; } }, false );// 禁用鼠标控制相机平移和倾斜避免与键盘控制冲突 viewer.scene.screenSpaceCameraController.enableTranslate false; // 禁用平移 viewer.scene.screenSpaceCameraController.enableTilt false; // 禁用倾斜// 添加键盘释放事件监听器 document.addEventListener( keyup, keyUpHandler function (e) { let flagName getFlagFromKeyboard(e); if (typeof flagName ! undefined) { flags[flagName] false; } }, false );// 添加每帧更新事件监听器 tickHandler viewer.clock.onTick.addEventListener(() { let camera viewer.camera; let ellipsoid viewer.scene.globe.ellipsoid; // 获取当前相机高度 cameraHeight ellipsoid.cartesianToCartographic(camera.position).height; // 根据相机高度动态调整移动速率高度越高移动越快 let moveRate (cameraHeight / 150.0) * setStep; // 获取当前相机姿态偏航角、俯仰角、翻滚角 heading camera.heading; pitch camera.pitch; roll camera.roll; if (flags.headingLeft) { hprSetting(-0.005 * setStep, 0, 0); } if (flags.headingRight) { hprSetting(0.005 * setStep, 0, 0); } if (flags.pitchUp) { hprSetting(0, 0.01 * setStep, 0); } if (flags.pitchDown) { hprSetting(0, -0.01 * setStep, 0); } if (flags.rollLeft) { hprSetting(0, 0, 0.01 * setStep); } if (flags.rollRight) { hprSetting(0, 0, -0.01 * setStep); } // zoomIn与moveForward效果相同 if (flags.moveForward) { camera.zoomIn(moveRate); // camera.moveForward(moveRate); } // zoomOut与moveBackward效果相同 if (flags.moveBackward) { camera.zoomOut(moveRate); // camera.moveBackward(moveRate); } if (flags.moveUp) { camera.moveUp(moveRate); } if (flags.moveDown) { camera.moveDown(moveRate); } if (flags.moveLeft) { camera.moveLeft(moveRate); } if (flags.moveRight) { camera.moveRight(moveRate); } if (flags.key1) { camera.lookUp(Cesium.Math.toRadians(setStep)) } if (flags.key2) { camera.lookDown(Cesium.Math.toRadians(setStep)) } if (flags.key3) { camera.lookLeft(Cesium.Math.toRadians(setStep)) } if (flags.key4) { camera.lookRight(Cesium.Math.toRadians(setStep)) } if (flags.arrowUp) { camera.rotateDown(Cesium.Math.toRadians(setStep)) } if (flags.arrowDown) { camera.rotateUp(Cesium.Math.toRadians(setStep)) } if (flags.arrowLeft) { camera.rotateLeft(Cesium.Math.toRadians(setStep)) } if (flags.arrowRight) { camera.rotateRight(Cesium.Math.toRadians(setStep)) } }); }/**相机姿态设置方法param {number} h - 偏航角调整量param {number} p - 俯仰角调整量param {number} r - 翻滚角调整量*/ function hprSetting(h, p, r) { viewer.camera.setView({ orientation: { heading: heading h, // 偏航角 pitch: pitch p, // 俯仰角 roll: roll r, // 翻滚角 }, }); }/**监听键盘按下和松开的状态param {KeyboardEvent} k - 键盘事件returns {string|undefined} 对应的标志名称*/ function getFlagFromKeyboard(k) { switch (k.key) { // 按字符的Unicode编码 // 相机姿态操控WASDQE控制相机视角 case w: return pitchUp; // W键 - 向上俯仰 case s: return pitchDown; // S键 - 向下俯仰 case a: return headingLeft; // A键 - 向左偏航 case d: return headingRight; // D键 - 向右偏航 case q: return rollLeft; // Q键 - 向左翻滚 case e: return rollRight; // E键 - 向右翻滚 // 相机位置操控IJKLUO控制相机移动 case i: return moveForward; // I键 - 向前移动 case k: return moveBackward; // K键 - 向后移动 case j: return moveLeft; // J键 - 向左移动 case l: return moveRight; // L键 - 向右移动 case u: return moveUp; // U键 - 向上移动 case o: return moveDown; // O键 - 向下移动 case 1: return key1; // 数字键1 case 2: return key2; // 数字键2 case 3: return key3; // 数字键3 case 4: return key4; // 数字键4 case ArrowUp: return arrowUp; // 方向键上 case ArrowDown: return arrowDown; // 方向键下 case ArrowLeft: return arrowRight; // 方向键左 case ArrowRight: return arrowLeft; // 方向键右 // 未匹配的按键 default: return undefined; } }/**销毁键盘漫游事件 - 清理所有事件监听器并重置状态*/ function quitKeyboardRoam() { // 移除键盘按下事件监听器 if (keyDownHandler) { document.removeEventListener(keydown, keyDownHandler, false); keyDownHandler null; }// 移除键盘释放事件监听器 if (keyUpHandler) { document.removeEventListener(keyup, keyUpHandler, false); keyUpHandler null; }// 移除帧更新事件监听器 if (tickHandler) { viewer.clock.onTick.removeEventListener(tickHandler); tickHandler null; }// 解除禁用鼠标移动地图事件恢复默认控制 if (viewer) { viewer.scene.screenSpaceCameraController.enableTranslate true; // 恢复平移 viewer.scene.screenSpaceCameraController.enableTilt true; // 恢复倾斜 }// 重置所有标志为false状态 for (let flag in flags) { flags[flag] false; } }完整源码GitHub小结本文提供键盘漫游完整 Cesium.js 源码与在线 Demo建议先运行案例再改 uniform/参数做二次实验更多 Cesium.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库
RELATED

相关推荐

2026抖音右下角水印去除方法:手机电脑合规工具与侵权说明

2026抖音右下角水印去除方法:手机电脑合规工具与侵权说明

日常保存抖音视频时,右下角的平台水印会影响视频观感与素材整理,很多个人用户都想通过简单稳妥的方式去除水印。2026年主流的抖音去水印方式分为官方原生设置、手机端工具处理、电脑端专业处理三类,适配不同使用场景。本文将全面讲解抖音右下…

📅 2026/11/13 2:50:59
结构化方法 3 大核心工具实战:数据流图、ER图、数据字典在考务系统中的应用

结构化方法 3 大核心工具实战:数据流图、ER图、数据字典在考务系统中的应用

结构化方法三大核心工具实战:数据流图、ER图与数据字典在考务系统中的深度应用 1. 结构化方法工具链的价值重构 在当代软件工程实践中,结构化方法依然保持着强大的生命力。不同于面向对象方法的抽象封装特性,结构化方法通过 分解与细化 的…

📅 2026/11/13 8:52:38
MAX9744与STM32L021K4实现高效嵌入式音频系统设计

MAX9744与STM32L021K4实现高效嵌入式音频系统设计

1. 项目背景与核心器件选型在嵌入式音频系统开发中,我们常常面临一个经典难题:如何在紧凑的空间和有限的电源预算下,实现高质量的音频功率放大?这个问题的解决方案直接关系到各类便携式音频设备、智能家居终端和物联网产品的用户体…

📅 2026/11/8 2:22:03
MORE NEWS

更多资讯

📰

维修电工证考些啥千万别踩坑,这些细节必须知道

维修电工证考些啥千万别踩坑,这些细节必须知道 怕考不过白交培训费?维修电工证考些啥,很多人都不清楚,结果一报班就花了冤枉钱。别急,这篇文章讲透考试内容、报名门槛、复习方法,帮你避开那些培训机构设的坑,省下一笔培训费,还能稳稳拿到证。…

📰

工地太忙根本没时间复习考试?戚跃先电工证考前押题帮你省时省力

工地太忙根本没时间复习考试?戚跃先电工证考前押题帮你省时省力 工地太忙根本没时间复习考试,这几乎是每个工地电工都经历过的事。你手上拿着低压电工证,却因为没时间备考,错过了考试或者成绩不理想,这样的情况在焦作房建工程行业并不少见。尤其是像戚跃…

📰

漯河电工证拿证时间多久?通过率揭秘助你避坑

漯河电工证拿证时间多久?通过率揭秘助你避坑 证书过期了不知道怎么复审延期?你不是一个人!最近有不少漯河的电工朋友反馈,手上持有的电工证已经到期,却对如何复审、如何重新办理一脸懵圈。别急,本文就来聊聊【漯河电工证拿证时间】,并通过【通过率揭秘…

📰

电工外网高压电工证怎么转?外省证在河南也能用

电工外网高压电工证怎么转?外省证在河南也能用 之前考的证在外省能不能转过来?这个是很多转岗的河南电工最关心的问题。尤其是拿着 外省高压电工证 想在河南本地就业的同行,总担心证件的 含金量…

📰

长春哪里考电工证真实经历告诉你怎么转异地

长春哪里考电工证真实经历告诉你怎么转异地 证书过期了不知道怎么复审延期,这事儿我真遇到过,别看你是电工,证书要是过期了,直接等于“无证上岗”,不仅影响工作,还可能被追责。今天我来给你讲讲我自己的 真实经历 ,以及 长春哪里考电工证…

📰

证书过期了不知道怎么复审延期?建筑特种工申报年龄和官方报名入口全解析

证书过期了不知道怎么复审延期?建筑特种工申报年龄和官方报名入口全解析 证书过期了不知道怎么复审延期,这种情况其实挺常见的。尤其是建筑特种工这类需要持证上岗的工种,一旦错过复审时间,轻则影响工作,重则面临被清退的风险。如果你正面临这样的情况,…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬