Cesium 快速入门(十三)事件系统

Cesium 快速入门(十三)事件系统

看过的知识不等于学会。唯有用心总结、系统记录,并通过温故知新反复实践,才能真正掌握一二

作为一名摸爬滚打三年的前端开发,开源社区给了我饭碗,我也将所学的知识体系回馈给大家,助你少走弯路!
OpenLayers、Leaflet 快速入门 ,每周保持更新 2 个案例
Cesium 快速入门,每周保持更新 4 个案例

Cesium 快速入门(一)快速搭建项目
Cesium 快速入门(二)底图更换
Cesium 快速入门(三)Viewer:三维场景的"外壳"
Cesium 快速入门(四)相机控制完全指南
Cesium 快速入门(五)坐标系
Cesium 快速入门(六)实体类型介绍
Cesium 快速入门(七)材质详解
Cesium 快速入门(八)Primitive(图元)系统深度解析
Cesium 快速入门(九)Appearance(外观)系统深度解析
Cesium 快速入门(十) JulianDate(儒略日期)详解
Cesium 快速入门(十一)3D Tiles 大规模三维地理空间数据
Cesium 快速入门(十二)数据加载详解
Cesium 快速入门(十三)事件系统

事件学习

Cesium 的事件系统允许开发者监听和响应场景中的各类交互与状态变化,涵盖 相机操作、实体交互、屏幕输入 等核心场景

屏幕空间事件

屏幕空间事件是最常用的事件类型,用于处理用户在屏幕上的交互操作,如鼠标点击、移动、悬停等,使用 new Cesium.ScreenSpaceEventHandler(element),ScreenSpaceEventHandler 官方文档

鼠标交互事件

js 复制代码
viewer.screenSpaceEventHandler.setInputAction(action, type, modifier);
参数 类型 描述
action Function 事件触发后执行的回调函数
type ScreenSpaceEventType 事件类型(如鼠标左键点击、移动等)
modifier KeyboardEventModifier 可选,键盘事件修饰符, 如 shift, ctrl, alt 等
名字 类型 描述
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 表示触摸表面上双指事件的更改。
实战案例:鼠标点击获取经纬度
js 复制代码
// 添加地图点击事件,点击后获取经纬度坐标
viewer.screenSpaceEventHandler.setInputAction(function (e) {
  // 点击后获取点击位置的笛卡尔坐标
  const cartesian = viewer.scene.pickPosition(e.position);

  // 必须判断坐标是否有效(当点击天空盒等位置时会返回undefined)
  if (Cesium.defined(cartesian)) {
    // 笛卡尔坐标转弧度坐标
    const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
    // 弧度转度数并保留6位小数
    const longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6);
    const latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6);
    const height = cartographic.height.toFixed(2);

    console.log(`经度: ${longitude}, 纬度: ${latitude}, 高度: ${height}米`);
  } else {
    console.log("无法获取有效坐标(可能点击了天空或地形外区域)");
  }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
事件销毁
js 复制代码
// 移除特定类型的事件监听
viewer.screenSpaceEventHandler.removeInputAction(
  Cesium.ScreenSpaceEventType.LEFT_CLICK
);

// 完全销毁事件处理器(释放资源,避免内存泄漏)
viewer.screenSpaceEventHandler.destroy();
实体点击检测

判断点击到实体并获取实体信息:

js 复制代码
// 添加实体
const circle = viewer.entities.add({
  id: "circle",
  name: "circle",
  description: "This is circle",
  position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
  ellipse: {
    semiMajorAxis: 1000,
    semiMinorAxis: 1000,
    material: Cesium.Color.RED.withAlpha(0.5),
    outline: true,
    outlineColor: Cesium.Color.WHITE,
  },
});
// 定位到实体
viewer.zoomTo(circle);

// 添加鼠标点击事件
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (e) {
  // 使用scene.pick方法获取点击位置的实体
  const pickedObject = viewer.scene.pick(e.position);
  if (
    Cesium.defined(pickedObject) &&
    pickedObject.id instanceof Cesium.Entity
  ) {
    const entity = pickedObject.id;
    console.log("实体信息:", entity); // 输出实体信息
  } else {
    console.log("未点击到实体");
  }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

键盘事件

注意:Cesium 的键盘修饰符不能单独使用,需要配合鼠标事件。如需监听独立键盘事件,需使用原生 JavaScript 事件。

键盘修饰符列表
名字 描述
SHIFT 表示 shift 键被按住
CTRL 表示 ctrl 键被按住
ALT 表示 alt 键被按住
组合事件示例
js 复制代码
// Shift+左键点击事件
viewer.screenSpaceEventHandler.setInputAction(
  function (e) {
    console.log("Shift+鼠标左键点击");
    // 可以实现选择多个实体等功能
  },
  Cesium.ScreenSpaceEventType.LEFT_CLICK,
  Cesium.KeyboardEventModifier.SHIFT
);

// Ctrl+Alt+右键点击事件
viewer.screenSpaceEventHandler.setInputAction(
  function (e) {
    console.log("Ctrl+Alt+鼠标右键点击");
  },
  Cesium.ScreenSpaceEventType.RIGHT_CLICK,
  [Cesium.KeyboardEventModifier.CTRL, Cesium.KeyboardEventModifier.ALT]
);

相机事件

相机事件(如 RIGHT_DRAG 和 WHEEL)用于控制场景的交互行为(如旋转、缩放、倾斜)

事件类型与默认行为

注: 默认行为通过 ScreenSpaceCameraController 控制

事件类型 默认操作 适用视图模式
CameraEventType.LEFT_DRAG 旋转地球(3D)或平移(2D) 3D/Columbus
CameraEventType.RIGHT_DRAG 缩放 所有模式
CameraEventType.MIDDLE_DRAG 倾斜地球 3D/Columbus
CameraEventType.WHEEL 缩放 所有模式
CameraEventType.PINCH 缩放/倾斜(触摸屏) 所有模式

自定义相机交互行为

通过修改screenSpaceCameraController属性自定义交互方式:

js 复制代码
const cameraController = viewer.scene.screenSpaceCameraController;

// 示例1:修改旋转事件为右键拖拽(默认是左键)
cameraController.rotateEventTypes = [Cesium.CameraEventType.RIGHT_DRAG];

// 示例2:修改缩放事件为仅支持滚轮
cameraController.zoomEventTypes = [Cesium.CameraEventType.WHEEL];

// 示例3:配置倾斜事件支持多种方式
cameraController.tiltEventTypes = [
  Cesium.CameraEventType.MIDDLE_DRAG, // 中键拖拽
  {
    eventType: Cesium.CameraEventType.LEFT_DRAG,
    modifier: Cesium.KeyboardEventModifier.CTRL,
  }, // Ctrl+左键拖拽
];

禁用默认相机交互

js 复制代码
const cameraController = viewer.scene.screenSpaceCameraController;

// 禁用所有相机交互(完全控制场景)
cameraController.enableRotate = false; // 禁用旋转
cameraController.enableZoom = false; // 禁用缩放
cameraController.enableTilt = false; // 禁用倾斜
cameraController.enableTranslate = false; // 禁用平移
cameraController.enableLook = false; // 禁用视角控制

场景事件

场景事件包括相机移动、场景渲染等生命周期事件,用于监控场景状态变化。

相机状态事件

名字 描述
moveStart 获取将在摄像机开始移动时引发的事件
moveEnd 获取当摄像机停止移动时将引发的事件
changed 获取当摄像机位置或方向发生变化时将引发的事件
js 复制代码
// 监听相机移动开始
viewer.camera.moveStart.addEventListener(() => {
  console.log("相机开始移动");
});

// 监听相机移动结束、获取相机位置
viewer.camera.moveEnd.addEventListener(() => {
  const positionCartographic = viewer.camera.positionCartographic;
  let cameraPosition = {};
  cameraPosition.y = Number(
    Cesium.Math.toDegrees(positionCartographic.latitude).toFixed(6)
  );
  cameraPosition.x = Number(
    Cesium.Math.toDegrees(positionCartographic.longitude).toFixed(6)
  );
  cameraPosition.z = Number(positionCartographic.height.toFixed(1));
  cameraPosition.heading = Number(
    Cesium.Math.toDegrees(viewer.camera.heading || -90).toFixed(1)
  );
  cameraPosition.pitch = Number(
    Cesium.Math.toDegrees(viewer.camera.pitch || 0).toFixed(1)
  );
  cameraPosition.roll = Number(
    Cesium.Math.toDegrees(viewer.camera.roll || 0).toFixed(1)
  );
  console.log("相机位置", cameraPosition);
});

// 监听相机位置或方向发生变化
viewer.camera.changed.addEventListener(() => {
  console.log("相机位置或方向发生变化");
});

场景渲染事件

事件名称 描述 触发频率
preUpdate 场景更新前触发 每帧
postUpdate 场景更新后触发 每帧
preRender 场景渲染前触发 每帧
postRender 场景渲染后触发 每帧
js 复制代码
// 监听场景更新之前的事件
viewer.scene.preUpdate.addEventListener(() => {
  console.log("场景更新之前");
});
// 监听场景更新之后的事件
viewer.scene.postUpdate.addEventListener(() => {
  console.log("场景更新之后");
});
// 监听场景渲染之前的事件
viewer.scene.preRender.addEventListener(() => {
  console.log("场景渲染之前");
});
// 监听场景渲染之后的事件
viewer.scene.postRender.addEventListener(() => {
  console.log("场景渲染之后");
});

// 限制高频事件的处理频率(性能优化)
let lastUpdateTime = 0;
viewer.scene.postUpdate.addEventListener((scene, time) => {
  // 每100ms处理一次,避免每帧处理影响性能
  if (time - lastUpdateTime > 0.1) {
    lastUpdateTime = time;
    // 执行需要定期更新的逻辑
  }
});

自定义事件系统

构建独立的事件总线,实现组件间解耦通信:

js 复制代码
// 创建自定义事件总线
const eventBus = {
  events: {},
  emit(event, data) {
    if (this.events[event]) {
      this.events[event].forEach((fn) => fn(data));
    }
  },
  on(event, callback) {
    if (!this.events[event]) this.events[event] = [];
    this.events[event].push(callback);
  },
};
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
// 在实体点击时触发自定义事件
handler.setInputAction((click) => {
  const picked = viewer.scene.pick(click.position);
  if (picked && picked.id) {
    eventBus.emit("entity-clicked", picked.id);
  }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

// 监听自定义事件
eventBus.on("entity-clicked", (entity) => {
  console.log("实体被点击:", entity.name);
});
相关推荐
QQ1__8115175157 小时前
Spring boot名城小区物业管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
钛态7 小时前
前端微前端架构:大项目的救命稻草还是自找麻烦?
前端·vue·react·web
一粒黑子7 小时前
【实战解析】阿里开源 PageAgent:纯前端 GUI Agent,一行JS让网页支持自然语言操控
前端·javascript·开源
独角鲸网络安全实验室7 小时前
2026微信小程序抓包全解析:从实操落地到合规风控,解锁前端调试新范式
前端·微信小程序·小程序·抓包·系统代理绕过·https证书严格校验·进程隔离
紫微AI7 小时前
前端文本测量成了卡死一切创新的最后瓶颈,pretext实现突破了
前端·人工智能·typescript
GISer_Jing7 小时前
AI前端(From豆包)
前端·aigc·ai编程
IT枫斗者7 小时前
前端部署后如何判断“页面是不是最新”?一套可落地的版本检测方案(适配 Vite/Vue/React/任意 SPA)
前端·javascript·vue.js·react.js·架构·bug
测试修炼手册7 小时前
[测试技术] 深入理解 JSON Web Token (JWT)
前端·json
AI老李7 小时前
2026 年 Web 前端开发的 8 个趋势!
前端
里欧跑得慢7 小时前
15. Web可访问性最佳实践:让每个用户都能平等访问
前端·css·flutter·web