UNPKG

@realsee/five

Version:

Realsee Renderer SDK

182 lines (135 loc) • 6.39 kB
# Gesture (手势与事件) - **Summary**: Five 提供了一套跨平台的手势事件系统,抹平了 PC 与移动端的差异,并针对不同 Mode 提供了默认的交互逻辑。 - **Schema**: `GestureEvent` 继承自 `StateEvent`,包含了手势中心点、射线等信息。 - **Concepts**: Gesture Type, Default Behavior, PreventDefault。 - **Examples**: 阻止默认行为、点击添加标记。 ## Schema > **Definition**: [GestureEvent](../../five/utils/event.d.ts) 所有手势事件的回调参数均为 `GestureEvent` 类型: ```typescript import { State } from "@realsee/five"; import * as THREE from "three"; interface GestureEvent { type: string; // 事件类型,如 "gesture.tap" timeStamp: number; // 时间戳 target: EventTarget | null; pointerType: 'touch' | 'pen' | 'mouse' | 'kinect'; // 手势中心点信息 center: { x: number; // 屏幕 X 坐标 y: number; // 屏幕 Y 坐标 raycaster: THREE.Raycaster; // 从相机发出的射线(已包含坐标变换) }; // 当前相机状态 state: State; // 是否是用户触发(区别于代码调用) userAction: boolean; // 阻止默认行为 preventDefault(): void; defaultPrevented: boolean; } ``` ## Concepts Five 的手势系统基于 Hammer.js 封装,主要包含以下几种手势: * **gesture.fire**: 任意事件被触发。 * **gesture.pan**: 拖拽/平移。 * **gesture.pinch**: 双指缩放。 * **gesture.tap**: 点击。 * **gesture.dbltap**: 双击。 * **gesture.press**: 长按。 * **gesture.mousewheel**: 鼠标滚轮。 ### 模式差异 (Mode Specifics) 不同的 Mode 对手势有不同的**默认响应**: | 手势 | Panorama (全景) | Mapview (模型) | 说明 | | :--- | :--- | :--- | :--- | | **Pan** | 旋转相机视角 (Look around) | 围绕模型旋转/平移相机 (Orbit/Pan) | | | **Pinch** | 调整 FOV (Zoom in/out) | 调整相机距离 (Distance) | | | **Tap** | **移动点位** (Move to pano) | **切换到全景** (Enter pano) | 若点击到地面/模型,Mapview 下默认无响应,除非点击到点位标记 | | **DblTap** | 动画调整 FOV | 聚焦并拉近视角 (Fly to) | | | **MouseWheel** | 调整 FOV | 调整相机距离 | | ### 事件捕获与阻止 (Event Handling) Five 的事件触发顺序如下: 1. **Emit Event**: Five 触发 `gesture.xxx` 事件。 2. **User Callback**: 开发者注册的监听函数被执行。 3. **Default Behavior**: **如果**开发者没有调用 `event.preventDefault()`,Five 执行默认逻辑(如旋转相机、移动点位)。 因此,如果你想自定义交互(例如:点击不走点,而是弹出一个框),**必须**调用 `event.preventDefault()`。 ## Examples ### 快速上手 (Quick Example) 监听点击事件并打印日志: ```typescript five.on("gesture.tap", (event) => { console.log("点击位置:", event.center.x, event.center.y); // event.center.raycaster 可以用来做射线检测 }); ``` ### 场景交互:点击添加标签球 (Add Label on Click) 这个示例展示了如何通过点击事件在场景中添加一个红色的球体,并阻止 Five 默认的点位移动行为。 ```typescript import * as THREE from "three"; import { Five } from "@realsee/five"; const five = new Five(); five.on("gesture.tap", (event) => { // 1. 阻止默认行为(防止点击地面时 Five 自动走点或切换模式) event.preventDefault(); // 2. 获取射线 const raycaster = event.center.raycaster; // 3. 检测与模型的碰撞 // five.model.intersectRaycaster 是 Five 提供的便捷方法,会自动检测所有可见模型 const intersects = five.model.intersectRaycaster(raycaster); if (intersects.length > 0) { const intersect = intersects[0]; const point = intersect.point; // 碰撞点世界坐标 console.log("点击到了模型,坐标:", point); // 4. 创建一个小球 const geometry = new THREE.SphereGeometry(0.1, 32, 32); const material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); const sphere = new THREE.Mesh(geometry, material); // 5. 设置位置并添加到场景 sphere.position.copy(point); five.scene.add(sphere); // 强制刷新渲染,确保小球立即出现 five.needsRender = true; } else { console.log("未点击到任何模型"); } }); ``` ### 进阶用法:自定义双指缩放范围 ```typescript five.on("gesture.pinch", (event) => { // 获取当前 FOV const currentFov = five.state.fov; // 假设我们限制 FOV 在 80 到 100 之间 // 注意:这只是逻辑演示,Five 内部有自己的 minFov/maxFov 配置, // 这里演示如何完全接管控制权。 if (currentFov < 80 || currentFov > 100) { // 阻止 Five 的默认缩放 event.preventDefault(); console.log("已达到缩放极限"); } }); ``` ## Debugging * **查看事件触发**: 在控制台监听所有手势。 ```typescript ["pan", "tap", "pinch", "press"].forEach(type => { five.on(`gesture.${type}` as any, (e) => console.log(type, e)); }); ``` * **Helper Line**: 如果射线检测不准,可以画出射线辅助线。 ```typescript five.scene.add(new THREE.ArrowHelper(raycaster.ray.direction, raycaster.ray.origin, 10, 0xff0000)); five.needsRender = true; ``` ## Common Pitfalls 1. **忘记 preventDefault**: 如果你发现点击后既生成了小球,相机又自动飞走了,通常是因为没有调用 `event.preventDefault()`。 2. **坐标系混淆**: `event.center.x/y` 是屏幕像素坐标,`event.center.raycaster` 已经处理了屏幕到世界的转换。直接使用 `raycaster` 最安全。 3. **点击穿透**: 如果场景中有 HTML 覆盖层(如按钮),HTML 元素的点击事件可能会冒泡或被 Five 捕获。建议在 HTML 元素上使用 `stopPropagation` 或判断 `event.target`。 ## Related * [Mode (模式)](./mode.md): 了解不同模式下的默认行为。 * [State (状态)](./state.md): 手势最终改变的是 State。 * [Raycast (射线检测)](./raycast.md): 深入了解 `intersectRaycaster` 的工作原理。 --- ```yaml tags: [手势, 点击, 拖拽, 缩放, 长按, 鼠标, 触摸, 交互控制, 自定义交互, gesture, event, interaction, tap, pan, pinch, preventDefault] ```