cesium.js入门基础教程四(事件)
事件简介
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分为两类:
1.鼠标操作
| 事件名称 | 类型 | 描述 |
|---|---|---|
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 |
鼠标中键单击 |
MIDDLE_MOVE |
Number |
鼠标移动 |
WHEEL |
Number |
鼠标滚轮滚动 |
2.触摸屏操作
| 事件名称 | 类型 | 描述 |
|---|---|---|
PINCH_START |
Number |
触摸屏开始两指触摸 |
PINCH_END |
Number |
触摸屏结束两指触摸 |
PINCH_MOVE |
Number |
触摸屏两指触摸移动 |
键盘事件修饰符KeyboardEventModifier
| 事件名称 | 类型 | 描述 |
|---|---|---|
SHIFT |
Number |
shift键被按住 |
CTRL |
Number |
ctrl键被按住 |
ALT |
Number |
ALT键被按住 |
事件注册方法 setInputAction
事件注册方法setInputAction用于根据事件类型定义事件的触发方式并执行对应的回调函数,该方法的描述如下:
| 属性名称 | 类型 | 描述 |
|---|---|---|
action |
指定不同的type值会触发不同的回调函数,详见官网 |
shift键被按住 |
CTRL |
屏幕空间事件类型ScreenSpaceEventType |
屏幕空间事件类型 |
ALT |
键盘事件修饰符KeyboardEventModifier |
可选项,键盘事件修饰符 |
前面提到想要定义一个事件,首先要创建一个事件处理器handler,再使用事件处理器handler上的setInputAction方法来指定事件的类型和事件的回调,如下面代码:
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene,canvas);
handler.setInputAction(movement=>{
//do someting
},Cesium.ScreenSpaceEventType.LEFT_CLICK)
至于在回调函数中做些什么,是由触发的回调函数来决定的
在方法描述中可以看到键盘事件修饰符modifier为可选项,在Cesium中键盘事件类型是无法单独使用的,需要和鼠标事件类型一起使用,如下代码表示按住键盘CTRL键并且点击鼠标左键才能触发事件回调函数:
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene,canvas);
handler.setInputAction(movement=>{
//do someting
},Cesium.ScreenSpaceEventType.LEFT_CLICK,Cesium.KeyboardEventModifier.CTRL)
事件回调函数
由于触发事件的类型各异,所以对应的也有不同的事件回调来处理不同的事件,事件回调函数分为如下几种:
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):所触发的事件类型为鼠标移动事件:MOUSE_MOVEWheelEventCallback(delte): 所触发的事件类型为鼠标滚轮滚动事件:WHEEL;TwoPointEventCallback(evnet):所触发的事件类型为触摸屏两指触摸事件:PINCH_SRART、PINCH_ENDTwoPointMotionEventCallback(event):所触发事件类型为触摸屏两指移动事件:PINCH_MOVE
PositionedEventCallback(event)
该回调函数会返回一个Cartesian2对象:
| 参数名称 | 类型 | 描述 |
|---|---|---|
position |
Cartesian2 |
鼠标点击的笛卡尔平面直角坐标系 |
代码如下:
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(position=>{
console.log(position)
},Cesium.ScreenSpaceEventType.LEFT_CLICK)
WheelEventCallback(delta)
该回调函数会返回一个delta值,为鼠标滚轮滚动的值:
| 参数名称 | 类型 | 描述 |
|---|---|---|
delta |
Number |
鼠标滚轮滚动的值 |
代码如下:
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(delta=>{
//do something
},Cesium.ScreenSpaceEventType.WHEEL)
移除事件 removeInputAction
定义Cesium中的事件往往是执行某一个具体的操作,如鼠标点击拾取,当操作执行结束后需要移除该事件,避免对后续操作造成影像,移除事件的方法removeInputAction,该方法的描述如下:
| 参数名称 | 类型 | 描述 |
|---|---|---|
type |
ScreenSpaceEventType |
屏幕空间事件类型 |
type |
KeyboardEventModifier |
可选项,键盘事件修饰符 |
使用方法如下:
handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
相机事件
与相机相关的事件又三个:
viewer.cameara.changed:当相机改变触发viewer.camera.moveStart:当相机开始移动时触发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和请求失败的原因messagetileUnload:当一个瓦片卸载后触发,卸载指的是从内存中删除,被卸载的原因因为设置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场景渲染
- 最先被调用的是preUpdate,表示当前正处于场景更新之前阶段;
- 第二个被调用的是postUpdate,表示当前正处于场景更新之后阶段;
- 第三个被调用的是preRender,表示当前正处于场景渲染之前阶段;
- 最后一个被调用的是postRender,表示当前正处于场景渲染之后阶段。
总的来说,更新Update操作是先于渲染Render操作的,可以使用这些事件将一些外部DOM操作放在事件内,避免渲染后操作造成页面抖动。
浙公网安备 33010602011771号