| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 | /** * @author Eberhard Graether / http://egraether.com/ * @author Mark Lundin 	/ http://mark-lundin.com */THREE.TrackballControls = function ( object, domElement ) {	var _this = this;	var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 };	this.object = object;	this.domElement = ( domElement !== undefined ) ? domElement : document;	// API	this.enabled = true;	this.screen = { left: 0, top: 0, width: 0, height: 0 };	this.rotateSpeed = 1.0;	this.zoomSpeed = 1.2;	this.panSpeed = 0.3;	this.noRotate = false;	this.noZoom = false;	this.noPan = false;	this.noRoll = false;	this.staticMoving = false;	this.dynamicDampingFactor = 0.2;	this.minDistance = 0;	this.maxDistance = Infinity;	this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];	// internals	this.target = new THREE.Vector3();	var EPS = 0.000001;	var lastPosition = new THREE.Vector3();	var _state = STATE.NONE,	_prevState = STATE.NONE,	_eye = new THREE.Vector3(),	_rotateStart = new THREE.Vector3(),	_rotateEnd = new THREE.Vector3(),	_zoomStart = new THREE.Vector2(),	_zoomEnd = new THREE.Vector2(),	_touchZoomDistanceStart = 0,	_touchZoomDistanceEnd = 0,	_panStart = new THREE.Vector2(),	_panEnd = new THREE.Vector2();	// for reset	this.target0 = this.target.clone();	this.position0 = this.object.position.clone();	this.up0 = this.object.up.clone();	// events	var changeEvent = { type: 'change' };	var startEvent = { type: 'start'};	var endEvent = { type: 'end'};	// methods	this.handleResize = function () {		if ( this.domElement === document ) {			this.screen.left = 0;			this.screen.top = 0;			this.screen.width = window.innerWidth;			this.screen.height = window.innerHeight;		} else {			var box = this.domElement.getBoundingClientRect();			// adjustments come from similar code in the jquery offset() function			var d = this.domElement.ownerDocument.documentElement;			this.screen.left = box.left + window.pageXOffset - d.clientLeft;			this.screen.top = box.top + window.pageYOffset - d.clientTop;			this.screen.width = box.width;			this.screen.height = box.height;		}	};	this.handleEvent = function ( event ) {		if ( typeof this[ event.type ] == 'function' ) {			this[ event.type ]( event );		}	};	var getMouseOnScreen = ( function () {		var vector = new THREE.Vector2();		return function ( pageX, pageY ) {			vector.set(				( pageX - _this.screen.left ) / _this.screen.width,				( pageY - _this.screen.top ) / _this.screen.height			);			return vector;		};	}() );	var getMouseProjectionOnBall = ( function () {		var vector = new THREE.Vector3();		var objectUp = new THREE.Vector3();		var mouseOnBall = new THREE.Vector3();		return function ( pageX, pageY ) {			mouseOnBall.set(				( pageX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5),				( _this.screen.height * 0.5 + _this.screen.top - pageY ) / (_this.screen.height*.5),				0.0			);			var length = mouseOnBall.length();			if ( _this.noRoll ) {				if ( length < Math.SQRT1_2 ) {					mouseOnBall.z = Math.sqrt( 1.0 - length*length );				} else {					mouseOnBall.z = .5 / length;									}			} else if ( length > 1.0 ) {				mouseOnBall.normalize();			} else {				mouseOnBall.z = Math.sqrt( 1.0 - length * length );			}			_eye.copy( _this.object.position ).sub( _this.target );			vector.copy( _this.object.up ).setLength( mouseOnBall.y )			vector.add( objectUp.copy( _this.object.up ).cross( _eye ).setLength( mouseOnBall.x ) );			vector.add( _eye.setLength( mouseOnBall.z ) );			return vector;		};	}() );	this.rotateCamera = (function(){		var axis = new THREE.Vector3(),			quaternion = new THREE.Quaternion();		return function () {			var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );			if ( angle ) {				axis.crossVectors( _rotateStart, _rotateEnd ).normalize();				angle *= _this.rotateSpeed;				quaternion.setFromAxisAngle( axis, -angle );				_eye.applyQuaternion( quaternion );				_this.object.up.applyQuaternion( quaternion );				_rotateEnd.applyQuaternion( quaternion );				if ( _this.staticMoving ) {					_rotateStart.copy( _rotateEnd );				} else {					quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) );					_rotateStart.applyQuaternion( quaternion );				}			}		}	}());	this.zoomCamera = function () {		if ( _state === STATE.TOUCH_ZOOM_PAN ) {			var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;			_touchZoomDistanceStart = _touchZoomDistanceEnd;			_eye.multiplyScalar( factor );		} else {			var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;			if ( factor !== 1.0 && factor > 0.0 ) {				_eye.multiplyScalar( factor );				if ( _this.staticMoving ) {					_zoomStart.copy( _zoomEnd );				} else {					_zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;				}			}		}	};	this.panCamera = (function(){		var mouseChange = new THREE.Vector2(),			objectUp = new THREE.Vector3(),			pan = new THREE.Vector3();		return function () {			mouseChange.copy( _panEnd ).sub( _panStart );			if ( mouseChange.lengthSq() ) {				mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );				pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x );				pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) );				_this.object.position.add( pan );				_this.target.add( pan );				if ( _this.staticMoving ) {					_panStart.copy( _panEnd );				} else {					_panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );				}			}		}	}());	this.checkDistances = function () {		if ( !_this.noZoom || !_this.noPan ) {			if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) {				_this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) );			}			if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) {				_this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) );			}		}	};	this.update = function () {		_eye.subVectors( _this.object.position, _this.target );		if ( !_this.noRotate ) {			_this.rotateCamera();		}		if ( !_this.noZoom ) {			_this.zoomCamera();		}		if ( !_this.noPan ) {			_this.panCamera();		}		_this.object.position.addVectors( _this.target, _eye );		_this.checkDistances();		_this.object.lookAt( _this.target );		if ( lastPosition.distanceToSquared( _this.object.position ) > EPS ) {			_this.dispatchEvent( changeEvent );			lastPosition.copy( _this.object.position );		}	};	this.reset = function () {		_state = STATE.NONE;		_prevState = STATE.NONE;		_this.target.copy( _this.target0 );		_this.object.position.copy( _this.position0 );		_this.object.up.copy( _this.up0 );		_eye.subVectors( _this.object.position, _this.target );		_this.object.lookAt( _this.target );		_this.dispatchEvent( changeEvent );		lastPosition.copy( _this.object.position );	};	// listeners	function keydown( event ) {		if ( _this.enabled === false ) return;		window.removeEventListener( 'keydown', keydown );		_prevState = _state;		if ( _state !== STATE.NONE ) {			return;		} else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) {			_state = STATE.ROTATE;		} else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) {			_state = STATE.ZOOM;		} else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) {			_state = STATE.PAN;		}	}	function keyup( event ) {		if ( _this.enabled === false ) return;		_state = _prevState;		window.addEventListener( 'keydown', keydown, false );	}	function mousedown( event ) {		if ( _this.enabled === false ) return;		event.preventDefault();		event.stopPropagation();		if ( _state === STATE.NONE ) {			_state = event.button;		}		if ( _state === STATE.ROTATE && !_this.noRotate ) {			_rotateStart.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) );			_rotateEnd.copy( _rotateStart );		} else if ( _state === STATE.ZOOM && !_this.noZoom ) {			_zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );			_zoomEnd.copy(_zoomStart);		} else if ( _state === STATE.PAN && !_this.noPan ) {			_panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );			_panEnd.copy(_panStart)		}		// bai//		document.addEventListener( 'mousemove', mousemove, false );//		document.addEventListener( 'mouseup', mouseup, false );		_this.dispatchEvent( startEvent );	}	function mousemove( event ) {		if ( _this.enabled === false ) return;		event.preventDefault();		event.stopPropagation();		if ( _state === STATE.ROTATE && !_this.noRotate ) {			_rotateEnd.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) );		} else if ( _state === STATE.ZOOM && !_this.noZoom ) {						_zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );		} else if ( _state === STATE.PAN && !_this.noPan ) {			//把右键位移关掉了//			_panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );		}	}	function mouseup( event ) {		if ( _this.enabled === false ) return;		event.preventDefault();		event.stopPropagation();		_state = STATE.NONE;		document.removeEventListener( 'mousemove', mousemove );		document.removeEventListener( 'mouseup', mouseup );		_this.dispatchEvent( endEvent );	}	function mousewheel( event ) {		if ( _this.enabled === false ) return;		event.preventDefault();		event.stopPropagation();		var delta = 0;		if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9			delta = event.wheelDelta / 40;		} else if ( event.detail ) { // Firefox			delta = - event.detail / 3;		}		_zoomStart.y += delta * 0.01;		_this.dispatchEvent( startEvent );		_this.dispatchEvent( endEvent );	}	function touchstart( event ) {		if ( _this.enabled === false ) return;		switch ( event.touches.length ) {			case 1:				_state = STATE.TOUCH_ROTATE;				_rotateStart.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );				_rotateEnd.copy( _rotateStart );				break;			case 2:				_state = STATE.TOUCH_ZOOM_PAN;				var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;				var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;				_touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );				var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;				var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;				_panStart.copy( getMouseOnScreen( x, y ) );				_panEnd.copy( _panStart );				break;			default:				_state = STATE.NONE;		}		_this.dispatchEvent( startEvent );	}	function touchmove( event ) {		if ( _this.enabled === false ) return;		event.preventDefault();		event.stopPropagation();		switch ( event.touches.length ) {			case 1:				_rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );				break;			case 2:				var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;				var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;				_touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy );				var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;				var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;				_panEnd.copy( getMouseOnScreen( x, y ) );				break;			default:				_state = STATE.NONE;		}	}	function touchend( event ) {		if ( _this.enabled === false ) return;		switch ( event.touches.length ) {			case 1:				_rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );				_rotateStart.copy( _rotateEnd );				break;			case 2:				_touchZoomDistanceStart = _touchZoomDistanceEnd = 0;				var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;				var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;				_panEnd.copy( getMouseOnScreen( x, y ) );				_panStart.copy( _panEnd );				break;		}		_state = STATE.NONE;		_this.dispatchEvent( endEvent );	}	this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );	this.domElement.addEventListener( 'mousedown', mousedown, false );	// bai	// this.domElement.addEventListener( 'mousewheel', mousewheel, false );	// this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox	this.domElement.addEventListener( 'touchstart', touchstart, false );	this.domElement.addEventListener( 'touchend', touchend, false );	this.domElement.addEventListener( 'touchmove', touchmove, false );//	window.addEventListener( 'keydown', keydown, false );//	window.addEventListener( 'keyup', keyup, false );	this.handleResize();	// force an update at start	this.update();};THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
 |