G
Q
Q
and
M
E

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_DOWNLEFT_UPLEFT_CLICKLEFT_DOUBLE_CLICKRIGHT_DOWNRIGHT_UPRIGHT_CLICKMIDDLE_DOWNMIDDLE_UPMIDDLE_CLICK;
  • MotionEventCallback(event):所触发的事件类型为鼠标移动事件:MOUSE_MOVE
  • WheelEventCallback(delte): 所触发的事件类型为鼠标滚轮滚动事件:WHEEL;
  • TwoPointEventCallback(evnet):所触发的事件类型为触摸屏两指触摸事件:PINCH_SRARTPINCH_END
  • TwoPointMotionEventCallback(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和请求失败的原因message
  • tileUnload:当一个瓦片卸载后触发,卸载指的是从内存中删除,被卸载的原因因为设置maximumMemoryUsage大小不足,或是trimLoadedTiles()方法被调用
  • tileLoad:当一个瓦片加载后触发
  • tileVisible:当一个瓦片可见时触发

 
Entity常见事件如下:
definitionChanged:当实体的属性发生改变时触发

 

DataSource常见事件如下:

  • changedEvent:当数据发生改变时触发
  • errorEvent:当数据加载时发生错误时触发
  • loadingEvent:当数据的值发生改变时触发

Cesium3DTileset加载示例

本例中将使用allTilesLoadedinitialTilesLoadedloadProgresstileLoad这四个事件说明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:当地形提供者发生改变时触发
场景渲染示例

本实例中将使用postRenderpostUpdatepreRenderpreUpdate这四个事件说明场景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操作放在事件内,避免渲染后操作造成页面抖动。

posted @ 2023-12-18 09:39  sy0313  阅读(1056)  评论(0编辑  收藏  举报