Skip to main content

事件系统

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

tip

完整的 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', () => {})
caution

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) => {})
caution

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 // 焦点环
) => {
// 鼠标焦点环位置被重新计算
})