事件系统
Five 以 发布订阅者模式 来管理内部异步行为,你可以通过 five.on()
或 five.once()
监听 Five 生命周期、交互反馈等异步事件。当然,您也可以通过 five.off()
注销添加的订阅回调函数。
提示
完整的 Five 异步事件您可以从 Five.EventCallback 查看, 本文仅针对常用的异步事件做简要说明。
加载进度
从执行 five.load(work)
到渲染出 3D 全景和模型主要经历四个关键阶段:
请求立方体全景贴图 ➩ 请求模型贴图 ➩ 解析三维空间数据 ➩ 渲染三维模型

全景贴图
绝大部分场景下, 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 // 焦点环
) => {
// 鼠标焦点环位置被重新计算
}
);