|
@@ -34,6 +34,7 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
// "target" sets the location of focus, where the control orbits around
|
|
|
// and where it pans with respect to.
|
|
|
this.target = new THREE.Vector3();
|
|
|
+
|
|
|
// center is old, deprecated; use "target" instead
|
|
|
this.center = this.target;
|
|
|
|
|
@@ -41,6 +42,7 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
// backwards compatibility
|
|
|
this.noZoom = false;
|
|
|
this.zoomSpeed = 1.0;
|
|
|
+
|
|
|
// Limits to how far you can dolly in and out
|
|
|
this.minDistance = 0;
|
|
|
this.maxDistance = Infinity;
|
|
@@ -64,6 +66,7 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
|
|
|
// Set to true to disable use of the keys
|
|
|
this.noKeys = false;
|
|
|
+
|
|
|
// The four arrow keys
|
|
|
this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
|
|
|
|
|
@@ -81,6 +84,9 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
var panStart = new THREE.Vector2();
|
|
|
var panEnd = new THREE.Vector2();
|
|
|
var panDelta = new THREE.Vector2();
|
|
|
+ var panOffset = new THREE.Vector3();
|
|
|
+
|
|
|
+ var offset = new THREE.Vector3();
|
|
|
|
|
|
var dollyStart = new THREE.Vector2();
|
|
|
var dollyEnd = new THREE.Vector2();
|
|
@@ -94,12 +100,19 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
var lastPosition = new THREE.Vector3();
|
|
|
|
|
|
var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
|
|
|
+
|
|
|
var state = STATE.NONE;
|
|
|
|
|
|
+ // for reset
|
|
|
+
|
|
|
+ this.target0 = this.target.clone();
|
|
|
+ this.position0 = this.object.position.clone();
|
|
|
+
|
|
|
// events
|
|
|
|
|
|
var changeEvent = { type: 'change' };
|
|
|
-
|
|
|
+ var startEvent = { type: 'start'};
|
|
|
+ var endEvent = { type: 'end'};
|
|
|
|
|
|
this.rotateLeft = function ( angle ) {
|
|
|
|
|
@@ -128,11 +141,11 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
// pass in distance in world space to move left
|
|
|
this.panLeft = function ( distance ) {
|
|
|
|
|
|
- var panOffset = new THREE.Vector3();
|
|
|
var te = this.object.matrix.elements;
|
|
|
+
|
|
|
// get X column of matrix
|
|
|
- panOffset.set( te[0], te[1], te[2] );
|
|
|
- panOffset.multiplyScalar(-distance);
|
|
|
+ panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] );
|
|
|
+ panOffset.multiplyScalar( - distance );
|
|
|
|
|
|
pan.add( panOffset );
|
|
|
|
|
@@ -141,18 +154,19 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
// pass in distance in world space to move up
|
|
|
this.panUp = function ( distance ) {
|
|
|
|
|
|
- var panOffset = new THREE.Vector3();
|
|
|
var te = this.object.matrix.elements;
|
|
|
+
|
|
|
// get Y column of matrix
|
|
|
- panOffset.set( te[4], te[5], te[6] );
|
|
|
- panOffset.multiplyScalar(distance);
|
|
|
+ panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] );
|
|
|
+ panOffset.multiplyScalar( distance );
|
|
|
|
|
|
pan.add( panOffset );
|
|
|
+
|
|
|
};
|
|
|
|
|
|
- // main entry point; pass in Vector2 of change desired in pixel space,
|
|
|
+ // pass in x,y of change desired in pixel space,
|
|
|
// right and down are positive
|
|
|
- this.pan = function ( delta ) {
|
|
|
+ this.pan = function ( deltaX, deltaY ) {
|
|
|
|
|
|
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
|
|
|
|
|
@@ -164,20 +178,21 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
var targetDistance = offset.length();
|
|
|
|
|
|
// half of the fov is center to top of screen
|
|
|
- targetDistance *= Math.tan( (scope.object.fov/2) * Math.PI / 180.0 );
|
|
|
+ targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
|
|
|
+
|
|
|
// we actually don't use screenWidth, since perspective camera is fixed to screen height
|
|
|
- scope.panLeft( 2 * delta.x * targetDistance / element.clientHeight );
|
|
|
- scope.panUp( 2 * delta.y * targetDistance / element.clientHeight );
|
|
|
+ scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight );
|
|
|
+ scope.panUp( 2 * deltaY * targetDistance / element.clientHeight );
|
|
|
|
|
|
} else if ( scope.object.top !== undefined ) {
|
|
|
|
|
|
// orthographic
|
|
|
- scope.panLeft( delta.x * (scope.object.right - scope.object.left) / element.clientWidth );
|
|
|
- scope.panUp( delta.y * (scope.object.top - scope.object.bottom) / element.clientHeight );
|
|
|
+ scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth );
|
|
|
+ scope.panUp( deltaY * (scope.object.top - scope.object.bottom) / element.clientHeight );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- // camera neither orthographic or perspective - warn user
|
|
|
+ // camera neither orthographic or perspective
|
|
|
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
|
|
|
|
|
|
}
|
|
@@ -211,7 +226,8 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
this.update = function () {
|
|
|
|
|
|
var position = this.object.position;
|
|
|
- var offset = position.clone().sub( this.target );
|
|
|
+
|
|
|
+ offset.copy( position ).sub( this.target );
|
|
|
|
|
|
// angle from z-axis around y-axis
|
|
|
|
|
@@ -255,7 +271,7 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
thetaDelta = 0;
|
|
|
phiDelta = 0;
|
|
|
scale = 1;
|
|
|
- pan.set(0,0,0);
|
|
|
+ pan.set( 0, 0, 0 );
|
|
|
|
|
|
if ( lastPosition.distanceTo( this.object.position ) > 0 ) {
|
|
|
|
|
@@ -268,6 +284,17 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
};
|
|
|
|
|
|
|
|
|
+ this.reset = function () {
|
|
|
+
|
|
|
+ state = STATE.NONE;
|
|
|
+
|
|
|
+ this.target.copy( this.target0 );
|
|
|
+ this.object.position.copy( this.position0 );
|
|
|
+
|
|
|
+ this.update();
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
function getAutoRotationAngle() {
|
|
|
|
|
|
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
|
|
@@ -282,25 +309,25 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
|
|
|
function onMouseDown( event ) {
|
|
|
|
|
|
- if ( scope.enabled === false ) { return; }
|
|
|
+ if ( scope.enabled === false ) return;
|
|
|
event.preventDefault();
|
|
|
|
|
|
if ( event.button === 0 ) {
|
|
|
- if ( scope.noRotate === true ) { return; }
|
|
|
+ if ( scope.noRotate === true ) return;
|
|
|
|
|
|
state = STATE.ROTATE;
|
|
|
|
|
|
rotateStart.set( event.clientX, event.clientY );
|
|
|
|
|
|
} else if ( event.button === 1 ) {
|
|
|
- if ( scope.noZoom === true ) { return; }
|
|
|
+ if ( scope.noZoom === true ) return;
|
|
|
|
|
|
state = STATE.DOLLY;
|
|
|
|
|
|
dollyStart.set( event.clientX, event.clientY );
|
|
|
|
|
|
} else if ( event.button === 2 ) {
|
|
|
- if ( scope.noPan === true ) { return; }
|
|
|
+ if ( scope.noPan === true ) return;
|
|
|
|
|
|
state = STATE.PAN;
|
|
|
|
|
@@ -308,9 +335,9 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
|
|
|
}
|
|
|
|
|
|
- // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
|
|
|
scope.domElement.addEventListener( 'mousemove', onMouseMove, false );
|
|
|
scope.domElement.addEventListener( 'mouseup', onMouseUp, false );
|
|
|
+ scope.dispatchEvent( startEvent );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -331,6 +358,7 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
|
|
|
// rotating across whole screen goes 360 degrees around
|
|
|
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
|
|
|
+
|
|
|
// rotating up and down along whole screen attempts to go 360, but limited to 180
|
|
|
scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
|
|
|
|
|
@@ -362,13 +390,12 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
panEnd.set( event.clientX, event.clientY );
|
|
|
panDelta.subVectors( panEnd, panStart );
|
|
|
|
|
|
- scope.pan( panDelta );
|
|
|
+ scope.pan( panDelta.x, panDelta.y );
|
|
|
|
|
|
panStart.copy( panEnd );
|
|
|
|
|
|
}
|
|
|
|
|
|
- // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
|
|
|
scope.update();
|
|
|
|
|
|
}
|
|
@@ -377,10 +404,9 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
|
|
|
if ( scope.enabled === false ) return;
|
|
|
|
|
|
- // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
|
|
|
scope.domElement.removeEventListener( 'mousemove', onMouseMove, false );
|
|
|
scope.domElement.removeEventListener( 'mouseup', onMouseUp, false );
|
|
|
-
|
|
|
+ scope.dispatchEvent( endEvent );
|
|
|
state = STATE.NONE;
|
|
|
|
|
|
}
|
|
@@ -389,13 +415,15 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
|
|
|
if ( scope.enabled === false || scope.noZoom === true ) return;
|
|
|
|
|
|
+ event.preventDefault();
|
|
|
+
|
|
|
var delta = 0;
|
|
|
|
|
|
- if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
|
|
|
+ if ( event.wheelDelta !== undefined ) { // WebKit / Opera / Explorer 9
|
|
|
|
|
|
delta = event.wheelDelta;
|
|
|
|
|
|
- } else if ( event.detail ) { // Firefox
|
|
|
+ } else if ( event.detail !== undefined ) { // Firefox
|
|
|
|
|
|
delta = - event.detail;
|
|
|
|
|
@@ -412,56 +440,50 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
}
|
|
|
|
|
|
scope.update();
|
|
|
+ scope.dispatchEvent( startEvent );
|
|
|
+ scope.dispatchEvent( endEvent );
|
|
|
|
|
|
}
|
|
|
|
|
|
function onKeyDown( event ) {
|
|
|
|
|
|
- if ( scope.enabled === false ) { return; }
|
|
|
- if ( scope.noKeys === true ) { return; }
|
|
|
- if ( scope.noPan === true ) { return; }
|
|
|
-
|
|
|
- // pan a pixel - I guess for precise positioning?
|
|
|
- // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
|
|
|
- var needUpdate = false;
|
|
|
+ if ( scope.enabled === false || scope.noKeys === true || scope.noPan === true ) return;
|
|
|
|
|
|
switch ( event.keyCode ) {
|
|
|
|
|
|
case scope.keys.UP:
|
|
|
- scope.pan( new THREE.Vector2( 0, scope.keyPanSpeed ) );
|
|
|
- needUpdate = true;
|
|
|
+ scope.pan( 0, scope.keyPanSpeed );
|
|
|
+ scope.update();
|
|
|
break;
|
|
|
+
|
|
|
case scope.keys.BOTTOM:
|
|
|
- scope.pan( new THREE.Vector2( 0, -scope.keyPanSpeed ) );
|
|
|
- needUpdate = true;
|
|
|
+ scope.pan( 0, - scope.keyPanSpeed );
|
|
|
+ scope.update();
|
|
|
break;
|
|
|
+
|
|
|
case scope.keys.LEFT:
|
|
|
- scope.pan( new THREE.Vector2( scope.keyPanSpeed, 0 ) );
|
|
|
- needUpdate = true;
|
|
|
+ scope.pan( scope.keyPanSpeed, 0 );
|
|
|
+ scope.update();
|
|
|
break;
|
|
|
+
|
|
|
case scope.keys.RIGHT:
|
|
|
- scope.pan( new THREE.Vector2( -scope.keyPanSpeed, 0 ) );
|
|
|
- needUpdate = true;
|
|
|
+ scope.pan( - scope.keyPanSpeed, 0 );
|
|
|
+ scope.update();
|
|
|
break;
|
|
|
- }
|
|
|
-
|
|
|
- // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
|
|
|
- if ( needUpdate ) {
|
|
|
-
|
|
|
- scope.update();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
function touchstart( event ) {
|
|
|
|
|
|
- if ( scope.enabled === false ) { return; }
|
|
|
+ if ( scope.enabled === false ) return;
|
|
|
|
|
|
switch ( event.touches.length ) {
|
|
|
|
|
|
case 1: // one-fingered touch: rotate
|
|
|
- if ( scope.noRotate === true ) { return; }
|
|
|
+
|
|
|
+ if ( scope.noRotate === true ) return;
|
|
|
|
|
|
state = STATE.TOUCH_ROTATE;
|
|
|
|
|
@@ -469,7 +491,8 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
break;
|
|
|
|
|
|
case 2: // two-fingered touch: dolly
|
|
|
- if ( scope.noZoom === true ) { return; }
|
|
|
+
|
|
|
+ if ( scope.noZoom === true ) return;
|
|
|
|
|
|
state = STATE.TOUCH_DOLLY;
|
|
|
|
|
@@ -480,7 +503,8 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
break;
|
|
|
|
|
|
case 3: // three-fingered touch: pan
|
|
|
- if ( scope.noPan === true ) { return; }
|
|
|
+
|
|
|
+ if ( scope.noPan === true ) return;
|
|
|
|
|
|
state = STATE.TOUCH_PAN;
|
|
|
|
|
@@ -488,27 +512,30 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
+
|
|
|
state = STATE.NONE;
|
|
|
|
|
|
}
|
|
|
+
|
|
|
+ scope.dispatchEvent( startEvent );
|
|
|
+
|
|
|
}
|
|
|
|
|
|
function touchmove( event ) {
|
|
|
|
|
|
- if ( scope.enabled === false ) { return; }
|
|
|
+ if ( scope.enabled === false ) return;
|
|
|
|
|
|
event.preventDefault();
|
|
|
event.stopPropagation();
|
|
|
|
|
|
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
|
|
|
|
|
|
- var needUpdate = false;
|
|
|
-
|
|
|
switch ( event.touches.length ) {
|
|
|
|
|
|
case 1: // one-fingered touch: rotate
|
|
|
- if ( scope.noRotate === true ) { return; }
|
|
|
- if ( state !== STATE.TOUCH_ROTATE ) { return; }
|
|
|
+
|
|
|
+ if ( scope.noRotate === true ) return;
|
|
|
+ if ( state !== STATE.TOUCH_ROTATE ) return;
|
|
|
|
|
|
rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
|
|
rotateDelta.subVectors( rotateEnd, rotateStart );
|
|
@@ -520,12 +547,13 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
|
|
|
rotateStart.copy( rotateEnd );
|
|
|
|
|
|
- needUpdate = true;
|
|
|
+ scope.update();
|
|
|
break;
|
|
|
|
|
|
case 2: // two-fingered touch: dolly
|
|
|
- if ( scope.noZoom === true ) { return; }
|
|
|
- if ( state !== STATE.TOUCH_DOLLY ) { return; }
|
|
|
+
|
|
|
+ if ( scope.noZoom === true ) return;
|
|
|
+ if ( state !== STATE.TOUCH_DOLLY ) return;
|
|
|
|
|
|
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
|
|
|
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
|
|
@@ -546,31 +574,27 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
|
|
|
dollyStart.copy( dollyEnd );
|
|
|
|
|
|
- needUpdate = true;
|
|
|
+ scope.update();
|
|
|
break;
|
|
|
|
|
|
case 3: // three-fingered touch: pan
|
|
|
- if ( scope.noPan === true ) { return; }
|
|
|
- if ( state !== STATE.TOUCH_PAN ) { return; }
|
|
|
+
|
|
|
+ if ( scope.noPan === true ) return;
|
|
|
+ if ( state !== STATE.TOUCH_PAN ) return;
|
|
|
|
|
|
panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
|
|
panDelta.subVectors( panEnd, panStart );
|
|
|
|
|
|
- scope.pan( panDelta );
|
|
|
+ scope.pan( panDelta.x, panDelta.y );
|
|
|
|
|
|
panStart.copy( panEnd );
|
|
|
|
|
|
- needUpdate = true;
|
|
|
+ scope.update();
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
- state = STATE.NONE;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if ( needUpdate ) {
|
|
|
|
|
|
- scope.update();
|
|
|
+ state = STATE.NONE;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -578,9 +602,11 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
|
|
|
function touchend( /* event */ ) {
|
|
|
|
|
|
- if ( scope.enabled === false ) { return; }
|
|
|
+ if ( scope.enabled === false ) return;
|
|
|
|
|
|
+ scope.dispatchEvent( endEvent );
|
|
|
state = STATE.NONE;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
|
|
@@ -588,12 +614,12 @@ THREE.OrbitControls = function ( object, domElement ) {
|
|
|
this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
|
|
|
this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
|
|
|
|
|
|
- this.domElement.addEventListener( 'keydown', onKeyDown, false );
|
|
|
-
|
|
|
this.domElement.addEventListener( 'touchstart', touchstart, false );
|
|
|
this.domElement.addEventListener( 'touchend', touchend, false );
|
|
|
this.domElement.addEventListener( 'touchmove', touchmove, false );
|
|
|
|
|
|
+ window.addEventListener( 'keydown', onKeyDown, false );
|
|
|
+
|
|
|
};
|
|
|
|
|
|
THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
|