为什么无法悬停和点击Threejs变换工具?代码有什么遗漏?
代码遗漏问题及修复方案
核心遗漏点
- 缺少
pointerdown、pointerup事件的绑定:THREE.TransformControls仅靠mousemove无法响应点击、拖拽操作,必须把按下、抬起事件也传入控件处理 - 未校准鼠标事件坐标:直接传入原生event会导致坐标偏移,需要将鼠标坐标转换为相对于canvas元素的本地坐标
isDragging状态未同步更新:现有代码判断了isDragging状态,但没有在按下/抬起事件中修改该状态,导致拖拽逻辑无法触发- 未屏蔽Viewer默认交互事件:Forge Viewer自带的鼠标旋转、平移逻辑会优先拦截事件,导致变换控件收不到交互信号
- 重复绑定
change事件:每次调用onItemSelected时都会新增一次change事件监听,会导致回调函数重复执行 - 可选检查:确认
createTransformMesh返回的THREE.Mesh是有效可渲染对象,如果网格本身不可见、没有材质,也会导致变换控件无法命中
修复代码示例
// 激活工具的时候新增事件绑定、禁用Viewer默认操作 activateTheTransformTool() { let bbox = this.viewer.model.getBoundingBox(); this.viewer.impl.createOverlayScene("Dotty.Viewing.Tool.TransformTool"); this.transformControlTx = new THREE.TransformControls( this.viewer.impl.camera, this.viewer.impl.canvas, "translate" ); this.transformControlTx.setSize(bbox.getBoundingSphere().radius * 5); this.transformControlTx.visible = false; this.viewer.impl.addOverlay( "Dotty.Viewing.Tool.TransformTool", this.transformControlTx ); this.transformMesh = this.createTransformMesh(); this.transformControlTx.attach(this.transformMesh); // 新增:绑定pointerdown、pointerup事件监听 this.viewer.impl.canvas.addEventListener('pointerdown', this.handlePointerDown.bind(this)); this.viewer.impl.canvas.addEventListener('pointerup', this.handlePointerUp.bind(this)); // 新增:禁用Viewer默认交互,避免事件被拦截 this.viewer.setNavigationLocked(true); // 新增:只绑定一次change事件 this.transformControlTx.addEventListener("change", this.onTxChange.bind(this)); this.onItemSelected(); } // 新增:处理鼠标按下事件 handlePointerDown(event) { if (!this.transformControlTx) return; // 转换为canvas本地坐标 const rect = this.viewer.impl.canvas.getBoundingClientRect(); event.offsetX = event.clientX - rect.left; event.offsetY = event.clientY - rect.top; if (this.transformControlTx.onPointerDown(event)) { this.isDragging = true; return true; } } // 新增:处理鼠标抬起事件 handlePointerUp(event) { if (!this.transformControlTx) return; const rect = this.viewer.impl.canvas.getBoundingClientRect(); event.offsetX = event.clientX - rect.left; event.offsetY = event.clientY - rect.top; this.transformControlTx.onPointerUp(event); this.isDragging = false; } handleMouseMove(event) { if (this.transformControlTx) { // 新增:校准坐标 const rect = this.viewer.impl.canvas.getBoundingClientRect(); event.offsetX = event.clientX - rect.left; event.offsetY = event.clientY - rect.top; if (this.isDragging) { console.log(this.transformControlTx); if (this.transformControlTx.onPointerMove(event)) { return true; } return false; } if (this.transformControlTx.onPointerHover(event)) return true; } } onTxChange() { console.log("onTx change"); this.viewer.impl.sceneUpdated(true); } onItemSelected() { if (this.hitPoint) { this.transformControlTx.visible = true; this.transformControlTx.setPosition(this.hitPoint); this.hitPoint = null; } else { this.transformControlTx.visible = false; } } // 新增:工具销毁时清理事件、恢复Viewer交互 destoryTransformTool() { this.viewer.impl.canvas.removeEventListener('pointerdown', this.handlePointerDown.bind(this)); this.viewer.impl.canvas.removeEventListener('pointerup', this.handlePointerUp.bind(this)); this.viewer.setNavigationLocked(false); this.transformControlTx.removeEventListener("change", this.onTxChange.bind(this)); this.viewer.impl.removeOverlay("Dotty.Viewing.Tool.TransformTool", this.transformControlTx); }
内容的提问来源于stack exchange,提问作者surya kumara
相关产品推荐
相关产品推荐

