2017-10-10 678 views
1

我试图将标签作为元素与position:absolute;放置在THREE.JS场景中。问题在于,当鼠标悬停在其中一个标签上时(例如下面的红色框),触发OrbitControls的事件被标签“停止”,并且不会传播到Renderer。THREE.JS OrbitControls在DOM元素定位在场景上时不起作用

我转载了最小版本的代码来查看问题。

enter image description here

<html lang="en"> 

<head> 
    <meta charset="utf-8"> 
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> 
    <style> 
     body { 
      margin: 0px; 
      overflow: hidden; 
     } 

     #overlay { 
      position: absolute; 
      top: 40%; 
      left: 40%; 
      width: 20%; 
      height: 20%; 
      background-color: #f00; 
      padding: 3%; 
      text-align: center; 
      color: #fff; 
      box-sizing: border-box; 
     } 
    </style> 
</head> 

<body> 
    <div id="container"></div> 

    <!-- This div below stop the OrbitControls events, why? --> 
    <div id="overlay">I am a div with position:absolute</div> 

    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script> 
    <!-- https://raw.githubusercontent.com/mrdoob/three.js/r87/examples/js/controls/OrbitControls.js --> 
    <script src="orbit-controls.js"></script> 
    <script> 
     var container; 
     var camera, scene, renderer; 
     var uniforms, material, mesh; 
     var controls; 
     init(); 
     animate(); 

     function init() { 
      container = document.getElementById('container'); 
      var aspect = window.innerWidth/window.innerHeight; 
      camera = new THREE.PerspectiveCamera(45, aspect, 0.1, 1500); 
      camera.position.set(1, 1, 1); 
      scene = new THREE.Scene(); 
      renderer = new THREE.WebGLRenderer(); 
      container.appendChild(renderer.domElement); 
      renderer.setSize(window.innerWidth, window.innerHeight); 
      controls = new THREE.OrbitControls(this.camera, this.renderer.domElement); 

      var geometry = new THREE.BoxGeometry(1, 1, 1); 
      var material = new THREE.MeshBasicMaterial({ 
       color: 0x00ff00 
      }); 
      var cube = new THREE.Mesh(geometry, material); 

      scene.add(cube); 
     } 

     function animate() { 
      requestAnimationFrame(animate); 
      render(); 
     } 

     function render() { 
      renderer.render(scene, camera); 
     } 
    </script> 
</body> 

</html> 

下面是一个类似的项目,其中的标签并不能阻止事件的传播,使相机可以按照鼠标交互的链接。但是,我还没有找到什么使这个例子工作,我的不是。 http://armsglobe.chromeexperiments.com

该怎么做让OrbitControls仍然在<div>标签后面工作?

+1

试试这个:'控制=新三。 OrbitControls(this.camera);'。默认情况下,'domElement'将会是'document' – prisoner849

+0

Thanks @ prisoner849!它解决了这个问题。你想写答案还是应该这样做? – Ben

+2

您可能希望将'pointer-events:none;'添加到覆盖元素的CSS中,这也将解决此问题 –

回答

1

要评论总结答案:

如果你不需要从覆盖任何鼠标事件,这是最简单的,只是禁用事件处理通过CSS:

<div class="overlay" style="pointer-events: none">...</div> 

你也可以使用共同的父元素为事件处理:

<div class="parent" style="position:relative"> 
    <canvas ... /> <!-- this is the canvas from renderer.domElement --> 
    <div class="overlay"></div> 
</div> 

和用于控制

const controls = new THREE.OrbitControls(camera, document.querySelector('.parent')); 

这样,所有到达父级的鼠标事件(包括来自叠加层的事件)都将由控件处理(其中一个特例是处理根级别的所有事件,方法是省略dom元素或为OrbitControls构造函数指定document.documentElement)。

如果要处理来自覆盖某些事件,比如点击例如,可以防止它们被转发到使用stopPropagation()轨道的控件:

overlayEl.addEventListener('click', event => { 
    event.stopPropagation(); 

    // handle event 
}); 
相关问题