|
@@ -24,6 +24,7 @@ class TrackballControls extends EventDispatcher {
|
|
|
|
|
|
this.object = object;
|
|
|
this.domElement = domElement;
|
|
|
+ this.domElement.style.touchAction = 'none'; // disable touch scroll
|
|
|
|
|
|
// API
|
|
|
|
|
@@ -77,7 +78,10 @@ class TrackballControls extends EventDispatcher {
|
|
|
_zoomEnd = new Vector2(),
|
|
|
|
|
|
_panStart = new Vector2(),
|
|
|
- _panEnd = new Vector2();
|
|
|
+ _panEnd = new Vector2(),
|
|
|
+
|
|
|
+ _pointers = [],
|
|
|
+ _pointerPositions = {};
|
|
|
|
|
|
// for reset
|
|
|
|
|
@@ -406,14 +410,24 @@ class TrackballControls 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 );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+
|
|
|
+ addPointer( event );
|
|
|
+
|
|
|
+ if ( event.pointerType === 'touch' ) {
|
|
|
+
|
|
|
+ onTouchStart( event );
|
|
|
+
|
|
|
+ } else {
|
|
|
|
|
|
- // TODO touch
|
|
|
+ onMouseDown( event );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -423,14 +437,13 @@ class TrackballControls extends EventDispatcher {
|
|
|
|
|
|
if ( scope.enabled === false ) return;
|
|
|
|
|
|
- switch ( event.pointerType ) {
|
|
|
+ if ( event.pointerType === 'touch' ) {
|
|
|
|
|
|
- case 'mouse':
|
|
|
- case 'pen':
|
|
|
- onMouseMove( event );
|
|
|
- break;
|
|
|
+ onTouchMove( event );
|
|
|
+
|
|
|
+ } else {
|
|
|
|
|
|
- // TODO touch
|
|
|
+ onMouseMove( event );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -440,17 +453,34 @@ class TrackballControls extends EventDispatcher {
|
|
|
|
|
|
if ( scope.enabled === false ) return;
|
|
|
|
|
|
- switch ( event.pointerType ) {
|
|
|
+ if ( event.pointerType === 'touch' ) {
|
|
|
|
|
|
- case 'mouse':
|
|
|
- case 'pen':
|
|
|
- onMouseUp();
|
|
|
- break;
|
|
|
+ onTouchEnd( event );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ onMouseUp( event );
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
- // TODO touch
|
|
|
+ //
|
|
|
+
|
|
|
+ removePointer( event );
|
|
|
+
|
|
|
+ if ( _pointers.length === 0 ) {
|
|
|
+
|
|
|
+ scope.domElement.ownerDocument.removeEventListener( 'pointermove', onPointerMove );
|
|
|
+ scope.domElement.ownerDocument.removeEventListener( 'pointerup', onPointerUp );
|
|
|
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function onPointerCancel( event ) {
|
|
|
+
|
|
|
+ removePointer( event );
|
|
|
+
|
|
|
}
|
|
|
|
|
|
function keydown( event ) {
|
|
@@ -542,8 +572,6 @@ class TrackballControls extends EventDispatcher {
|
|
|
|
|
|
function onMouseMove( event ) {
|
|
|
|
|
|
- if ( scope.enabled === false ) return;
|
|
|
-
|
|
|
const state = ( _keyState !== STATE.NONE ) ? _keyState : _state;
|
|
|
|
|
|
if ( state === STATE.ROTATE && ! scope.noRotate ) {
|
|
@@ -565,8 +593,6 @@ class TrackballControls extends EventDispatcher {
|
|
|
|
|
|
function onMouseUp() {
|
|
|
|
|
|
- if ( scope.enabled === false ) return;
|
|
|
-
|
|
|
_state = STATE.NONE;
|
|
|
|
|
|
scope.domElement.ownerDocument.removeEventListener( 'pointermove', onPointerMove );
|
|
@@ -576,7 +602,7 @@ class TrackballControls extends EventDispatcher {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function mousewheel( event ) {
|
|
|
+ function onMouseWheel( event ) {
|
|
|
|
|
|
if ( scope.enabled === false ) return;
|
|
|
|
|
@@ -608,28 +634,26 @@ class TrackballControls extends EventDispatcher {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function touchstart( event ) {
|
|
|
+ function onTouchStart( event ) {
|
|
|
|
|
|
- if ( scope.enabled === false ) return;
|
|
|
-
|
|
|
- event.preventDefault();
|
|
|
+ trackPointer( event );
|
|
|
|
|
|
- switch ( event.touches.length ) {
|
|
|
+ switch ( _pointers.length ) {
|
|
|
|
|
|
case 1:
|
|
|
_state = STATE.TOUCH_ROTATE;
|
|
|
- _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
|
|
|
+ _moveCurr.copy( getMouseOnCircle( _pointers[ 0 ].pageX, _pointers[ 0 ].pageY ) );
|
|
|
_movePrev.copy( _moveCurr );
|
|
|
break;
|
|
|
|
|
|
default: // 2 or more
|
|
|
_state = STATE.TOUCH_ZOOM_PAN;
|
|
|
- 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;
|
|
|
_touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
|
|
|
|
|
|
- const x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
|
|
|
- const y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
|
|
|
+ const x = ( _pointers[ 0 ].pageX + _pointers[ 1 ].pageX ) / 2;
|
|
|
+ const y = ( _pointers[ 0 ].pageY + _pointers[ 1 ].pageY ) / 2;
|
|
|
_panStart.copy( getMouseOnScreen( x, y ) );
|
|
|
_panEnd.copy( _panStart );
|
|
|
break;
|
|
@@ -640,26 +664,27 @@ class TrackballControls extends EventDispatcher {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function touchmove( event ) {
|
|
|
+ function onTouchMove( event ) {
|
|
|
|
|
|
- if ( scope.enabled === false ) return;
|
|
|
-
|
|
|
- event.preventDefault();
|
|
|
+ trackPointer( event );
|
|
|
|
|
|
- switch ( event.touches.length ) {
|
|
|
+ switch ( _pointers.length ) {
|
|
|
|
|
|
case 1:
|
|
|
_movePrev.copy( _moveCurr );
|
|
|
- _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
|
|
|
+ _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) );
|
|
|
break;
|
|
|
|
|
|
default: // 2 or more
|
|
|
- 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;
|
|
|
_touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy );
|
|
|
|
|
|
- const x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
|
|
|
- const y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
|
|
|
+ const x = ( event.pageX + position.x ) / 2;
|
|
|
+ const y = ( event.pageY + position.y ) / 2;
|
|
|
_panEnd.copy( getMouseOnScreen( x, y ) );
|
|
|
break;
|
|
|
|
|
@@ -667,11 +692,9 @@ class TrackballControls extends EventDispatcher {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function touchend( event ) {
|
|
|
-
|
|
|
- if ( scope.enabled === false ) return;
|
|
|
+ function onTouchEnd( event ) {
|
|
|
|
|
|
- switch ( event.touches.length ) {
|
|
|
+ switch ( _pointers.length ) {
|
|
|
|
|
|
case 0:
|
|
|
_state = STATE.NONE;
|
|
@@ -679,7 +702,7 @@ class TrackballControls extends EventDispatcher {
|
|
|
|
|
|
case 1:
|
|
|
_state = STATE.TOUCH_ROTATE;
|
|
|
- _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
|
|
|
+ _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) );
|
|
|
_movePrev.copy( _moveCurr );
|
|
|
break;
|
|
|
|
|
@@ -697,19 +720,59 @@ class TrackballControls 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 ];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
this.dispose = function () {
|
|
|
|
|
|
scope.domElement.removeEventListener( 'contextmenu', contextmenu );
|
|
|
|
|
|
scope.domElement.removeEventListener( 'pointerdown', onPointerDown );
|
|
|
- scope.domElement.removeEventListener( 'wheel', mousewheel );
|
|
|
-
|
|
|
- scope.domElement.removeEventListener( 'touchstart', touchstart );
|
|
|
- scope.domElement.removeEventListener( 'touchend', touchend );
|
|
|
- scope.domElement.removeEventListener( 'touchmove', touchmove );
|
|
|
-
|
|
|
- scope.domElement.ownerDocument.removeEventListener( 'pointermove', onPointerMove );
|
|
|
- scope.domElement.ownerDocument.removeEventListener( 'pointerup', onPointerUp );
|
|
|
+ scope.domElement.removeEventListener( 'pointercancel', onPointerCancel );
|
|
|
+ scope.domElement.removeEventListener( 'wheel', onMouseWheel );
|
|
|
|
|
|
window.removeEventListener( 'keydown', keydown );
|
|
|
window.removeEventListener( 'keyup', keyup );
|
|
@@ -719,14 +782,9 @@ class TrackballControls extends EventDispatcher {
|
|
|
this.domElement.addEventListener( 'contextmenu', contextmenu );
|
|
|
|
|
|
this.domElement.addEventListener( 'pointerdown', onPointerDown );
|
|
|
- this.domElement.addEventListener( 'wheel', mousewheel, { passive: false } );
|
|
|
-
|
|
|
- this.domElement.addEventListener( 'touchstart', touchstart, { passive: false } );
|
|
|
- this.domElement.addEventListener( 'touchend', touchend );
|
|
|
- this.domElement.addEventListener( 'touchmove', touchmove, { passive: false } );
|
|
|
+ this.domElement.addEventListener( 'pointercancel', onPointerCancel );
|
|
|
+ this.domElement.addEventListener( 'wheel', onMouseWheel, { passive: false } );
|
|
|
|
|
|
- this.domElement.ownerDocument.addEventListener( 'pointermove', onPointerMove );
|
|
|
- this.domElement.ownerDocument.addEventListener( 'pointerup', onPointerUp );
|
|
|
|
|
|
window.addEventListener( 'keydown', keydown );
|
|
|
window.addEventListener( 'keyup', keyup );
|