From 3fcc39301b5481ace7264861e0fb305c80b1f0ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eberhard=20Gr=C3=A4ther?= Date: Sun, 29 May 2011 07:43:14 +0200 Subject: [PATCH] restructured TrackballCamera, final static moving version --- src/extras/cameras/TrackballCamera.js | 348 ++++++++++++-------------- 1 file changed, 164 insertions(+), 184 deletions(-) diff --git a/src/extras/cameras/TrackballCamera.js b/src/extras/cameras/TrackballCamera.js index 9a969d6e87..3147efa0fa 100644 --- a/src/extras/cameras/TrackballCamera.js +++ b/src/extras/cameras/TrackballCamera.js @@ -9,6 +9,7 @@ * target: , * radius: , + * screen: { width : , height : , offsetLeft : , offsetTop : }, * zoomSpeed: , * panSpeed: , @@ -16,307 +17,286 @@ * noZoom: , * noPan: , - * keys: , // [ rotateKey, zoomKey, panKey ] + * keys: , // [ rotateKey, zoomKey, panKey ], * domElement: , * } */ -// TODO: onWindowResize(); - THREE.TrackballCamera = function ( parameters ) { - THREE.Camera.call( this, parameters.fov, parameters.aspect, parameters.near, parameters.far, parameters.target ); - - this.radius = ( window.innerWidth + window.innerHeight ) / 4; - - this.zoomSpeed = 1.0; - this.panSpeed = 1.0; - - this.noZoom = false; - this.noPan = false; - - this.keys = [ 65, 83, 68 ]; - this.keyPressed = false; + // target.position is modified when panning - this.domElement = document; + parameters = parameters || {}; - if ( parameters ) { - - if ( parameters.radius !== undefined ) this.radius = parameters.radius; + THREE.Camera.call( this, parameters.fov, parameters.aspect, parameters.near, parameters.far, parameters.target ); - if ( parameters.zoomSpeed !== undefined ) this.zoomSpeed = parameters.zoomSpeed; - if ( parameters.panSpeed !== undefined ) this.panSpeed = parameters.panSpeed; + this.domElement = parameters.domElement || document; - if ( parameters.noZoom !== undefined ) this.noZoom = parameters.noZoom; - if ( parameters.noPan !== undefined ) this.noPan = parameters.noPan; + this.screen = parameters.screen || { width : window.innerWidth, height : window.innerHeight, offsetLeft : 0, offsetTop : 0 }; + this.radius = parameters.radius || ( this.screen.width + this.screen.height ) / 4; - if ( parameters.keys !== undefined ) this.keys = parameters.keys; + this.zoomSpeed = parameters.zoomSpeed || 1.5; + this.panSpeed = parameters.panSpeed || 0.3; - if ( parameters.domElement !== undefined ) this.domElement = parameters.domElement; + this.noZoom = parameters.noZoom || false; + this.noPan = parameters.noPan || false; - } + this.keys = parameters.keys || [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; this.useTarget = true; - this.state = this.STATE.NONE; - this.screen = this.getScreenDimensions(); - this.mouse = new THREE.Vector2(); + //internals - this.start = new THREE.Vector3(); - this.end = new THREE.Vector3(); + var _keyPressed = false, - function bind( scope, fn ) { + _state = this.STATE.NONE, + + _mouse = new THREE.Vector2(), + + _start = new THREE.Vector3(), + _end = new THREE.Vector3(); - return function () { - fn.apply( scope, arguments ); + // methods - }; + this.handleEvent = function ( event ) { - }; - - this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); - - this.domElement.addEventListener( 'mousemove', bind( this, this.mousemove ), false ); - this.domElement.addEventListener( 'mousedown', bind( this, this.mousedown ), false ); - this.domElement.addEventListener( 'mouseup', bind( this, this.mouseup ), false ); + if ( typeof this[ event.type ] == 'function' ) { - window.addEventListener( 'keydown', bind( this, this.keydown ), false ); - window.addEventListener( 'keyup', bind( this, this.keyup ), false ); - -}; + this[ event.type ]( event ); -THREE.TrackballCamera.prototype = new THREE.Camera(); -THREE.TrackballCamera.prototype.constructor = THREE.TrackballCamera; -THREE.TrackballCamera.prototype.supr = THREE.Camera.prototype; + } -THREE.TrackballCamera.prototype.STATE = { - NONE : -1, - ROTATE : 0, - ZOOM : 1, - PAN : 2 -}; + }; -THREE.TrackballCamera.prototype.handleEvent = function ( event ) { + this.getMouseOnScreen = function( clientX, clientY ) { - if ( typeof this[ event.type ] == 'function' ) { + return new THREE.Vector2( + ( clientX - this.screen.offsetLeft ) / this.radius * 0.5, + ( clientY - this.screen.offsetTop ) / this.radius * 0.5 + ); - this[ event.type ]( event ); + }; - } + this.getMouseProjectionOnBall = function( clientX, clientY ) { -}; + var mouseOnBall = new THREE.Vector3( + ( clientX - this.screen.width * 0.5 - this.screen.offsetLeft ) / this.radius, + ( this.screen.height * 0.5 + this.screen.offsetTop - clientY ) / this.radius, + 0.0 + ); -THREE.TrackballCamera.prototype.keydown = function( event ) { - - if ( this.state !== this.STATE.NONE ) { + var length = mouseOnBall.length(); - return; + if ( length > 1.0 ) { - } else if ( event.keyCode === this.keys[ this.STATE.ROTATE ] ) { + mouseOnBall.normalize(); - this.state = this.STATE.ROTATE; - this.keyPressed = true; + } else { - } else if ( event.keyCode === this.keys[ this.STATE.ZOOM ] ) { + mouseOnBall.z = Math.sqrt( 1.0 - length * length ); - this.state = this.STATE.ZOOM; - this.keyPressed = true; + } - } else if ( event.keyCode === this.keys[ this.STATE.PAN ] ) { + var projection = this.up.clone().setLength( mouseOnBall.y ); + projection.addSelf( this.up.clone().crossSelf( this.position ).setLength( mouseOnBall.x ) ); + projection.addSelf( this.position.clone().setLength( mouseOnBall.z ) ); - this.state = this.STATE.PAN; - this.keyPressed = true; + return projection; - } + }; -}; + this.rotateCamera = function( clientX, clientY ) { -THREE.TrackballCamera.prototype.keyup = function( event ) { + _end = this.getMouseProjectionOnBall( clientX, clientY ); - if ( this.state !== this.STATE.NONE ) { + var angle = Math.acos( _start.dot( _end ) / _start.length() / _end.length() ); - this.state = this.STATE.NONE; + if ( angle ) { - } + var axis = (new THREE.Vector3()).cross( _end, _start ).normalize(), + quaternion = new THREE.Quaternion(); -}; + quaternion.setFromAxisAngle( axis, angle ); -THREE.TrackballCamera.prototype.mousedown = function(event) { + quaternion.multiplyVector3( this.position ); + quaternion.multiplyVector3( this.up ); - event.preventDefault(); - event.stopPropagation(); + // quaternion.setFromAxisAngle( axis, angle * -0.1 ); + // quaternion.multiplyVector3( _start ); - if ( this.state === this.STATE.NONE ) { + } - this.state = event.button; + }; - if ( this.state === this.STATE.ROTATE ) { + this.zoomCamera = function( clientX, clientY ) { - this.start = this.getMouseProjectionOnBall( event.clientX, event.clientY ); + var newMouse = this.getMouseOnScreen( clientX, clientY ), + eye = this.position.clone().subSelf( this.target.position ), + factor = 1.0 + ( newMouse.y - _mouse.y ) * this.zoomSpeed; - } else { + if ( factor > 0.0 ) { - this.mouse = this.getMouseOnScreen( event.clientX, event.clientY ); + this.position.add( this.target.position, eye.multiplyScalar( factor ) ); + _mouse = newMouse; } - } - -}; + }; -THREE.TrackballCamera.prototype.mousemove = function( event ) { - - if ( this.keyPressed ) { + this.panCamera = function( clientX, clientY ) { - this.start = this.getMouseProjectionOnBall( event.clientX, event.clientY ); - this.mouse = this.getMouseOnScreen( event.clientX, event.clientY ); + var newMouse = this.getMouseOnScreen( clientX, clientY ), + mouseChange = newMouse.clone().subSelf( _mouse ), + factor = this.position.distanceTo( this.target.position ) * this.panSpeed; - this.keyPressed = false; + mouseChange.multiplyScalar( factor ); - } + var pan = this.position.clone().crossSelf( this.up ).setLength( mouseChange.x ); + pan.addSelf( this.up.clone().setLength( mouseChange.y ) ); - if ( this.state === this.STATE.NONE ) { + this.position.addSelf( pan ); + this.target.position.addSelf( pan ); - return; + _mouse = newMouse; - } else if ( this.state === this.STATE.ROTATE ) { + }; + + // this.update = function( parentMatrixWorld, forceUpdate, camera ) { + // + // this.rotateCamera(); + // + // this.supr.update.call( this, parentMatrixWorld, forceUpdate, camera ); + // + // }; - this.rotateCamera( event.clientX, event.clientY ); + // listeners - } else if ( this.state === this.STATE.ZOOM && !this.noZoom ) { + function keydown( event ) { - this.zoomCamera( event.clientX, event.clientY ); + if ( _state !== this.STATE.NONE ) { - } else if ( this.state === this.STATE.PAN && !this.noPan ) { + return; - this.panCamera( event.clientX, event.clientY ); + } else if ( event.keyCode === this.keys[ this.STATE.ROTATE ] ) { - } + _state = this.STATE.ROTATE; + _keyPressed = true; -}; + } else if ( event.keyCode === this.keys[ this.STATE.ZOOM ] ) { -THREE.TrackballCamera.prototype.mouseup = function( event ) { + _state = this.STATE.ZOOM; + _keyPressed = true; - event.preventDefault(); - event.stopPropagation(); + } else if ( event.keyCode === this.keys[ this.STATE.PAN ] ) { - this.state = this.STATE.NONE; + _state = this.STATE.PAN; + _keyPressed = true; -}; + } -THREE.TrackballCamera.prototype.getScreenDimensions = function() { + }; - if ( this.domElement != document ) { + function keyup( event ) { - return { - width : this.domElement.offsetWidth, - height : this.domElement.offsetHeight, - offsetLeft : this.domElement.offsetLeft, - offsetTop : this.domElement.offsetTop - }; + if ( _state !== this.STATE.NONE ) { - } else { + _state = this.STATE.NONE; - return { - width : window.innerWidth, - height : window.innerHeight, - offsetLeft : 0, - offsetTop : 0 - }; + } - } + }; -}; + function mousedown(event) { -THREE.TrackballCamera.prototype.getMouseOnScreen = function( clientX, clientY ) { + event.preventDefault(); + event.stopPropagation(); - return new THREE.Vector2( - ( clientX - this.screen.offsetLeft ) / this.radius * 0.5, - ( clientY - this.screen.offsetTop ) / this.radius * 0.5 - ); + if ( _state === this.STATE.NONE ) { -}; + _state = event.button; -THREE.TrackballCamera.prototype.getMouseProjectionOnBall = function( clientX, clientY ) { + if ( _state === this.STATE.ROTATE ) { - var mouseOnBall = new THREE.Vector3( - ( clientX - this.screen.width * 0.5 - this.screen.offsetLeft ) / this.radius, - ( this.screen.height * 0.5 + this.screen.offsetTop - clientY ) / this.radius, - 0.0 - ); + _start = this.getMouseProjectionOnBall( event.clientX, event.clientY ); - var length = mouseOnBall.length(); + } else { - if ( length > 1.0 ) { + _mouse = this.getMouseOnScreen( event.clientX, event.clientY ); - mouseOnBall.normalize(); + } - } else { + } - mouseOnBall.z = Math.sqrt( 1.0 - length * length ); + }; - } + function mousemove( event ) { - var projection = this.up.clone().setLength( mouseOnBall.y ); - projection.addSelf( this.up.clone().crossSelf( this.position ).setLength( mouseOnBall.x ) ); - projection.addSelf( this.position.clone().setLength( mouseOnBall.z ) ); + if ( _keyPressed ) { - return projection; + _start = this.getMouseProjectionOnBall( event.clientX, event.clientY ); + _mouse = this.getMouseOnScreen( event.clientX, event.clientY ); -}; + _keyPressed = false; -THREE.TrackballCamera.prototype.rotateCamera = function( clientX, clientY ) { + } - this.end = this.getMouseProjectionOnBall( clientX, clientY ); + if ( _state === this.STATE.NONE ) { - var angle = Math.acos( this.start.dot( this.end ) / this.start.length() / this.end.length() ); + return; - if ( angle ) { + } else if ( _state === this.STATE.ROTATE ) { - var axis = (new THREE.Vector3()).cross( this.end, this.start ).normalize(), - quaternion = new THREE.Quaternion(); + // _end = this.getMouseProjectionOnBall( event.clientX, event.clientY ); - quaternion.setFromAxisAngle( axis, angle ); + this.rotateCamera( event.clientX, event.clientY ); - quaternion.multiplyVector3( this.position ); - quaternion.multiplyVector3( this.up ); + } else if ( _state === this.STATE.ZOOM && !this.noZoom ) { - } + this.zoomCamera( event.clientX, event.clientY ); -}; + } else if ( _state === this.STATE.PAN && !this.noPan ) { -THREE.TrackballCamera.prototype.zoomCamera = function( clientX, clientY ) { + this.panCamera( event.clientX, event.clientY ); - var newMouse = this.getMouseOnScreen( clientX, clientY ), - eye = this.position.clone().subSelf( this.target.position ), - factor = 1.0 + ( newMouse.y - this.mouse.y ) * this.zoomSpeed; + } - if ( factor > 0.0 ) { + }; - this.position.add( this.target.position, eye.multiplyScalar( factor ) ); - this.mouse = newMouse; + function mouseup( event ) { - } + event.preventDefault(); + event.stopPropagation(); -}; + _state = this.STATE.NONE; -THREE.TrackballCamera.prototype.panCamera = function( clientX, clientY ) { + }; - var newMouse = this.getMouseOnScreen( clientX, clientY ), - mouseChange = newMouse.clone().subSelf(this.mouse), - factor = this.position.distanceTo( this.target.position ) * this.panSpeed; + function bind( scope, fn ) { + + return function () { + + fn.apply( scope, arguments ); - mouseChange.multiplyScalar( factor ); + }; - var pan = this.position.clone().crossSelf( this.up ).setLength( mouseChange.x ); - pan.addSelf( this.up.clone().setLength( mouseChange.y ) ); + }; + + this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); - this.position.addSelf( pan ); - this.target.position.addSelf( pan ); + this.domElement.addEventListener( 'mousemove', bind( this, mousemove ), false ); + this.domElement.addEventListener( 'mousedown', bind( this, mousedown ), false ); + this.domElement.addEventListener( 'mouseup', bind( this, mouseup ), false ); - this.mouse = newMouse; + window.addEventListener( 'keydown', bind( this, keydown ), false ); + window.addEventListener( 'keyup', bind( this, keyup ), false ); }; + +THREE.TrackballCamera.prototype = new THREE.Camera(); +THREE.TrackballCamera.prototype.constructor = THREE.TrackballCamera; +THREE.TrackballCamera.prototype.supr = THREE.Camera.prototype; + +THREE.TrackballCamera.prototype.STATE = { NONE : -1, ROTATE : 0, ZOOM : 1, PAN : 2 }; -- GitLab