@realsee/five
Version:
Realsee Renderer SDK
274 lines (207 loc) • 8.63 kB
Markdown
# Events (事件系统)
- **Summary**: Five 提供了一套基于发布/订阅模式的事件系统,用于监听用户交互、状态变更、数据加载及渲染生命周期。
- **Schema**: `on` / `once` / `off` 接口定义;`BaseEvent` / `BaseExtendableEvent` 事件对象。
- **Concepts**: Event 对象(`preventDefault` / `waitUntil`)、Gesture Events, State Events, Pano Events, Model Events, Lifecycle Events.
- **Examples**: 监听全景移动、手势交互及状态变更;使用 `preventDefault` 拦截默认行为;使用 `waitUntil` 延迟点位切换。
## Schema
> **Definition**: [Five](../../five/application/five.d.ts), [EventTypes](../../five/application/events.d.ts)
Five 实例提供了以下方法来管理事件监听:
### on
注册持久化事件监听器。
```typescript
five.on(
name: string,
callback: (...args: any[]) => void,
once?: boolean
): () => void
```
- **name**: 事件名称(支持的事件见 Concepts)。
- **callback**: 事件触发时的回调函数。
- **once**: (可选) 是否仅执行一次,默认为 `false`。
- **返回**: 一个函数,调用该函数可取消当前监听。
### once
注册一次性事件监听器(触发一次后自动销毁)。
```typescript
five.once(
name: string,
callback: (...args: any[]) => void
): () => void
```
### off
取消事件监听。
```typescript
five.off(
name?: string,
callback?: (...args: any[]) => void
): void
```
- **name**: (可选) 若不传,则清空所有事件;若传,则取消指定类型的事件。
- **callback**: (可选) 若传,则仅取消该特定的回调函数;若不传,则取消该类型下的所有回调。
## Event 对象
> **Definition**: [BaseEvent / BaseExtendableEvent](../../five/utils/event.d.ts)
Five 中所有事件回调的参数都是一个 Event 对象,分为两种基础类型:
### BaseEvent
所有事件的基础接口,包含以下属性和方法:
```typescript
interface BaseEvent {
/** 事件类型名称 */
type: string;
/** 事件触发时的时间戳 */
timeStamp: number;
/** 阻止事件的默认行为 */
preventDefault(): void;
/** 是否已调用过 preventDefault */
readonly defaultPrevented: boolean;
}
```
### BaseExtendableEvent
继承自 `BaseEvent`,额外提供 `waitUntil` 方法,用于在事件处理中插入异步等待逻辑:
```typescript
interface BaseExtendableEvent extends BaseEvent {
waitUntil(f: Promise<any>): void;
}
```
目前 `pano.prepare` 事件使用 `BaseExtendableEvent`(对应 `PanoPrepareEvent`),其余事件均基于 `BaseEvent`。
`PanoPrepareEvent` 额外包含以下属性:
| 属性 | 类型 | 描述 |
| :--- | :--- | :--- |
| `options` | `MovePanoOptions` | 点位切换时的选项(如 `effect`、`duration`、`longitude`、`latitude`、`fov` 等)。**支持在回调中修改此对象**,修改后的值将影响实际的切换行为。 |
| `prevMode` | `Mode` | 切换发生前的显示模式。 |
| `prevPano` | `Pano` | 切换前的点位信息。 |
| `pano` | `Pano` | 目标点位信息。 |
### preventDefault
调用 `event.preventDefault()` 可以阻止事件的默认行为。Five 内部会在触发事件后检查 `event.defaultPrevented`,若为 `true` 则跳过后续的默认处理逻辑。
比如:
- `gesture.tap`:阻止默认的点位跳转或相机弹跳动画。
- `intersect.update`:阻止默认的交互高亮行为。
```typescript
// 示例:阻止点击时的默认点位跳转
five.on("gesture.tap", (event) => {
if (shouldBlockNavigation()) {
event.preventDefault();
// 执行自定义逻辑
showCustomMenu(event);
}
});
// 示例:阻止拖拽时的默认相机旋转
five.on("gesture.pan", (event) => {
event.preventDefault();
// 用拖拽手势实现自定义交互(如绘制标注)
drawAnnotation(event);
});
```
### waitUntil
`waitUntil(promise)` 仅在 `ExtendableEvent` 上可用。调用后,Five 会等待传入的 Promise 完成后再继续后续流程。可多次调用,所有 Promise 会被并行等待。
目前仅 `pano.prepare` 事件支持 `waitUntil`。
```typescript
// 示例:在切换点位前预加载资源
five.on("pano.prepare", (event) => {
// event.pano 目标点位
// event.prevPano 切换前点位
// event.prevMode 切换前模式
// 等待自定义资源加载完成后再继续点位切换
event.waitUntil(
loadCustomResources(event.pano)
);
// 可以多次调用,所有 Promise 会被并行等待
event.waitUntil(
preloadTextures(event.pano)
);
});
// 示例:通过 waitUntil reject 来取消走点
five.on("pano.prepare", (event) => {
event.waitUntil(
showConfirmDialog("是否前往该点位?").then((confirmed) => {
if (!confirmed) {
throw new Error("用户取消走点");
}
})
);
});
// 示例:修改 event.options 影响切换行为
five.on("pano.prepare", (event) => {
// 修改切换动画效果为无动画
event.options.effect = "instant";
// 或修改切换后的相机朝向
event.options.longitude = Math.PI / 4;
event.options.latitude = 0;
event.options.fov = 90;
// 注意:直接修改 event.options 属性即可,不需要重新赋值 event.options
});
```
> **注意**: `preventDefault` 和 `waitUntil` 必须在事件回调的同步执行阶段调用,不能放在 `await` 之后。
## Concepts
Five 的事件系统将事件主要分为以下几类:
### Gesture Events (交互手势)
监听用户的鼠标或触摸操作。
- `gesture.tap`: 点击/轻触。
- `gesture.dbltap`: 双击/双击轻触。
- `gesture.press`: 长按。
- `gesture.pan`: 平移/拖拽。
- `gesture.pinch`: 缩放(双指或滚轮)。
- `gesture.mousewheel`: 鼠标滚轮滚动。
- `gesture.mousemove`: 鼠标移动。
### Pano Events (全景导航)
监听全景图的点位切换过程。
- `pano.prepare`: 准备切换到新点位。这是一个 `ExtendableEvent`,支持通过 `waitUntil(promise)` 延迟后续加载流程(如预加载资源),以及通过 `preventDefault()` 取消本次走点。事件对象包含 `options`(可修改,影响切换行为)、`prevMode`(切换前模式)、`prevPano`(切换前点位)、`pano`(目标点位)等属性。
- `pano.arrived`: 成功到达新点位(移动动画结束)。
- `pano.moving`: 正在移动到新点位(动画进行中)。
- `pano.willChange`: 即将发生点位变更(旧版兼容)。
- `pano.error`: 点位加载或移动出错。
### State Events (状态变更)
监听 Five 内部状态(State)的变化,常用于 UI 同步或数据记录。
- `state.change`: 状态发生变更(可能是用户操作或代码触发)。
- `currentState.change`: 当前状态发生变更(通常指即时状态)。
- `state.synced`: 状态已同步。
### Model & Work Events (数据加载)
监听场景数据(Work)或模型(Model)的加载生命周期。
- `works.load`: Work 数据开始加载。
- `works.ready`: Work 数据加载完成且 Controller 就绪。
- `model.load`: 模型开始加载。
- `models.load`: 所有模型加载完成。
### Render Events (渲染循环)
监听每一帧的渲染过程。
- `render`: 每一帧渲染后触发。
- `render.prepare`: 每一帧渲染前触发。
## Examples
### 快速上手 (Quick Example)
监听点击事件并打印日志。
```typescript
import { Five } from "@realsee/five";
const five = new Five();
// 监听点击事件
five.on("gesture.tap", (event) => {
console.log("User tapped at:", event);
});
// 监听点位变更完成
five.on("pano.arrived", (event) => {
console.log("Arrived at pano:", event.pano);
});
```
### 进阶用法 (Advanced Usage)
使用 `once` 监听一次性初始化事件,使用返回值取消监听。
```typescript
// 1. 等待首次数据加载完成
five.once("works.ready", () => {
console.log("Five is ready!");
// 执行初始化逻辑,如自动巡游
});
// 2. 动态绑定与解绑
const onRender = () => {
// 每一帧执行的逻辑
updateUI();
};
// 开始监听
five.on("render", onRender);
// 在某个时刻取消监听(例如组件销毁时)
// five.off("render", onRender);
```
## Debugging
- 使用 `five.on("error", (err) => console.error(err))` 捕获全局错误。
## Related
- [State](./state.md): 了解 State 的结构与变更机制。
- [Five](./five.md): Five 核心类说明。
---
```yaml
tags: [事件监听, 点击, 拖拽, 加载完成, 渲染回调, 生命周期, 回调, events, interaction, lifecycle, gesture, state, preventDefault, waitUntil, on, off, subscribe]
```