第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > Cesium 键盘鼠标控制相机漫游(源码+原理讲解)

Cesium 键盘鼠标控制相机漫游(源码+原理讲解)

时间:2018-08-07 14:47:48

相关推荐

Cesium 键盘鼠标控制相机漫游(源码+原理讲解)

Cesium 键盘鼠标控制相机漫游(源码+原理讲解)

在各大博客平台上,Cesium使用键盘控制相机漫游的源码已经有不少人贴出源码,本人在浏览这些源码的过程中发现大家采用的方式基本一致,大部分代码都是一个模子,甚至有一部分博文对代码进行部分删除,导致出现看不懂的情况。这些博文有个共同的问题就是无任何说明,对新手很不友好。

本文使用同样的思路完成键盘鼠标同时控制相机漫游功能,并附带必要说明,建议收藏。

1 达到的效果

键盘控制:w,相机前进; s,相机后退;a,相机左移;d,相机右移;q,相机上移;e,相机下移。鼠标控制:按住鼠标左键向某个方向移动鼠标使相机镜头转向该方向。

2 实现思路

开启键盘鼠标控制相机漫游:

将默认的相机操作模式禁用,防止鼠标动作冲突;设置相机漫游的标记;添加鼠标监听事件,监听按住鼠标移动情况来改变漫游标记;添加键盘监听事件,监听键盘来改变漫游标记;添加渲染事件,根据漫游标记的改变来渲染。

关闭键盘鼠标控制相机漫游:

移除鼠标监听事件;移除键盘监听事件;移除渲染事件;将默认的相机操作模式启用。

3 源码及说明

3.1 HTML代码

<div id="cesiumContainer" style="width:100%;height:100%"></div>

3.2 JavaScript代码

// 初始化地球小部件let viewer = new Cesium.Viewer('cesiumContainer');// 声明变量,以下代码可能会多次用到let scene = viewer.scene;let canvas = viewer.canvas; // 此处用viewer.canvas或viewer.scene.canvas都可以,是同一个canvas对象let camera = viewer.camera;let ellipsoid = viewer.scene.globe.ellipsoid;// 声明相机漫游标记let flags = null;// 声明handlerlet handler = null;/*** 进入键盘鼠标漫游模式*/function enterKeyBoardMouseRoamingMode() {console.log('进入漫游模式');// 1.禁用默认相机操作模式scene.screenSpaceCameraController.enableRotate = false;scene.screenSpaceCameraController.enableTranslate = false;scene.screenSpaceCameraController.enableZoom = false;scene.screenSpaceCameraController.enableTilt = false;scene.screenSpaceCameraController.enableLook = false;// 2.初始化相机漫游的标记flags = {looking: false, // 是否正在用鼠标调整视角startPosition: null, // 鼠标指针开始移动位置endPosition: null, // 鼠标指针停止移动位置moveForward: false, // 是否向前移动moveBackward: false, // 是否向后移动moveLeft: false, // 是否向左移动moveRight: false, // 是否向右移动moveUp: false, // 是否向上移动moveDown: false, // 是否向下移动}; // 相机漫游标记// 3.添加鼠标监听事件handler = new Cesium.ScreenSpaceEventHandler(canvas);// 左键按下handler.setInputAction((movement) => {flags.looking = true;flags.startPosition = Cesium.Cartesian3.clone(movement.position);flags.endPosition = Cesium.Cartesian3.clone(movement.position);}, Cesium.ScreenSpaceEventType.LEFT_DOWN);// 鼠标移动handler.setInputAction((movement) => {flags.endPosition = movement.endPosition;}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 左键弹起handler.setInputAction(() => {flags.looking = false;}, Cesium.ScreenSpaceEventType.LEFT_UP);// 4.添加键盘监听事件// 键盘按下事件document.addEventListener('keydown', keyDown, false);// 键盘弹起事件document.addEventListener('keyup', keyUp, false);// 5.添加渲染事件viewer.clock.onTick.addEventListener(renderEvent);}// DOM添加一个开启键盘鼠标漫游模式的按钮,使用绝对定位放在屏幕左上角,用于测试let enterButton = document.createElement('button');enterButton.innerText = '开启';enterButton.style.position = 'absolute';enterButton.style.left = '20px';enterButton.style.top = '20px';enterButton.onclick = enterKeyBoardMouseRoamingMode;document.body.appendChild(enterButton);/*** 退出键盘鼠标漫游模式*/function exitKeyBoardMouseRoamingMode() {console.log('退出漫游');// 1.移除鼠标监听事件if (handler) {handler.destroy();handler = null;}// 2.移除键盘监听事件document.removeEventListener('keydown', keyDown, false);document.removeEventListener('keyup', keyUp, false);// 3.移除渲染事件viewer.clock.onTick.removeEventListener(renderEvent);// 4.启用默认相机操作模式scene.screenSpaceCameraController.enableRotate = true;scene.screenSpaceCameraController.enableTranslate = true;scene.screenSpaceCameraController.enableZoom = true;scene.screenSpaceCameraController.enableTilt = true;scene.screenSpaceCameraController.enableLook = true;}// DOM添加一个关闭键盘鼠标漫游模式的按钮,使用绝对定位放在屏幕左上角,用于测试let exitButton = document.createElement('button');exitButton.innerText = '关闭';exitButton.style.position = 'absolute';exitButton.style.left = '70px';exitButton.style.top = '20px';exitButton.onclick = exitKeyBoardMouseRoamingMode;document.body.appendChild(exitButton);/*** 键盘按下*/function keyDown(event) {let flagName = getFlagFromKeyCode(event.keyCode);if (typeof flagName !== 'undefined') {flags[flagName] = true;}}/*** 键盘弹起*/function keyUp(event) {let flagName = getFlagFromKeyCode(event.keyCode);if (typeof flagName !== 'undefined') {flags[flagName] = false;}}/*** 渲染函数*/function renderEvent() {// 镜头转向if (flags.looking) {let width = viewer.canvas.clientWidth;let height = viewer.canvas.clientHeight;let lookFactor = 0.05; // 镜头转向系数,系数越大约灵敏,此处取0.05比较适中let x = (flags.endPosition.x - flags.startPosition.x) / width;let y = -(flags.endPosition.y - flags.startPosition.y) / height;// 计算出x,y之后,有两种方式实现镜头,经过测试感觉方式 1更流畅// 方式 1camera.lookRight(x * lookFactor);camera.lookUp(y * lookFactor);// 方式 2// camera.setView({// orientation: {//heading: camera.heading + x * lookFactor,//pitch: camera.pitch + y * lookFactor,//roll: 0.0,// },// });}// 根据高度来决定镜头移动的速度let cameraHeight = ellipsoid.cartesianToCartographic(camera.position).height;let moveRate = cameraHeight / 100.0;if (flags.moveForward) {camera.moveForward(moveRate);}if (flags.moveBackward) {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);}}/*** 从键盘码获取flag标记*/function getFlagFromKeyCode(keyCode) {switch (keyCode) {case 'W'.charCodeAt(0):return 'moveForward';case 'S'.charCodeAt(0):return 'moveBackward';case 'Q'.charCodeAt(0):return 'moveUp';case 'E'.charCodeAt(0):return 'moveDown';case 'D'.charCodeAt(0):return 'moveRight';case 'A'.charCodeAt(0):return 'moveLeft';default:return undefined;}}

4 无需鼠标控制的情况

如果我们项目中只需要键盘控制则可以对代码精简如下:

4.1 HTML代码

<div id="cesiumContainer" style="width:100%;height:100%"></div>

4.2 JavaScript代码

// 初始化地球小部件let viewer = new Cesium.Viewer('cesiumContainer');// 声明变量,以下代码可能会多次用到let camera = viewer.camera;let ellipsoid = viewer.scene.globe.ellipsoid;// 声明相机漫游标记let flags = null;/*** 进入键盘漫游模式*/function enterKeyBoardMouseRoamingMode() {console.log('进入漫游模式');// 1.初始化相机漫游的标记flags = {moveForward: false, // 是否向前移动moveBackward: false, // 是否向后移动moveLeft: false, // 是否向左移动moveRight: false, // 是否向右移动moveUp: false, // 是否向上移动moveDown: false, // 是否向下移动}; // 相机漫游标记// 2.添加键盘监听事件// 键盘按下事件document.addEventListener('keydown', keyDown, false);// 键盘弹起事件document.addEventListener('keyup', keyUp, false);// 3.添加渲染事件viewer.clock.onTick.addEventListener(renderEvent);}// DOM添加一个开启键盘鼠标漫游模式的按钮,使用绝对定位放在屏幕左上角,用于测试let enterButton = document.createElement('button');enterButton.innerText = '开启';enterButton.style.position = 'absolute';enterButton.style.left = '20px';enterButton.style.top = '20px';enterButton.onclick = enterKeyBoardMouseRoamingMode;document.body.appendChild(enterButton);/*** 退出键盘漫游模式*/function exitKeyBoardMouseRoamingMode() {console.log('退出漫游');// 1.移除键盘监听事件document.removeEventListener('keydown', keyDown, false);document.removeEventListener('keyup', keyUp, false);// 2.移除渲染事件viewer.clock.onTick.removeEventListener(renderEvent);}// DOM添加一个关闭键盘鼠标漫游模式的按钮,使用绝对定位放在屏幕左上角,用于测试let exitButton = document.createElement('button');exitButton.innerText = '关闭';exitButton.style.position = 'absolute';exitButton.style.left = '70px';exitButton.style.top = '20px';exitButton.onclick = exitKeyBoardMouseRoamingMode;document.body.appendChild(exitButton);/*** 键盘按下*/function keyDown(event) {let flagName = getFlagFromKeyCode(event.keyCode);if (typeof flagName !== 'undefined') {flags[flagName] = true;}}/*** 键盘弹起*/function keyUp(event) {let flagName = getFlagFromKeyCode(event.keyCode);if (typeof flagName !== 'undefined') {flags[flagName] = false;}}/*** 渲染函数*/function renderEvent() {// 根据高度来决定镜头移动的速度let cameraHeight = ellipsoid.cartesianToCartographic(camera.position).height;let moveRate = cameraHeight / 100.0;if (flags.moveForward) {camera.moveForward(moveRate);}if (flags.moveBackward) {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);}}/*** 从键盘码获取flag标记*/function getFlagFromKeyCode(keyCode) {switch (keyCode) {case 'W'.charCodeAt(0):return 'moveForward';case 'S'.charCodeAt(0):return 'moveBackward';case 'Q'.charCodeAt(0):return 'moveUp';case 'E'.charCodeAt(0):return 'moveDown';case 'D'.charCodeAt(0):return 'moveRight';case 'A'.charCodeAt(0):return 'moveLeft';default:return undefined;}}

5 延伸阅读

如果对这篇博文理解困难,请浏览以下博文,帮助您理解Cesium中的事件。

Cesium 事件详解

Cesium 核心类Viewer-查看器详解

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。