diff --git a/src/extras/cameras/TrackballCamera.js b/src/extras/cameras/TrackballCamera.js new file mode 100644 index 00000000..db01c142 --- /dev/null +++ b/src/extras/cameras/TrackballCamera.js @@ -0,0 +1,199 @@ +/** + * @author Eberhard Gräther / http://egraether.com/ + + * parameters = { + * fov: , + * aspect: , + * near: , + * far: , + * target: , + + * radius: , + + * zoomSpeed: , + * panSpeed: , + + * noZoom: , + * noPan: , + + * domElement: , + * } + */ + +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.domElement = document; + + if ( parameters ) { + + if ( parameters.radius !== undefined ) this.radius = parameters.radius; + + if ( parameters.zoomSpeed !== undefined ) this.zoomSpeed = parameters.zoomSpeed; + if ( parameters.panSpeed !== undefined ) this.panSpeed = parameters.panSpeed; + + if ( parameters.noZoom !== undefined ) this.noZoom = parameters.noZoom; + if ( parameters.noPan !== undefined ) this.noPan = parameters.noPan; + + if ( parameters.domElement !== undefined ) this.domElement = parameters.domElement; + + } + + this.useTarget = true; + + this.mouseDragOn = false; + + this.screen = this.getScreenDimensions(); + + this.start = new THREE.Vector3(); + this.end = new THREE.Vector3(); + + function bind( scope, fn ) { + + return function () { + + fn.apply( scope, arguments ); + + }; + + }; + + 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 ); + + window.addEventListener( 'keydown', bind( this, this.keydown ), false ); + window.addEventListener( 'keyup', bind( this, 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.handleEvent = function ( event ) { + + if ( typeof this[ event.type ] == 'function' ) { + + this[ event.type ]( event ); + + } + +}; + +THREE.TrackballCamera.prototype.keydown = function( event ) { + + + +}; + +THREE.TrackballCamera.prototype.keyup = function( event ) { + + + +}; + +THREE.TrackballCamera.prototype.mousedown = function(event) { + + event.preventDefault(); + event.stopPropagation(); + + this.mouseDragOn = true; + + this.start = this.getMouseProjectionOnBall( event.clientX, event.clientY ); + +}; + +THREE.TrackballCamera.prototype.mousemove = function( event ) { + + if ( this.mouseDragOn ) { + + this.end = this.getMouseProjectionOnBall( event.clientX, event.clientY ); + + var angle = Math.acos( this.start.dot( this.end ) / this.start.length() / this.end.length() ); + + if ( angle ) { + + var axis = (new THREE.Vector3()).cross( this.end, this.start ).normalize(), + quaternion = new THREE.Quaternion(); + + quaternion.setFromAxisAngle( axis, angle ); + + quaternion.multiplyVector3( this.position ); + quaternion.multiplyVector3( this.up ); + + } + + } + +}; + +THREE.TrackballCamera.prototype.mouseup = function( event ) { + + event.preventDefault(); + event.stopPropagation(); + + this.mouseDragOn = false; + +}; + +THREE.TrackballCamera.prototype.getScreenDimensions = function() { + + if ( this.domElement != document ) { + + return { + width : this.domElement.offsetWidth, + height : this.domElement.offsetHeight, + offsetLeft : this.domElement.offsetLeft, + offsetTop : this.domElement.offsetTop + }; + + } else { + + return { + width : window.innerWidth, + height : window.innerHeight, + offsetLeft : 0, + offsetTop : 0 + }; + + } + +}; + +THREE.TrackballCamera.prototype.getMouseProjectionOnBall = function( clientX, clientY ) { + + var mouse = 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 + ); + + var length = mouse.length(); + + if ( length > 1.0 ) { + + mouse.divideScalar( length ); + + } else { + + mouse.z = Math.sqrt( 1.0 - length * length ); + + } + + var projection = this.up.clone().setLength( mouse.y ); + projection.addSelf( this.up.clone().crossSelf( this.position ).setLength( mouse.x ) ); + projection.addSelf( this.position.clone().setLength( mouse.z ) ); + + return projection; + +};