You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么无法悬停和点击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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 01:27:01