|
@@ -30,6 +30,7 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
this.object = object;
|
|
|
this.domElement = domElement;
|
|
|
+ this.domElement.style.touchAction = 'none'; // disable touch scroll
|
|
|
|
|
|
// Set to false to disable this control
|
|
|
this.enabled = true;
|
|
@@ -290,12 +291,9 @@ class OrbitControls extends EventDispatcher {
|
|
|
scope.domElement.removeEventListener( 'contextmenu', onContextMenu );
|
|
|
|
|
|
scope.domElement.removeEventListener( 'pointerdown', onPointerDown );
|
|
|
+ scope.domElement.removeEventListener( 'pointercancel', onPointerCancel );
|
|
|
scope.domElement.removeEventListener( 'wheel', onMouseWheel );
|
|
|
|
|
|
- scope.domElement.removeEventListener( 'touchstart', onTouchStart );
|
|
|
- scope.domElement.removeEventListener( 'touchend', onTouchEnd );
|
|
|
- scope.domElement.removeEventListener( 'touchmove', onTouchMove );
|
|
|
-
|
|
|
scope.domElement.ownerDocument.removeEventListener( 'pointermove', onPointerMove );
|
|
|
scope.domElement.ownerDocument.removeEventListener( 'pointerup', onPointerUp );
|
|
|
|
|
@@ -351,6 +349,9 @@ class OrbitControls extends EventDispatcher {
|
|
|
const dollyEnd = new Vector2();
|
|
|
const dollyDelta = new Vector2();
|
|
|
|
|
|
+ const pointers = [];
|
|
|
+ const pointerPositions = {};
|
|
|
+
|
|
|
function getAutoRotationAngle() {
|
|
|
|
|
|
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
|
|
@@ -636,16 +637,16 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function handleTouchStartRotate( event ) {
|
|
|
+ function handleTouchStartRotate() {
|
|
|
|
|
|
- if ( event.touches.length == 1 ) {
|
|
|
+ if ( pointers.length === 1 ) {
|
|
|
|
|
|
- rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
|
|
+ rotateStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- const x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
|
|
|
- const y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
|
|
|
+ const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX );
|
|
|
+ const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY );
|
|
|
|
|
|
rotateStart.set( x, y );
|
|
|
|
|
@@ -653,16 +654,16 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function handleTouchStartPan( event ) {
|
|
|
+ function handleTouchStartPan() {
|
|
|
|
|
|
- if ( event.touches.length == 1 ) {
|
|
|
+ if ( pointers.length === 1 ) {
|
|
|
|
|
|
- panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
|
|
+ panStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- const x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
|
|
|
- const y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
|
|
|
+ const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX );
|
|
|
+ const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY );
|
|
|
|
|
|
panStart.set( x, y );
|
|
|
|
|
@@ -670,10 +671,10 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function handleTouchStartDolly( event ) {
|
|
|
+ function handleTouchStartDolly() {
|
|
|
|
|
|
- const dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
|
|
|
- const dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
|
|
|
+ const dx = pointers[ 0 ].pageX - pointers[ 1 ].pageX;
|
|
|
+ const dy = pointers[ 0 ].pageY - pointers[ 1 ].pageY;
|
|
|
|
|
|
const distance = Math.sqrt( dx * dx + dy * dy );
|
|
|
|
|
@@ -681,32 +682,34 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function handleTouchStartDollyPan( event ) {
|
|
|
+ function handleTouchStartDollyPan() {
|
|
|
|
|
|
- if ( scope.enableZoom ) handleTouchStartDolly( event );
|
|
|
+ if ( scope.enableZoom ) handleTouchStartDolly();
|
|
|
|
|
|
- if ( scope.enablePan ) handleTouchStartPan( event );
|
|
|
+ if ( scope.enablePan ) handleTouchStartPan();
|
|
|
|
|
|
}
|
|
|
|
|
|
- function handleTouchStartDollyRotate( event ) {
|
|
|
+ function handleTouchStartDollyRotate() {
|
|
|
|
|
|
- if ( scope.enableZoom ) handleTouchStartDolly( event );
|
|
|
+ if ( scope.enableZoom ) handleTouchStartDolly();
|
|
|
|
|
|
- if ( scope.enableRotate ) handleTouchStartRotate( event );
|
|
|
+ if ( scope.enableRotate ) handleTouchStartRotate();
|
|
|
|
|
|
}
|
|
|
|
|
|
function handleTouchMoveRotate( event ) {
|
|
|
|
|
|
- if ( event.touches.length == 1 ) {
|
|
|
+ if ( pointers.length == 1 ) {
|
|
|
|
|
|
- rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
|
|
+ rotateEnd.set( event.pageX, event.pageY );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- const x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
|
|
|
- const y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
|
|
|
+ const position = getSecondPointerPosition( event );
|
|
|
+
|
|
|
+ const x = 0.5 * ( event.pageX + position.x );
|
|
|
+ const y = 0.5 * ( event.pageY + position.y );
|
|
|
|
|
|
rotateEnd.set( x, y );
|
|
|
|
|
@@ -726,14 +729,16 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
function handleTouchMovePan( event ) {
|
|
|
|
|
|
- if ( event.touches.length == 1 ) {
|
|
|
+ if ( pointers.length === 1 ) {
|
|
|
|
|
|
- panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
|
|
|
+ panEnd.set( event.pageX, event.pageY );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- const x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
|
|
|
- const y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
|
|
|
+ const position = getSecondPointerPosition( event );
|
|
|
+
|
|
|
+ const x = 0.5 * ( event.pageX + position.x );
|
|
|
+ const y = 0.5 * ( event.pageY + position.y );
|
|
|
|
|
|
panEnd.set( x, y );
|
|
|
|
|
@@ -749,8 +754,10 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
function handleTouchMoveDolly( event ) {
|
|
|
|
|
|
- const dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
|
|
|
- const dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
|
|
|
+ const position = getSecondPointerPosition( event );
|
|
|
+
|
|
|
+ const dx = event.pageX - position.x;
|
|
|
+ const dy = event.pageY - position.y;
|
|
|
|
|
|
const distance = Math.sqrt( dx * dx + dy * dy );
|
|
|
|
|
@@ -794,14 +801,24 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
if ( scope.enabled === false ) return;
|
|
|
|
|
|
- switch ( event.pointerType ) {
|
|
|
+ if ( pointers.length === 0 ) {
|
|
|
|
|
|
- case 'mouse':
|
|
|
- case 'pen':
|
|
|
- onMouseDown( event );
|
|
|
- break;
|
|
|
+ scope.domElement.ownerDocument.addEventListener( 'pointermove', onPointerMove );
|
|
|
+ scope.domElement.ownerDocument.addEventListener( 'pointerup', onPointerUp );
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
- // TODO touch
|
|
|
+ //
|
|
|
+
|
|
|
+ addPointer( event );
|
|
|
+
|
|
|
+ if ( event.pointerType === 'touch' ) {
|
|
|
+
|
|
|
+ onTouchStart( event );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ onMouseDown( event );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -811,14 +828,13 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
if ( scope.enabled === false ) return;
|
|
|
|
|
|
- switch ( event.pointerType ) {
|
|
|
+ if ( event.pointerType === 'touch' ) {
|
|
|
|
|
|
- case 'mouse':
|
|
|
- case 'pen':
|
|
|
- onMouseMove( event );
|
|
|
- break;
|
|
|
+ onTouchMove( event );
|
|
|
|
|
|
- // TODO touch
|
|
|
+ } else {
|
|
|
+
|
|
|
+ onMouseMove( event );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -826,19 +842,37 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
function onPointerUp( event ) {
|
|
|
|
|
|
- switch ( event.pointerType ) {
|
|
|
+ if ( scope.enabled === false ) return;
|
|
|
|
|
|
- case 'mouse':
|
|
|
- case 'pen':
|
|
|
- onMouseUp( event );
|
|
|
- break;
|
|
|
+ if ( event.pointerType === 'touch' ) {
|
|
|
+
|
|
|
+ onTouchEnd();
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ onMouseUp( event );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ removePointer( event );
|
|
|
+
|
|
|
+ //
|
|
|
+
|
|
|
+ if ( pointers.length === 0 ) {
|
|
|
|
|
|
- // TODO touch
|
|
|
+ scope.domElement.ownerDocument.removeEventListener( 'pointermove', onPointerMove );
|
|
|
+ scope.domElement.ownerDocument.removeEventListener( 'pointerup', onPointerUp );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
+ function onPointerCancel( event ) {
|
|
|
+
|
|
|
+ removePointer( event );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
function onMouseDown( event ) {
|
|
|
|
|
|
let mouseAction;
|
|
@@ -930,9 +964,6 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
if ( state !== STATE.NONE ) {
|
|
|
|
|
|
- scope.domElement.ownerDocument.addEventListener( 'pointermove', onPointerMove );
|
|
|
- scope.domElement.ownerDocument.addEventListener( 'pointerup', onPointerUp );
|
|
|
-
|
|
|
scope.dispatchEvent( _startEvent );
|
|
|
|
|
|
}
|
|
@@ -975,11 +1006,6 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
function onMouseUp( event ) {
|
|
|
|
|
|
- scope.domElement.ownerDocument.removeEventListener( 'pointermove', onPointerMove );
|
|
|
- scope.domElement.ownerDocument.removeEventListener( 'pointerup', onPointerUp );
|
|
|
-
|
|
|
- if ( scope.enabled === false ) return;
|
|
|
-
|
|
|
handleMouseUp( event );
|
|
|
|
|
|
scope.dispatchEvent( _endEvent );
|
|
@@ -1012,11 +1038,9 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
function onTouchStart( event ) {
|
|
|
|
|
|
- if ( scope.enabled === false ) return;
|
|
|
-
|
|
|
- event.preventDefault(); // prevent scrolling
|
|
|
+ trackPointer( event );
|
|
|
|
|
|
- switch ( event.touches.length ) {
|
|
|
+ switch ( pointers.length ) {
|
|
|
|
|
|
case 1:
|
|
|
|
|
@@ -1026,7 +1050,7 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
if ( scope.enableRotate === false ) return;
|
|
|
|
|
|
- handleTouchStartRotate( event );
|
|
|
+ handleTouchStartRotate();
|
|
|
|
|
|
state = STATE.TOUCH_ROTATE;
|
|
|
|
|
@@ -1036,7 +1060,7 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
if ( scope.enablePan === false ) return;
|
|
|
|
|
|
- handleTouchStartPan( event );
|
|
|
+ handleTouchStartPan();
|
|
|
|
|
|
state = STATE.TOUCH_PAN;
|
|
|
|
|
@@ -1058,7 +1082,7 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
if ( scope.enableZoom === false && scope.enablePan === false ) return;
|
|
|
|
|
|
- handleTouchStartDollyPan( event );
|
|
|
+ handleTouchStartDollyPan();
|
|
|
|
|
|
state = STATE.TOUCH_DOLLY_PAN;
|
|
|
|
|
@@ -1068,7 +1092,7 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
if ( scope.enableZoom === false && scope.enableRotate === false ) return;
|
|
|
|
|
|
- handleTouchStartDollyRotate( event );
|
|
|
+ handleTouchStartDollyRotate();
|
|
|
|
|
|
state = STATE.TOUCH_DOLLY_ROTATE;
|
|
|
|
|
@@ -1098,9 +1122,7 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
function onTouchMove( event ) {
|
|
|
|
|
|
- if ( scope.enabled === false ) return;
|
|
|
-
|
|
|
- event.preventDefault(); // prevent scrolling
|
|
|
+ trackPointer( event );
|
|
|
|
|
|
switch ( state ) {
|
|
|
|
|
@@ -1154,8 +1176,6 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
function onTouchEnd( event ) {
|
|
|
|
|
|
- if ( scope.enabled === false ) return;
|
|
|
-
|
|
|
handleTouchEnd( event );
|
|
|
|
|
|
scope.dispatchEvent( _endEvent );
|
|
@@ -1172,17 +1192,60 @@ class OrbitControls extends EventDispatcher {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ function addPointer( event ) {
|
|
|
+
|
|
|
+ pointers.push( event );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function removePointer( event ) {
|
|
|
+
|
|
|
+ delete pointerPositions[ event.pointerId ];
|
|
|
+
|
|
|
+ for ( let i = 0; i < pointers.length; i ++ ) {
|
|
|
+
|
|
|
+ if ( pointers[ i ].pointerId == event.pointerId ) {
|
|
|
+
|
|
|
+ pointers.splice( i, 1 );
|
|
|
+ return;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function trackPointer( event ) {
|
|
|
+
|
|
|
+ let position = pointerPositions[ event.pointerId ];
|
|
|
+
|
|
|
+ if ( position === undefined ) {
|
|
|
+
|
|
|
+ position = new Vector2();
|
|
|
+ pointerPositions[ event.pointerId ] = position;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ position.set( event.pageX, event.pageY );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function getSecondPointerPosition( event ) {
|
|
|
+
|
|
|
+ const pointer = ( event.pointerId === pointers[ 0 ].pointerId ) ? pointers[ 1 ] : pointers[ 0 ];
|
|
|
+
|
|
|
+ return pointerPositions[ pointer.pointerId ];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
//
|
|
|
|
|
|
scope.domElement.addEventListener( 'contextmenu', onContextMenu );
|
|
|
|
|
|
scope.domElement.addEventListener( 'pointerdown', onPointerDown );
|
|
|
+ scope.domElement.addEventListener( 'pointercancel', onPointerCancel );
|
|
|
scope.domElement.addEventListener( 'wheel', onMouseWheel, { passive: false } );
|
|
|
|
|
|
- scope.domElement.addEventListener( 'touchstart', onTouchStart, { passive: false } );
|
|
|
- scope.domElement.addEventListener( 'touchend', onTouchEnd );
|
|
|
- scope.domElement.addEventListener( 'touchmove', onTouchMove, { passive: false } );
|
|
|
-
|
|
|
// force an update at start
|
|
|
|
|
|
this.update();
|