admin管理员组

文章数量:1317131

I'm trying to place labels as element with position:absolute; over a THREE.JS scene. The problem is that when the mouse is over one of the labels (the red box in the exemple below), the events triggering OrbitControls are "stopped" by the labels and do not propagate to the Renderer.

I've reproduced a minimal version of code to see the problem.

<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=".js/87/three.min.js"></script>
    <!-- .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>

Here is a link to a similar project where the labels doesn't stop the propagation of the event so that the camera can follow the mouse interaction. However I have not found what makes this exemple work and mine not.

What to do so that the OrbitControls still works behind the <div> labels ?

I'm trying to place labels as element with position:absolute; over a THREE.JS scene. The problem is that when the mouse is over one of the labels (the red box in the exemple below), the events triggering OrbitControls are "stopped" by the labels and do not propagate to the Renderer.

I've reproduced a minimal version of code to see the problem.

<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./ajax/libs/three.js/87/three.min.js"></script>
    <!-- https://raw.githubusercontent./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>

Here is a link to a similar project where the labels doesn't stop the propagation of the event so that the camera can follow the mouse interaction. However I have not found what makes this exemple work and mine not. http://armsglobe.chromeexperiments.

What to do so that the OrbitControls still works behind the <div> labels ?

Share Improve this question asked Oct 10, 2017 at 12:46 BenBen 68410 silver badges22 bronze badges 5
  • 1 Try this: controls = new THREE.OrbitControls(this.camera);. By default, domElement will be document – prisoner849 Commented Oct 10, 2017 at 12:51
  • Thanks @prisoner849! It fixes the problem. You wanna write the answer or should I do it ? – Ben Commented Oct 10, 2017 at 12:56
  • 2 you might want to add pointer-events: none; to the css of the overlay-element, that would fix the issue as well – Martin Schuhfuß Commented Oct 10, 2017 at 13:00
  • Event better solution @MartinSchuhfuß. Changing the domElement of the renderer fixes the overlay problem but causes other issues with the camera linked to OrbitControls in my project. The pointer-events: none; works best. Just need to be careful about browser patibility. – Ben Commented Oct 10, 2017 at 13:38
  • @MartinSchuhfuß any chance to have a similar solution but allowing for "click" event on labels? – Ben Commented Oct 10, 2017 at 20:52
Add a ment  | 

2 Answers 2

Reset to default 6

To summarize answers from ments:

If you don't need any mouse-events from the overlays, it is easiest to just disable event-handling via css:

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

You can also use a mon parent-element for event-handling:

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

and for the controls

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

this way all mouse-events reaching the parent (which includes events from the overlays) will be handled by the controls (a special case of this is handling all events at the root-level, by omitting the dom-element (or specifying document.documentElement) for the OrbitControls constructor).

If you want to handle certain events from the overlays, like click for instance, you can prevent them to get forwarded to the orbit-controls using stopPropagation():

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

  // handle event
});

If you want to apply orbit controls on the background scene you can do this:

const controls = new orbitControls.OrbitControls(camera, document.body);

本文标签: javascriptTHREEJS OrbitControls not working when DOM Element is positioned over the sceneStack Overflow