跳到主要内容

事件系统

Five发布订阅者模式 来管理内部异步行为,你可以通过 five.on()five.once() 监听 Five 生命周期、交互反馈等异步事件。当然,您也可以通过 five.off() 注销添加的订阅回调函数。

提示

完整的 Five 异步事件您可以从 Five.EventCallback 查看, 本文仅针对常用的异步事件做简要说明。

加载进度

从执行 five.load(work) 到渲染出 3D 全景和模型主要经历四个关键阶段:

请求立方体全景贴图请求模型贴图解析三维空间数据渲染三维模型

Five 加载过程

全景贴图

绝大部分场景下, Five 渲染默认模态就是 Panorama,完成六张立方体全景图下载之后即可以进行全景交互。

/* 您的进度条逻辑 */
const progress = (pst: number) => {
if (pst === 1) {
five.off("textureLoading", progress);
}
const percentage = (pst * 0.75 + 0.2) * 100;
};
five.on("textureLoading", progress);

// 全景图完成渲染,在当前点位可以交互
five.once("panoArrived", () => {});
警告

five.on('textureLoading') 仅表示全景贴图的下载进度,与 five.once('panoArrived') 完全能全景交互大概还有 100ms 左右的延迟。

模型状态

five.on("modelMaterialLoaded", () => {
/* 模型材质加载完成 */
});

five.on("modelGeometryLoaded", () => {
/* 模型三角面片数据加载完成 */
});

five.on("modelLoaded", () => {
/* 模型加载完成 */
});

状态变更

前文提到过可以通过 five.setState()five.state() 方法获取、修改 Five 状态。

可以通过 five.on('stateChange') 来获取 Five 状态发生变更事件:

five.on("stateChange", (newState, oldState, userAction) => {});
警告

userAction 表示是否由用户通过点击、旋转等交互造成的变更。

全景游走

Panorama 全景游走模态 下,你可以在空间游走(切换全景点位),这里也会有部分关键事件:

five.on("wantsMoveToPano", (panoIndex) => {
/* 意图到某个点位 */

return false; /* 如果返回值是 false,则会中止后面的行为 */
});

five.on("panoWillArrive", (panoIndex) => {
/* 准备开始去某个点位 */
});

five.on("movingToPano", (panoIndex) => {
/* 在去某个点位的移动过程 */
});

five.on("panoArrived", (panoIndex) => {
/* 已经到达某个点位 */
});

模态切换

除了全景模态下点位间游走,模态间的切换也有相关事件:

five.on("wantsChangeMode", (mode: Mode, prevMode: Mode) => {
/* 将要切换模态: 可以通过 return false 阻止 */
});

five.on("modeChange", (mode: Mode, prevMode: Mode) => {
/* 模态已经切换,但是 UI 效果不一定完全渲染到新模态,有一段动画*/
});

需要注意的是模态间切换是附带动画的,可以监听动画执行事件:

five.on("initAnimationWillStart", () => {
/* 模态间切换动画开始 */
});

five.on("initAnimationEnded", () => {
/* 模态间切换动画结束 */
});

手势操作

// 手势操作
five.on(
"gesture",
(
// GestureTypes: "pan" | "tap" | "pinch" | "press" | "mouseWheel"
type: GestureTypes,
// 多指
pointers: { delta?: number; x: number; y: number }[],
// 是否结束
final: boolean
) => {}
);

滑动屏幕

five.on("wantsPanGesture", (pose: Pose, final: boolean) => {
// 滑动屏幕 手势将要被触发(尚未触发)
// 可以通过 return false 阻止触发
});

five.on("panGesture", (pose: Pose, final: boolean) => {
// 滑动屏幕 手势被触发
});

点击屏幕

// 低于 250ms
five.on(
"wantsTapGesture",
(
raycaster: Raycaster,
tapPosition: Vector2,
duration: number,
final: boolean
) => {
// 轻触屏幕 手势将要被触发(尚未触发)
// 可以通过 return false 阻止触发
}
);

five.on(
"tapGesture",
(
raycaster: Raycaster,
tapPosition: Vector2,
duration: number,
final: boolean
) => {
// 轻触屏幕 手势被触发
}
);
// 大于 250ms
five.on(
"wantsPressGesture",
(
raycaster: Raycaster,
tapPosition: Vector2,
duration: number,
final: boolean
) => {
// 点击屏幕 手势将要被触发(尚未触发)
// 可以通过 return false 阻止触发
}
);

five.on(
"pressGesture",
(
raycaster: Raycaster,
tapPosition: Vector2,
duration: number,
final: boolean
) => {
// 点击屏幕 手势被触发
}
);

双指缩放

five.on("wantsPinchGesture", (pose: Pose, final: boolean) => {
// 双指缩放 手势将要被触发(尚未触发)
// 可以通过 return false 阻止触发
});

five.on("pinchGesture", (pose: Pose, final: boolean) => {
// 双指缩放 手势将要被触发(尚未触发)
// 可以通过 return false 阻止触发
});

鼠标滚轮

five.on("wantsMouseWheel", (delta: number, fov: number, final: boolean) => {
// 鼠标滚轮 手势将要被触发(尚未触发)
// 可以通过 return false 阻止触发
});

five.on("mouseWheel", (delta: number, fov: number, final: boolean) => {
// 鼠标滚轮 手势被触发
});

焦点圆环

三维空间内部会有个焦点圆环,引导当前鼠标或触屏区域,当进行移动手势时焦点圆环的位置和方向会被重新计算。

five.on(
"intersectionOnModelUpdate",
(
intersection: Intersection, // 焦点碰撞监测结果
mesh: IntersectMeshInterface // 焦点环
) => {
// 鼠标焦点环位置被重新计算
}
);