在 A-Frame 中动态创建的添加事件侦听器 工作示例

如何解决在 A-Frame 中动态创建的添加事件侦听器 工作示例

我创建了一个类,可帮助我使用 A-Frame 显示 3D 模型。在这个类中,有一些在运行时创建的球体插入到场景中。我正在尝试添加一个事件侦听器(单击这些球体时我必须显示一条消息)

代码如下:

export class AFrameObjViewNavMarkProvider implements Provider {
  // Class Variables...

  // Constructor...

  // ----- Method ----- \\
  public setPointerService(pointeRSService: PointeRSService) {
    // method code...
  }

  public setPointerTrigger(value: boolean) {
    // method code...
  }

  // ----- Handlers ----- \\

  // click Handler
  clickHandler(event,model: Model){
    // code for saving into backend...

    // save pointer into the back-end
    this.pointeRSService.loadPointer(newPointer).subscribe((pointer) => {
      this.showPointer(pointer);
    });
  }

  showPointer(pointer: Pointer){
    // create a string containing the position
    let pointString = pointer.position[0].toFixed(3) + " "
      + pointer.position[1].toFixed(3) + " "
      + pointer.position[2].toFixed(3);

    // compute the Box that contains the model
    let modelRef = <any>document.getElementById("model");
    const Box = new THREE.Box3().setFromObject(modelRef.object3D);
    const BoxSizes = Box.getSize(new THREE.Vector3());

    // compute the min size of the Box (x,y,z)
    // it will be used to set pointer radius
    let minBoxSize = Math.min(BoxSizes.x,BoxSizes.y,BoxSizes.z);
    let radius = minBoxSize / 30;

    let scene = document.getElementById("scene");
    let marker = document.createElement("a-sphere");
    scene.appendChild(marker);

    marker.setAttribute("class","pointer");
    marker.setAttribute("radius",`${radius}`);
    marker.setAttribute("color","#CC0000");
    marker.setAttribute("position",pointString);
  }

  // ----- Visual Methods ----- \\
  renderModel(model: Model) {
    // position-setter is used to set the model position according to its size
    AFrameUtils.registerPositionSetter();

    // reference to the provider itself
    let caller: any = this;

    function clickHandler(event) {
      caller.clickHandler(event,model);
    }

    // sets the behavIoUr in response to a click event
    AFRAME.registerComponent('click-handler',{
      // init also calls update
      init: function () {
        let mouseDownTime: number = null;
        let mouseDownPoint: any = null;

        this.el.addEventListener('mousedown',event => {
          mouseDownTime = new Date().getTime();
          mouseDownPoint = event.detail.intersection.point;
        });

        this.el.addEventListener('mouseup',event => {
          if(!event.detail.intersection) return;

          let mouseUpTime = new Date().getTime();
          let mouseUpPoint = event.detail.intersection.point;

          // compute the differences (time and position) between press and release
          let timeDiff = mouseUpTime - mouseDownTime;

          // if press and release occur within 185 ms
          //  we consider the event as a click
          if (timeDiff <= 185 && JSON.stringify(mouseDownPoint) === JSON.stringify(mouseUpPoint)) {
            clickHandler(event);
          }
        });
      }
    });

    let renderingArea = document.getElementById('rendering-area');
    renderingArea.innerHTML = `
      <a-scene embedded id="scene" cursor="rayOrigin: mouse" raycaster="objects: .clickable">
        <!-- Assets deFinition -->
        <a-assets>
            <a-asset-item id="object-ref" src="${model.sources[0]}"></a-asset-item>
            <a-asset-item id="material-ref" src="${model.sources[1]}"></a-asset-item>
        </a-assets>

        <!-- Using the asset management system. -->
        <a-obj-model id="model" class="clickable" src="#object-ref" mtl="#material-ref" position-setter click-handler>
        </a-obj-model>

        <!-- Camera -->
        <a-camera id="camera" wasd-controls="fly:true"></a-camera>

        <!-- Environment elements-->
        <a-sky id="sky" color="#000000"></a-sky>
      </a-scene>
    `;

    setTimeout(() => {
      this.pointeRSService.getPointersByModelId(model.id).subscribe(pointers => {
        for(let pointer of pointers){
          this.showPointer(pointer);
        }

        let markers = Array.from(document.getElementsByClassName('pointer'));
        for(let marker of markers){
          marker.addEventListener('click',() => {
            console.log('click on pointer');
          })
        }
      });
    },125);
  }
}

和截图:

enter image description here

首次尝试:我尝试注册一个组件,如下所示:

AFRAME.registerComponent('pointer-handler',{
      init: function(){
        this.el.addEventListener('click',() => {
          console.log('click on pointer');
        });
      }
    });

并在 setAttribute("pointer-handler","") 方法中使用 showPointer

第二次尝试:我尝试将使用 marker.addEventListener 的事件侦听器直接添加showPointer 方法中。

第三次尝试:第三次尝试可以在代码中找到,进入setTimeout的回调。

每次尝试都不行;如果我尝试单击一个球体,则什么也不会发生。但是,如果我打开 A-Frame 检查器,导航到其中一个球体并单击它,则会记录该消息。我怀疑添加了处理程序,但某些原因导致无法检测到点击。

我们将不胜感激。

谢谢!

EDIT:您可以找到存储库 here

解决方法

使用 setAttribute("pointer-handler","") 方法绝对有效,是实现您想要实现的目标的正确方法。

我认为可能是 click 事件导致了问题。我建议您将其替换为 mouseupmousedown 事件。

还要确保您确实可以触发事件 - 您需要将光标连接到相机

工作示例

全屏运行(运行片段后右上角查看整个场景 - 关闭也在右上角)。

您可以通过按左上角的按钮来添加新元素。看看有时会触发点击,有时根本不触发。

let boxCounter = 0;

function createNewElement() {
  let box = document.createElement("a-box");
  boxCounter++;
  box.setAttribute("position","" + boxCounter + " 0 -2");
  box.setAttribute("scale","0.5");
  box.setAttribute("color","red");
  box.setAttribute("click-handler","");
  document.getElementById("scene").appendChild(box);
}
<!DOCTYPE html>
<html>
    <head>
        <script src="https://aframe.io/releases/1.0.0/aframe.min.js"></script>
    </head>
    <body>
      <script>
        AFRAME.registerComponent('click-handler',{
          init: function() {
            this.el.addEventListener('mousedown',(event) => {
              console.log("I was mousedowned!");
              this.el.setAttribute('material','color','green');
            });

            this.el.addEventListener('mouseup',(event) => {
              console.log("I was mouseuped!");
              this.el.setAttribute('material','red');
            });
            
            this.el.addEventListener('click',(event) => {
              console.log("I was clicked!");
              this.el.setAttribute('scale','0.5 0.5 0.5');
            });
          }
        });
      </script>
        <a-scene id="scene">
          <a-entity camera look-controls>
            <a-entity cursor="fuse: true; fuseTimeout: 500;"
                      position="0 0 -1"
                      geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
                      material="color: black; shader: flat">
            </a-entity>
          </a-entity>
          <a-sphere color="red" position="0 0 -2" scale="0.5 0.5 0.5" click-handler></a-sphere>
        </a-scene>
        <button onclick="createNewElement()" style="width: 100px; height: 100px; position: absolute; top: 0; left: 0;" value="toggle"></button>
  </body>
    </body>
</html>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?