davimusprime
davimusprime

Reputation: 277

Three.js - How to continue to track mouse outside browser window and/or over other content on the page

I have a full window three.js scene. I have some absolutely positioned buttons on top of the scene and off to the side. If you click and drag the camera spins (weee!) but if you drag over the buttons the spinning stops (boo). It also stops if you drag out of the window. I'm using three.js R76 and OrbitControls.js. Is there an easy way to get the scene to keep listening to the mouse movement while the button is still held down?

http://codepen.io/anon/pen/qZgEBN HTML

<html lang="en">
<head>
    <title>three.js webgl - orbit controls</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <style>
        body {
            color: #000;
            font-family:Monospace;
            font-size:13px;
            text-align:center;
            font-weight: bold;

            background-color: #fff;
            margin: 0px;
            overflow: hidden;
        }

        #info {
            color:#000;
            position: absolute;
            top: 0px; width: 100%;
            padding: 5px;

        }

        a {
            color: red;
        }
    </style>
</head>

<body>
    <div id="container"></div>
    <div id="info">
        <a href="http://threejs.org" target="_blank">three.js</a> - orbit controls example
    </div>

</body>

JS

        var camera, controls, scene, renderer;

        init();
        animate();

        function init() {

            scene = new THREE.Scene();
            scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 );

            renderer = new THREE.WebGLRenderer();
            renderer.setClearColor( scene.fog.color );
            renderer.setPixelRatio( window.devicePixelRatio );
            renderer.setSize( window.innerWidth, window.innerHeight );

            var container = document.getElementById( 'container' );
            container.appendChild( renderer.domElement );

            camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
            camera.position.z = 500;

            controls = new THREE.OrbitControls( camera, renderer.domElement );
            //controls.addEventListener( 'change', render ); // add this only if there is no animation loop (requestAnimationFrame)
            controls.enableDamping = true;
            controls.dampingFactor = 0.25;
            controls.enableZoom = false;

            // world

            var geometry = new THREE.CylinderGeometry( 0, 10, 30, 4, 1 );
            var material =  new THREE.MeshPhongMaterial( { color:0xffffff, shading: THREE.FlatShading } );

            for ( var i = 0; i < 500; i ++ ) {

                var mesh = new THREE.Mesh( geometry, material );
                mesh.position.x = ( Math.random() - 0.5 ) * 1000;
                mesh.position.y = ( Math.random() - 0.5 ) * 1000;
                mesh.position.z = ( Math.random() - 0.5 ) * 1000;
                mesh.updateMatrix();
                mesh.matrixAutoUpdate = false;
                scene.add( mesh );

            }

            // lights

            light = new THREE.DirectionalLight( 0xffffff );
            light.position.set( 1, 1, 1 );
            scene.add( light );

            light = new THREE.DirectionalLight( 0x002288 );
            light.position.set( -1, -1, -1 );
            scene.add( light );

            light = new THREE.AmbientLight( 0x222222 );
            scene.add( light );

            //


            window.addEventListener( 'resize', onWindowResize, false );

        }

        function onWindowResize() {

            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();

            renderer.setSize( window.innerWidth, window.innerHeight );

        }

        function animate() {

            requestAnimationFrame( animate );

            controls.update(); // required if controls.enableDamping = true, or if controls.autoRotate = true

            render();

        }

        function render() {

            renderer.render( scene, camera );

        }

If you click and drag to spin the camera it works so long as you're in the actual scene but if your mouse goes outside of the scene the spinning stops. I'd like it to continue to spin.

Side note: the codepen responds differently from the three.js example page (http://threejs.org/examples/#misc_controls_orbit), while leaving the scene causes the spin to stop, returning (if you're still holding down the mouse button) resumes the spin. On the example page, (using the same code, so it must be something codepen specific) spinning does not resume.

Thought that maybe if I attached the event listener to the window or document instead of the dom element it might help, but no dice.

Changed OrbitControls.js lines 893 - 901 from:

scope.domElement.addEventListener( 'contextmenu', onContextMenu, false );

scope.domElement.addEventListener( 'mousedown', onMouseDown, false );
scope.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
scope.domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox

scope.domElement.addEventListener( 'touchstart', onTouchStart, false );
scope.domElement.addEventListener( 'touchend', onTouchEnd, false );
scope.domElement.addEventListener( 'touchmove', onTouchMove, false );

to:

window.addEventListener( 'contextmenu', onContextMenu, false );

window.addEventListener( 'mousedown', onMouseDown, false );
window.addEventListener( 'mousewheel', onMouseWheel, false );
window.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox

window.addEventListener( 'touchstart', onTouchStart, false );
window.addEventListener( 'touchend', onTouchEnd, false );
window.addEventListener( 'touchmove', onTouchMove, false );

window.addEventListener( 'keydown', onKeyDown, false );

Upvotes: 2

Views: 1176

Answers (1)

Radio
Radio

Reputation: 2853

What you want is line 703 in orbitControls.js (r.76), comment out the mouseout declaration, leave the others. This issue has come up many times. Maybe it ought to be defaulted to commented out or available as an option in orbit control's constructor parameters. Simple to code for a pull request.

Upvotes: 1

Related Questions