事件应用
Cesium 中根据事件的类型、用途,可以将事件分为三大类:
事件 | 类 | 描述 |
---|---|---|
鼠标操作事件 | ScreenSpaceEventHandler | 鼠标左键、鼠标中键、鼠标右键操作 |
通用Event事件 | 无具体类 | 该类通常在容器类内部实例化,并作为某个属性的类型被直接调用 |
相机控制事件 | ScreenSpaceCameraController | 该类通过与 CameraEventType 类配合实现相机的控制 |
鼠标事件
Cesium 中鼠标事件可以分为两个过程:
- 传递 viewer.canvas 参数,实例化 ScreenSpaceEventHandler 类;
- 使用 setInputAction() 方法设置鼠标事件,在回调函数中获取鼠标信息;
鼠标事件创建
对 ScreenSpaceEventHandler 类进行实例化,注册事件和注销事件:
js
const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
const eventType = cesium.ScreenSpaceEventType.LEFT_CLICK;
// 注册事件
handler.setInputAction((e) => {
console.log(e);
}, eventType);
// 注销事件
handler.removeInputAction(eventType);
上面代码中的事件类型直接采用了 ScreenSpaceEventType 中的常量,它包括以下几种:
鼠标左键
事件类型 作用 LEFT_CLICK 左键单击 LEFT_DOUBLE_CLICK 左键双击 LEFT_DOWN 左键按下 LEFT_UP 左键弹起 鼠标中键
事件类型 作用 MIDDLE_CLICK 中键单击 MIDDLE_DOWN 中键按下 MIDDLE_UP 中键弹起 鼠标右键
事件类型 作用 RIGHT_CLICK 右键单击 RIGHT_DOWN 左键按下 RIGHT_UP 左键弹起 双指触摸
事件类型 作用 PINCH_START 双指开始事件 PINCH_END 双指结束事件 PINCH_MOVE 双指更改事件 其他鼠标事件
事件类型 作用 MOUSE_MOVE 鼠标移动事件 WHEEL 鼠标滚轮事件
要素拾取
假设应用场景比较复杂,存在 Entity、Primitive、Model、3D Tiles 等多种要素时,鼠标拾取时可能会拾取到多个元素,如果想拾取单一元素时,可以使用 instanceof 方法来判断。
js
const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
const eventType = cesium.ScreenSpaceEventType.LEFT_CLICK;
handler.setInputAction(e => {
const picked = viewer.scene.pick(e.position);
if (Cesium.defined(picked)) {
if (picked.id && picked.id instanceof Cesium.Entity) {
console.log("选中了Entity", picked);
}
if (picked.primitive instanceof Cesium.Primitive) {
console.log("选中了Primitive", picked);
}
if (picked.primitive instanceof Cesium.Model) {
console.log("选中了Model", picked);
}
if (picked instanceof Cesium.Cesium3DTileFeature) {
console.log("选中了3DTiles", picked);
}
}
}, eventType);
获取鼠标坐标
js
const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
const eventType = cesium.ScreenSpaceEventType.LEFT_CLICK;
handler.setInputAction(e => {
const pickPosition = viewer.scene.camera.pickEllipsoid(e.position);
if (Cesium.defined(pickPosition)) {
// 笛卡尔坐标转为弧度坐标
const Cartographic = Cesium.Cartographic.fromCartesian(pickPosition);
const lng = Cesium.Math.toDegrees(Cartographic.longitude);
const lat = Cesium.Math.toDegrees(Cartographic.latitude);
console.log({ lng, lat });
}
}, eventType);
js
const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
const eventType = cesium.ScreenSpaceEventType.LEFT_CLICK;
handler.setInputAction(e => {
// 根据屏幕位置获取摄像机射线
const ray = viewer.camera.getPickRay(e.position);
// 获取射线与地球表面的交点
const cartesian = viewer.scene.globe.pick(ray, viewer.scene);
if (Cesium.defined(cartesian)) {
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const lng = Cesium.Math.toDegrees(cartographic.longitude);
const lat = Cesium.Math.toDegrees(cartographic.latitude);
console.log({ lng, lat });
}
}, eventType);
为图层添加事件
js
// 绘制多边形
const instance = new Cesium.GeometryInstance({
id: "rectangle",
geometry: new Cesium.RectangleGeometry({
rectangle: Cesium.Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0)
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
}
});
viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: instance,
appearance: new Cesium.PerInstanceColorAppearance()
})
);
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
const eventType = cesium.ScreenSpaceEventType.LEFT_CLICK;
handler.setInputAction(e => {
const pick = viewer.scene.pick(e.position);
// 按照图层Id进行事件出发条件过滤
if (Cesium.defined(pick) && pick.id === "rectangle") {
console.log("Mouse clicked rectangle.");
}
}, eventType);
相机事件
相机控制事件类 screenSpaceCameraController 不像鼠标事件相关类那样需要提前实例化。Cesium 在 Viewer类的实例化过程中,也实例化了其他很多类,其中就包括了ScreenSpaceCameraController 类,并把实例化结果赋值给了viewer.scene.screenSpaceCameraController。
所以,我们直接去操作 viewer.scene.screenSpaceCameraController
就可以了。
鼠标控制
通过鼠标控制相机的方式取决于 CameraEventType 的常量,包括以下几种:
鼠标操作相机事件
事件类型 作用 LEFT_DRAG 按住鼠标左键,然后移动鼠标并释放按钮 MIDDLE_DRAG 按住鼠标中键,然后移动鼠标并释放按钮 RIGHT_DRAG 按住鼠标右键,然后移动鼠标并释放按钮 PINCH 触摸表面上的双指触摸 WHEEL 滚动鼠标中键
下面的示例,修改默认的鼠标事件,实现鼠标中键缩放,右键旋转。
js
const viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
baseLayerPicker: true
})
// 配置视图倾斜事件
viewer.scene.screenSpaceCameraController.tiltEventTypes = [
// 鼠标右键拖动时触发视图的倾斜操作
Cesium.CameraEventType.RIGHT_DRAG,
// 双指触摸时触发视图的倾斜操作
Cesium.CameraEventType.PINCH,
// 按住 Ctrl 键的同时,鼠标左键拖动时触发视图的倾斜操作
{
eventType: Cesium.CameraEventType.LEFT_DRAG,
mofifier: Cesium.KeyboardEventModifier.CTRL
},
// 按住 Ctrl 键的同时,鼠标右键拖动时触发视图的倾斜操作
{
eventType: Cesium.CameraEventType.RIGHT_DRAG,
mofifier: Cesium.KeyboardEventModifier.CTRL
}
]
// 配置视图缩放事件
viewer.scene.screenSpaceCameraController.zoomEventTypes = [
// 按住滚轮中键可以缩放
Cesium.CameraEventType.MIDDLE_DRAG,
// 滚动滚轮中键可以缩放
Cesium.CameraEventType.WHEEL,
// 手指可缩放
Cesium.CameraEventType.PINCH
]
键盘控制
通过操作键盘实现相机的漫游,比如前进、后退、向上、向下等。
Cesium 中实现键盘漫游主要通过调用相机的 moveForward、moveBackward、moveLeft、moveRight、moveUp、moveDown方法。
js
const viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
baseLayerPicker: true
})
const scene = viewer.scene
const canvas = viewer.canvas
const elliposid = scene.globe.ellipsoid
let startMousePosition: any
let mousePosition: any
const flags = {
looking: false,
moveForward: false,
moveBackward: false,
moveUp: false,
moveDown: false,
moveLeft: false,
moveRight: false
}
function getFlagForKeyCode(code: string) {
switch (code) {
case "KeyW":
return "moveForward"
case "KeyS":
return "moveBackward"
case "KeyQ":
return "moveUp"
case "KeyE":
return "moveDown"
case "KeyD":
return "moveRight"
case "KeyA":
return "moveLeft"
default:
return undefined
}
}
document.addEventListener("keydown", e => {
const flagName = getFlagForKeyCode(e.code)
if (typeof flagName !== "undefined") {
flags[flagName] = true
}
})
document.addEventListener("keyup", e => {
const flagName = getFlagForKeyCode(e.code)
if (typeof flagName !== "undefined") {
flags[flagName] = false
}
})
viewer.clock.onTick.addEventListener((_e: any) => {
const camera = viewer.camera
if (flags.looking) {
const width = canvas.width
const height = canvas.height
const x = (mousePosition.x - startMousePosition.x) / width
const y = (mousePosition.y - startMousePosition.y) / height
const lookFactor = 0.05
camera.lookRight(x * lookFactor)
camera.lookUp(y * lookFactor)
}
const cameraHeight = elliposid.cartesianToCartographic(
camera.position
).height
const 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)
}
})
场景渲染事件
场景渲染事件主要包括以下四种:
事件 | 作用 |
---|---|
scene.preUpdate | 更新或呈现场景之前将引发的事件 |
scene.postUpdate | 场景更新后,以及渲染场景之前立即引发的事件 |
scene.preRender | 场景更新后,以及渲染场景之前将引发的事件 |
scene.postRender | 渲染场景后立即引发的事件 |
事件的添加和移除代码示例:
js
viewer.scene.preUpdate.addEventListener(callback)
viewer.scene.preUpdate.removeEventListener(callback)
js
// 1.更新或呈现场景之前将引发的事件
viewer.scene.preUpdate.addEventListener(callbackFunc)
viewer.scene.preUpdate.removeEventListener(callbackFunc)
// 2.场景更新后以及渲染场景之前立即引发的事件
viewer.scene.postUpdate.addEventListener(callbackFunc)
viewer.scene.postUpdate.removeEventListener(callbackFunc)
// 3.场景更新后以及渲染场景之前将引发的事件
viewer.scene.preRender.addEventListener(callbackFunc)
viewer.scene.preRender.removeEventListener(callbackFunc)
// 4.渲染场景后立即引发的事件
viewer.scene.postRender.addEventListener(callbackFunc)
viewer.scene.postRender.removeEventListener(callbackFunc)
// 需要回调的函数
function callbackFunc(e: any) {
console.log(e)
}