本文为稀土掘金技术社区首发签约文章,14 天内禁止转载,14 天后未获授权禁止转载,侵权必究!
哈喽,大家好 我是
xy
👨🏻💻。这篇文章是Cesium 三维地球可视化从入门到进阶
专栏的第三篇,Cesium
中的事件
数量繁多、类型各异,按照类型
进行分类,可以分为如下几种:鼠标键盘事件
、相机事件
、数据加载事件
、场景加载事件
。
Cesium 中的事件数量繁多、类型各异,本章内容仅介绍一些常用的事件及其使用方法。
Cesium 事件简介
Cesium
中的事件按照类型进行分类,可以分为如下几种:
鼠标键盘事件
;相机事件
;数据加载事件
;场景加载事件
。
按照事件的使用方式进行分类,可以分为如下两种:
- 创建事件处理器
Handler
并指定事件触发类型定义事件,如与鼠标键盘事件相关的屏幕空间事件处理器ScreenSpaceEventHandler
。 - Cesium 中已经定义好的事件回调,只需要添加事件监听的回调函数即可,如监听 3D Tiles 的瓦片全部加载完毕的回调函数
allTilesLoaded
。
鼠标键盘事件
要定义鼠标键盘事件,首先要创建一个屏幕空间事件处理器 ScreenSpaceEventHandler,该方法需要传入一个HTMLCanvasElement
用于指定事件处理器应用在哪个 Canvas 元素上,一般情况下指定为viewer.scene.canvas
,创建一个事件处理器的完整代码如下:
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
这样就成功创建了一个事件处理器,接下来就要使用事件处理器上的 setInputAction 方法来定义事件触发的类型和执行事件触发的回调函数。
其中鼠标的事件类型叫做“屏幕空间事件类型ScreenSpaceEventType
”,键盘的事件类型叫做“键盘事件修饰符KeyboardEventModifier
”
屏幕空间事件类型 ScreenSpaceEventType
因为 Cesium 的操作分为鼠标操作和触摸屏操作两种模式,所以屏幕空间事件类型ScreenSpaceEventType
分为两类:
- 鼠标操作
事件名称 | 类型 | 描述 |
---|---|---|
LEFT_DOWN | Number | 鼠标左键按下 |
LEFT_UP | Number | 鼠标左键弹起 |
LEFT_CLICK | Number | 鼠标左键单击 |
LEFT_DOUBLE_CLICK | Number | 鼠标左键双击 |
RIGHT_DOWN | Number | 鼠标右键按下 |
RIGHT_UP | Number | 鼠标右键弹起 |
RIGHT_CLICK | Number | 鼠标右键单击 |
MIDDLE_DOWN | Number | 鼠标中键按下 |
MIDDLE_UP | Number | 鼠标中键弹起 |
MIDDLE_CLICK | Number | 鼠标中键单击 |
MOUSE_MOVE | Number | 鼠标移动 |
WHEEL | Number | 鼠标滚轮滚动 |
- 触摸屏操作(仅作了解,本节不具体介绍)
事件名称 | 类型 | 描述 |
---|---|---|
PINCH_START | Number | 触摸屏开始两指触摸 |
PINCH_END | Number | 触摸屏结束两指触摸 |
PINCH_MOVE | Number | 触摸屏两指触摸移动 |
键盘事件修饰符 KeyboardEventModifier
事件名称 | 类型 | 描述 |
---|---|---|
SHIFT | Number | SHIFT 键被按住 |
CTRL | Number | CTRL 键被按住 |
ALT | Number | ALT 键被按住 |
事件注册方法 setInputAction
事件注册方法setInputAction
用于根据事件类型定义事件的触发方式并执行对应的回调函数,该方法的描述如下:
属性名称 | 类型 | 描述 |
---|---|---|
action | 指定不同的type 值会触发不同的回调函数,详见官方文档 setInputAction | 事件回调函数 |
type | 屏幕空间事件类型ScreenSpaceEventType | 屏幕空间事件类型 |
modifier | 键盘事件修饰符KeyboardEventModifier | 可选项,键盘事件修饰符 |
前面提到想要定义一个事件,首先要创建一个事件处理器handler
,再使用事件处理器handler
上的setInputAction
方法来指定事件的类型和事件的回调,如下面代码:
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
handler.setInputAction((movement) => {
// do something
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
至于在回调函数中内做些什么,是由触发的回调函数所决定的。
在方法描述中可以看到键盘事件修饰符modifier
为可选项,在 Cesium 中键盘事件类型是无法单独使用的,需要和鼠标事件类型一起使用,如下代码表示按住键盘CTRL
键并且点击鼠标左键才能触发事件回调函数:
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
handler.setInputAction((movement) => {
// do something
}, Cesium.ScreenSpaceEventType.LEFT_CLICK, Cesium.KeyboardEventModifier.CTRL)
事件回调函数
由于触发事件的类型各异,所以相应的也有不同的事件回调来处理不同的事件,事件回调函数分为如下几种:
PositionedEventCallback(event)
:PositionedEventCallback(event),所触发的事件类型为所有鼠标点击事件:LEFT_DOWN
、LEFT_UP
、LEFT_CLICK
、LEFT_DOUBLE_CLICK
、RIGHT_DOWN
、RIGHT_UP
、RIGHT_CLICK
、MIDDLE_DOWN
、MIDDLE_UP
、MIDDLE_CLICK
;MotionEventCallback(event)
:MotionEventCallback(event),所触发的事件类型为鼠标移动事件:MOUSE_MOVE
;WheelEventCallback(delta)
:WheelEventCallback(delta),所触发的事件类型为鼠标滚轮滚动事件:WHEEL
;TwoPointEventCallback(event)
(仅作了解,本节不具体介绍):TwoPointEventCallback(event),所触发的事件类型为触摸屏两指触摸事件:PINCH_START
、PINCH_END
;TwoPointMotionEventCallback(event)
(仅作了解,本节不具体介绍):TwoPointMotionEventCallback(event),所触发的事件类型为触摸屏两指移动事件:PINCH_MOVE
PositionedEventCallback(event)
该回调函数会返回一个Cartesian2
对象:
参数名称 | 类型 | 描述 |
---|---|---|
position | Cartesian2 | 鼠标点击的笛卡尔平面直角坐标 |
代码如下:
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
handler.setInputAction((position) => {
// position中包含一个Cartesian2对象
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
MotionEventCallback(event)
该回调函数会返回一个移动起点的Cartesian2
对象和一个移动终点的Cartesian2
对象:
参数名称 | 类型 | 描述 |
---|---|---|
startPosition | Cartesian2 | 鼠标移动起点的笛卡尔平面直角坐标 |
endPosition | Cartesian2 | 鼠标移动终点的笛卡尔平面直角坐标 |
代码如下:
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
handler.setInputAction((positions) => {
// positions中包含startPosition和endPosition两个Cartesian2对象
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
WheelEventCallback(delta)
该回调函数会返回一个delta
值,为鼠标滚轮滚动的值:
参数名称 | 类型 | 描述 |
---|---|---|
delta | Number | 鼠标滚轮滚动的值 |
代码如下:
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
handler.setInputAction((delta) => {
// delta为鼠标滚轮滚动的值
}, Cesium.ScreenSpaceEventType.WHEEL)
移除事件 removeInputAction
定义 Cesium 中的事件往往是执行某一个具体的操作,如鼠标点击拾取,当操作执行结束后需要移除该事件,避免对后续操作造成影响,移除事件的方法为removeInputAction
,该方法的描述如下:
参数名称 | 类型 | 描述 |
---|---|---|
type | ScreenSpaceEventType | 屏幕空间事件类型 |
modifier | KeyboardEventModifier | 可选项,键盘事件修饰符 |
使用方法如下:
// 移除鼠标左键单击事件
handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
相机事件
与相机相关的事件有三个:
viewer.camera.changed
:viewer.camera.changed,当相机改变时触发;viewer.camera.moveStart
:viewer.camera.moveStart,当相机开始移动时触发;viewer.camera.moveEnd
:viewer.camera.moveEnd,当相机结束移动时触发。
由于这三个事件都为 Cesium.Event() 类型,因此需要使用addEventListener
方法添加事件监听并指定回调函数,如下面代码:
viewer.camera.changed.addEventListener(() => {
// camera changed
})
viewer.camera.moveStart.addEventListener(() => {
// camera moveStart
})
viewer.camera.moveEnd.addEventListener(() => {
// camera moveEnd
})
数据加载事件
在 Cesium 中,常见的数据加载类型和相关事件包含以下几种:
-
Cesium3DTileset:常见事件如下:
- allTilesLoaded:当所有满足屏幕空间误差的瓦片集加载完成后触发,此时瓦片集已经完全加载;
- initialTilesLoaded:当所有满足屏幕空间误差的瓦片集加载完成后触发,此时初始视图已经加载完成,该方法的触发在
allTilesLoaded
之后; - loadProgress:当请求瓦片时触发,该方法会提供请求挂起的瓦片数量
numberOfPendingRequests
和正在处理的瓦片数量numberOfTilesProcessing
两个参数; - tileFailed:当一个瓦片请求失败时触发,该方法会提供一个
error
对象,包含请求失败的瓦片 url 和请求失败的原因message
; - tileUnload:当一个瓦片卸载后触发,卸载指的是从内存中删除,被卸载的原因为设置的
maximumMemoryUsage
大小不足,或者是trimLoadedTiles()
方法被调用。 - tileLoad:当一个瓦片加载后触发;
- tileVisible:当一个瓦片可见时触发。
-
Entity:常见事件如下:
- definitionChanged:当实体的属性发生改变时触发。
-
DataSource:常见事件如下:
- changedEvent:当数据发生改变时触发;
- errorEvent:当数据加载时发生错误触发;
- loadingEvent:当数据的值发生改变时触发。
Cesium3DTileset 加载示例
本例中将使用allTilesLoaded
、initialTilesLoaded
、loadProgress
和tileLoad
这四个事件说明 3D tiles 的加载过程。
主要代码如下:
// 加载3D tiles
const tileset = viewer.scene.primitives.add(
new Cesium.Cesium3DTileset({
url: '../3dtiles/tilesset/tileset.json',
})
)
// 视角定位到3D tiles
viewer.zoomTo(tileset)
// allTilesLoaded 瓦片集加载完成
tileset.allTilesLoaded.addEventListener(() => {
console.log('allTilesLoaded,瓦片集加载完成')
})
// initialTilesLoaded 瓦片集加载完成,并且场景初始化完成
tileset.initialTilesLoaded.addEventListener(() => {
console.log('initialTilesLoaded,瓦片集加载完成,并且场景初始化完成')
})
// loadProgress 瓦片加载进度
tileset.loadProgress.addEventListener((numberOfPendingRequests, numberOfTilesProcessing) => {
if ((numberOfPendingRequests === 0) && (numberOfTilesProcessing === 0)) {
console.log('loadProgress,加载完成')
return
}
console.log('loadProgress,请求挂起的瓦片数量' + numberOfPendingRequests + ', 正在处理的瓦片数量: ' + numberOfTilesProcessing);
})
// tileLoad 一个瓦片被加载
tileset.tileLoad.addEventListener(tile => {
console.log('tileLoad,一个瓦片被加载了', tile)
})
// 显示3D tiles的瓦片包围盒
tileset.debugShowContentBoundingVolume = true
页面效果如下:
根据控制台输出可以得到如下结论:
- 最先被调用的是
loadProgress
,表示当前正处于瓦片请求阶段; - 第二个被调用的是
tileLoad
,表示当前正处于单个瓦片加载阶段,根据 3D tiles 瓦片包围盒可以看到共有 5 个Cesium3Dtiles
,因此该事件被触发了 5 次; - 第三个被调用的是
allTilesLoaded
,表示满足当前屏幕空间误差的瓦片集已经完全加载; - 最后一个被调用的是
initialTilesLoaded
,表示满足当前屏幕空间误差的瓦片集已经完全加载,并且初始化视图已经完成。
场景渲染事件
在 Cesium 中,与场景渲染有关的事件都在 Scene 对象上,常见的事件如下:
- postRender:当场景渲染完成后触发;
- postUpdate:在场景更新后和渲染场景之前立即触发的事件;
- preRender:在场景渲染之前触发;
- preUpdate:在更新或渲染场景之前触发的事件;
- terrainProviderChanged:当地形提供者发生改变时触发。
场景渲染示例
本例中将使用postRender
、postUpdate
、preRender
和preUpdate
这四个事件说明场景 Scene 的渲染过程。
主要代码如下:
viewer.scene.postRender.addEventListener(() => {
console.log('postRender')
})
viewer.scene.postUpdate.addEventListener(() => {
console.log('postUpdate')
})
viewer.scene.preRender.addEventListener(() => {
console.log('preRender')
})
viewer.scene.preUpdate.addEventListener(() => {
console.log('preUpdate')
})
由于 Cesium 会自动开启渲染循环RenderLoop
,所以在使用该示例时,要关闭 Cesium 的自动渲染,关闭方法如下:
viewer.useDefaultRenderLoop = false // 关闭Cesium场景自动渲染
关闭后需要主动触发渲染,触发的方法如下:
viewer.render() // 主动触发Ceisum场景渲染
页面效果如下,首次打开时场景还没有被渲染:
点击 6 次触发渲染按钮后,地球将会被渲染出来:
点击 7 次触发渲染按钮后,地球外围的大气层将会被渲染出来:
根据控制台输出可以得到如下结论,在每一次渲染周期下:
- 最先被调用的是
preUpdate
,表示当前正处于场景更新之前阶段; - 第二个被调用的是
postUpdate
,表示当前正处于场景更新之后阶段; - 第三个被调用的是
preRender
,表示当前正处于场景渲染之前阶段; - 最后一个被调用的是
postRender
,表示当前正处于场景渲染之后阶段。
总得来说,更新Update
操作是先于渲染Render
操作的,可以使用这些事件将一些外部 DOM 操作放在事件内,避免渲染后操作造成页面抖动。
🎯 这篇文章是 Cesium 三维地球可视化从入门到进阶
专栏的第三篇文章,主要是对 Cesium 中常用的事件及其使用方法:鼠标键盘事件
、相机事件
、数据加载事件
、场景加载事件
做了详解
🎯 在后续的文章中, 将会分享更多
的实践案例
,如果你也对 三维可视化
比较感兴趣的话,欢迎关注我一起学习
🎯 Github 仓库地址:https://github.com/xushanpei/Cesium_Study_Cases
写在最后
公众号
:前端开发爱好者
专注分享web
前端相关技术文章
、视频教程
资源、热点资讯等,如果喜欢我的分享,给 🐟🐟 点一个赞
👍 或者 ➕关注
都是对我最大的支持。
大家好,我 xy,是一名前端 🤫 爱好:瞎折腾
如果你也是一名瞎折腾的前端欢迎加我微信交流哦...