/* * @author zz85 / https://github.com/zz85 * @author mrdoob / http://mrdoob.com * Running this will allow you to drag three.js objects around the screen. */ THREE.DragControls = function ( _objects, _camera, _domElement ) { if ( _objects instanceof THREE.Camera ) { console.warn( 'THREE.DragControls: Constructor now expects ( objects, camera, domElement )' ); var temp = _objects; _objects = _camera; _camera = temp; } var _plane = new THREE.Plane(); var _raycaster = new THREE.Raycaster(); var _mouse = new THREE.Vector2(); var _offset = new THREE.Vector3(); var _intersection = new THREE.Vector3(); var _selected = null, _hovered = null; // var scope = this; function activate() { _domElement.addEventListener( 'mousemove', onDocumentMouseMove, false ); _domElement.addEventListener( 'mousedown', onDocumentMouseDown, false ); _domElement.addEventListener( 'mouseup', onDocumentMouseCancel, false ); _domElement.addEventListener( 'mouseleave', onDocumentMouseCancel, false ); _domElement.addEventListener( 'touchmove', onDocumentTouchMove, false ); _domElement.addEventListener( 'touchstart', onDocumentTouchStart, false ); _domElement.addEventListener( 'touchend', onDocumentTouchEnd, false ); } function deactivate() { _domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false ); _domElement.removeEventListener( 'mousedown', onDocumentMouseDown, false ); _domElement.removeEventListener( 'mouseup', onDocumentMouseCancel, false ); _domElement.removeEventListener( 'mouseleave', onDocumentMouseCancel, false ); _domElement.removeEventListener( 'touchmove', onDocumentTouchMove, false ); _domElement.removeEventListener( 'touchstart', onDocumentTouchStart, false ); _domElement.removeEventListener( 'touchend', onDocumentTouchEnd, false ); } function dispose() { deactivate(); } function onDocumentMouseMove( event ) { event.preventDefault(); var rect = _domElement.getBoundingClientRect(); _mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1; _mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1; _raycaster.setFromCamera( _mouse, _camera ); if ( _selected && scope.enabled ) { if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { _selected.position.copy( _intersection.sub( _offset ) ); } scope.dispatchEvent( { type: 'drag', object: _selected } ); return; } _raycaster.setFromCamera( _mouse, _camera ); var intersects = _raycaster.intersectObjects( _objects ); if ( intersects.length > 0 ) { var object = intersects[ 0 ].object; _plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), object.position ); if ( _hovered !== object ) { scope.dispatchEvent( { type: 'hoveron', object: object } ); _domElement.style.cursor = 'pointer'; _hovered = object; } } else { if ( _hovered !== null ) { scope.dispatchEvent( { type: 'hoveroff', object: _hovered } ); _domElement.style.cursor = 'auto'; _hovered = null; } } } function onDocumentMouseDown( event ) { event.preventDefault(); _raycaster.setFromCamera( _mouse, _camera ); var intersects = _raycaster.intersectObjects( _objects ); if ( intersects.length > 0 ) { _selected = intersects[ 0 ].object; if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { _offset.copy( _intersection ).sub( _selected.position ); } _domElement.style.cursor = 'move'; scope.dispatchEvent( { type: 'dragstart', object: _selected } ); } } function onDocumentMouseCancel( event ) { event.preventDefault(); if ( _selected ) { scope.dispatchEvent( { type: 'dragend', object: _selected } ); _selected = null; } _domElement.style.cursor = 'auto'; } function onDocumentTouchMove( event ) { event.preventDefault(); event = event.changedTouches[ 0 ]; var rect = _domElement.getBoundingClientRect(); _mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1; _mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1; _raycaster.setFromCamera( _mouse, _camera ); if ( _selected && scope.enabled ) { if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { _selected.position.copy( _intersection.sub( _offset ) ); } scope.dispatchEvent( { type: 'drag', object: _selected } ); return; } } function onDocumentTouchStart( event ) { event.preventDefault(); event = event.changedTouches[ 0 ]; var rect = _domElement.getBoundingClientRect(); _mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1; _mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1; _raycaster.setFromCamera( _mouse, _camera ); var intersects = _raycaster.intersectObjects( _objects ); if ( intersects.length > 0 ) { _selected = intersects[ 0 ].object; _plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _selected.position ); if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { _offset.copy( _intersection ).sub( _selected.position ); } _domElement.style.cursor = 'move'; scope.dispatchEvent( { type: 'dragstart', object: _selected } ); } } function onDocumentTouchEnd( event ) { event.preventDefault(); if ( _selected ) { scope.dispatchEvent( { type: 'dragend', object: _selected } ); _selected = null; } _domElement.style.cursor = 'auto'; } activate(); // API this.enabled = true; this.activate = activate; this.deactivate = deactivate; this.dispose = dispose; // Backward compatibility this.setObjects = function () { console.error( 'THREE.DragControls: setObjects() has been removed.' ); }; this.on = function ( type, listener ) { console.warn( 'THREE.DragControls: on() has been deprecated. Use addEventListener() instead.' ); scope.addEventListener( type, listener ); }; this.off = function ( type, listener ) { console.warn( 'THREE.DragControls: off() has been deprecated. Use removeEventListener() instead.' ); scope.removeEventListener( type, listener ); }; this.notify = function ( type ) { console.error( 'THREE.DragControls: notify() has been deprecated. Use dispatchEvent() instead.' ); scope.dispatchEvent( { type: type } ); }; }; THREE.DragControls.prototype = Object.create( THREE.EventDispatcher.prototype ); THREE.DragControls.prototype.constructor = THREE.DragControls;