2017-10-10 1 views
1

Ich versuche, Etiketten als Element mit position:absolute; über eine THREE.JS Szene zu platzieren. Das Problem ist, dass die Ereignisse, die OrbitControls auslösen, durch die Beschriftungen "gestoppt" werden und nicht an den Renderer weitergegeben werden, wenn sich die Maus über einer der Beschriftungen befindet (im Beispiel unten die rote Box).THREE.JS OrbitControls funktioniert nicht wenn DOM Element über der Szene positioniert ist

Ich habe eine minimale Version des Codes reproduziert, um das Problem zu sehen.

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> 

Hier ist ein Link zu einem ähnlichen Projekt, bei dem die Etiketten nicht die Ausbreitung des Ereignisses nicht zu stoppen, so dass die Kamera die Maus Interaktion folgen kann. Ich habe jedoch nicht gefunden, was dieses Beispiel funktioniert und meins nicht. http://armsglobe.chromeexperiments.com

Was tun, damit die OrbitControls immer noch hinter den <div> Etiketten funktioniert?

+1

Try this: 'Kontrollen = new THREE. OrbitControls (this.camera); '. Standardmäßig ist 'domElement'' Dokument' – prisoner849

+0

Danke @ Häftling849! Es behebt das Problem. Willst du die Antwort schreiben oder soll ich es tun? – Ben

+2

möchten Sie 'pointer-events: none;' zur CSS des overlay-Elements hinzufügen, das würde das Problem auch beheben –

Antwort

1

Um Antworten Kommentare zusammenfassen:

Wenn Sie von dem Overlays keine Maus-Ereignisse benötigen, ist es am einfachsten, nur deaktivieren Event-Handling via CSS:

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

Sie können auch verwenden, um einen gemeinsamen Eltern-Element für die Ereignisbehandlungs:

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

und für die Kontrollen

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

So werden alle Mausereignisse, die den Elternknoten erreichen (der Ereignisse aus den Überlagerungen enthält), von den Steuerelementen gehandhabt (ein Spezialfall ist die Behandlung aller Ereignisse auf der Stammebene durch Weglassen des dom-Elements oder Spezifizieren document.documentElement) für den OrbitControls-Konstruktor).

Wenn Sie bestimmte Ereignisse aus den Overlays zu handhaben wollen, wie Klick zum Beispiel, Sie können sie verhindern, dass der Orbit-Kontrollen leitet werden mit stopPropagation():

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

    // handle event 
}); 
Verwandte Themen