9 } from './three.module.js';
\r
11 // This set of controls performs orbiting, dollying (zooming), and panning.
\r
12 // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
\r
14 // Orbit - left mouse / touch: one-finger move
\r
15 // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
\r
16 // Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move
\r
18 var OrbitControls = function ( object, domElement ) {
\r
20 if ( domElement === undefined ) console.warn( 'THREE.OrbitControls: The second parameter "domElement" is now mandatory.' );
\r
21 if ( domElement === document ) console.error( 'THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.' );
\r
23 this.object = object;
\r
24 this.domElement = domElement;
\r
26 // Set to false to disable this control
\r
27 this.enabled = true;
\r
29 // "target" sets the location of focus, where the object orbits around
\r
30 this.target = new Vector3();
\r
32 // How far you can dolly in and out ( PerspectiveCamera only )
\r
33 this.minDistance = 0;
\r
34 this.maxDistance = Infinity;
\r
36 // How far you can zoom in and out ( OrthographicCamera only )
\r
38 this.maxZoom = Infinity;
\r
40 // How far you can orbit vertically, upper and lower limits.
\r
41 // Range is 0 to Math.PI radians.
\r
42 this.minPolarAngle = 0; // radians
\r
43 this.maxPolarAngle = Math.PI; // radians
\r
45 // How far you can orbit horizontally, upper and lower limits.
\r
46 // If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI )
\r
47 this.minAzimuthAngle = - Infinity; // radians
\r
48 this.maxAzimuthAngle = Infinity; // radians
\r
50 // Set to true to enable damping (inertia)
\r
51 // If damping is enabled, you must call controls.update() in your animation loop
\r
52 this.enableDamping = false;
\r
53 this.dampingFactor = 0.05;
\r
55 // This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
\r
56 // Set to false to disable zooming
\r
57 this.enableZoom = true;
\r
58 this.zoomSpeed = 1.0;
\r
60 // Set to false to disable rotating
\r
61 this.enableRotate = true;
\r
62 this.rotateSpeed = 1.0;
\r
64 // Set to false to disable panning
\r
65 this.enablePan = true;
\r
66 this.panSpeed = 1.0;
\r
67 this.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up
\r
68 this.keyPanSpeed = 7.0; // pixels moved per arrow key push
\r
70 // Set to true to automatically rotate around the target
\r
71 // If auto-rotate is enabled, you must call controls.update() in your animation loop
\r
72 this.autoRotate = false;
\r
73 this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
\r
75 // The four arrow keys
\r
76 this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
\r
79 this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };
\r
82 this.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN };
\r
85 this.target0 = this.target.clone();
\r
86 this.position0 = this.object.position.clone();
\r
87 this.zoom0 = this.object.zoom;
\r
89 // the target DOM element for key events
\r
90 this._domElementKeyEvents = null;
\r
96 this.getPolarAngle = function () {
\r
98 return spherical.phi;
\r
102 this.getAzimuthalAngle = function () {
\r
104 return spherical.theta;
\r
108 this.listenToKeyEvents = function ( domElement ) {
\r
110 domElement.addEventListener( 'keydown', onKeyDown );
\r
111 this._domElementKeyEvents = domElement;
\r
115 this.saveState = function () {
\r
117 scope.target0.copy( scope.target );
\r
118 scope.position0.copy( scope.object.position );
\r
119 scope.zoom0 = scope.object.zoom;
\r
123 this.reset = function () {
\r
125 scope.target.copy( scope.target0 );
\r
126 scope.object.position.copy( scope.position0 );
\r
127 scope.object.zoom = scope.zoom0;
\r
129 scope.object.updateProjectionMatrix();
\r
130 scope.dispatchEvent( changeEvent );
\r
134 state = STATE.NONE;
\r
138 // this method is exposed, but perhaps it would be better if we can make it private...
\r
139 this.update = function () {
\r
141 var offset = new Vector3();
\r
143 // so camera.up is the orbit axis
\r
144 var quat = new Quaternion().setFromUnitVectors( object.up, new Vector3( 0, 1, 0 ) );
\r
145 var quatInverse = quat.clone().invert();
\r
147 var lastPosition = new Vector3();
\r
148 var lastQuaternion = new Quaternion();
\r
150 var twoPI = 2 * Math.PI;
\r
152 return function update() {
\r
154 var position = scope.object.position;
\r
156 offset.copy( position ).sub( scope.target );
\r
158 // rotate offset to "y-axis-is-up" space
\r
159 offset.applyQuaternion( quat );
\r
161 // angle from z-axis around y-axis
\r
162 spherical.setFromVector3( offset );
\r
164 if ( scope.autoRotate && state === STATE.NONE ) {
\r
166 rotateLeft( getAutoRotationAngle() );
\r
170 if ( scope.enableDamping ) {
\r
172 spherical.theta += sphericalDelta.theta * scope.dampingFactor;
\r
173 spherical.phi += sphericalDelta.phi * scope.dampingFactor;
\r
177 spherical.theta += sphericalDelta.theta;
\r
178 spherical.phi += sphericalDelta.phi;
\r
182 // restrict theta to be between desired limits
\r
184 var min = scope.minAzimuthAngle;
\r
185 var max = scope.maxAzimuthAngle;
\r
187 if ( isFinite( min ) && isFinite( max ) ) {
\r
189 if ( min < - Math.PI ) min += twoPI; else if ( min > Math.PI ) min -= twoPI;
\r
191 if ( max < - Math.PI ) max += twoPI; else if ( max > Math.PI ) max -= twoPI;
\r
193 if ( min <= max ) {
\r
195 spherical.theta = Math.max( min, Math.min( max, spherical.theta ) );
\r
199 spherical.theta = ( spherical.theta > ( min + max ) / 2 ) ?
\r
200 Math.max( min, spherical.theta ) :
\r
201 Math.min( max, spherical.theta );
\r
207 // restrict phi to be between desired limits
\r
208 spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );
\r
210 spherical.makeSafe();
\r
213 spherical.radius *= scale;
\r
215 // restrict radius to be between desired limits
\r
216 spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) );
\r
218 // move target to panned location
\r
220 if ( scope.enableDamping === true ) {
\r
222 scope.target.addScaledVector( panOffset, scope.dampingFactor );
\r
226 scope.target.add( panOffset );
\r
230 offset.setFromSpherical( spherical );
\r
232 // rotate offset back to "camera-up-vector-is-up" space
\r
233 offset.applyQuaternion( quatInverse );
\r
235 position.copy( scope.target ).add( offset );
\r
237 scope.object.lookAt( scope.target );
\r
239 if ( scope.enableDamping === true ) {
\r
241 sphericalDelta.theta *= ( 1 - scope.dampingFactor );
\r
242 sphericalDelta.phi *= ( 1 - scope.dampingFactor );
\r
244 panOffset.multiplyScalar( 1 - scope.dampingFactor );
\r
248 sphericalDelta.set( 0, 0, 0 );
\r
250 panOffset.set( 0, 0, 0 );
\r
256 // update condition is:
\r
257 // min(camera displacement, camera rotation in radians)^2 > EPS
\r
258 // using small-angle approximation cos(x/2) = 1 - x^2 / 8
\r
260 if ( zoomChanged ||
\r
261 lastPosition.distanceToSquared( scope.object.position ) > EPS ||
\r
262 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) {
\r
264 scope.dispatchEvent( changeEvent );
\r
266 lastPosition.copy( scope.object.position );
\r
267 lastQuaternion.copy( scope.object.quaternion );
\r
268 zoomChanged = false;
\r
280 this.dispose = function () {
\r
282 scope.domElement.removeEventListener( 'contextmenu', onContextMenu );
\r
284 scope.domElement.removeEventListener( 'pointerdown', onPointerDown );
\r
285 scope.domElement.removeEventListener( 'wheel', onMouseWheel );
\r
287 scope.domElement.removeEventListener( 'touchstart', onTouchStart );
\r
288 scope.domElement.removeEventListener( 'touchend', onTouchEnd );
\r
289 scope.domElement.removeEventListener( 'touchmove', onTouchMove );
\r
291 scope.domElement.ownerDocument.removeEventListener( 'pointermove', onPointerMove );
\r
292 scope.domElement.ownerDocument.removeEventListener( 'pointerup', onPointerUp );
\r
295 if ( scope._domElementKeyEvents !== null ) {
\r
297 scope._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown );
\r
301 //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
\r
311 var changeEvent = { type: 'change' };
\r
312 var startEvent = { type: 'start' };
\r
313 var endEvent = { type: 'end' };
\r
322 TOUCH_DOLLY_PAN: 5,
\r
323 TOUCH_DOLLY_ROTATE: 6
\r
326 var state = STATE.NONE;
\r
328 var EPS = 0.000001;
\r
330 // current position in spherical coordinates
\r
331 var spherical = new Spherical();
\r
332 var sphericalDelta = new Spherical();
\r
335 var panOffset = new Vector3();
\r
336 var zoomChanged = false;
\r
338 var rotateStart = new Vector2();
\r
339 var rotateEnd = new Vector2();
\r
340 var rotateDelta = new Vector2();
\r
342 var panStart = new Vector2();
\r
343 var panEnd = new Vector2();
\r
344 var panDelta = new Vector2();
\r
346 var dollyStart = new Vector2();
\r
347 var dollyEnd = new Vector2();
\r
348 var dollyDelta = new Vector2();
\r
350 function getAutoRotationAngle() {
\r
352 return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
\r
356 function getZoomScale() {
\r
358 return Math.pow( 0.95, scope.zoomSpeed );
\r
362 function rotateLeft( angle ) {
\r
364 sphericalDelta.theta -= angle;
\r
368 function rotateUp( angle ) {
\r
370 sphericalDelta.phi -= angle;
\r
374 var panLeft = function () {
\r
376 var v = new Vector3();
\r
378 return function panLeft( distance, objectMatrix ) {
\r
380 v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix
\r
381 v.multiplyScalar( - distance );
\r
383 panOffset.add( v );
\r
389 var panUp = function () {
\r
391 var v = new Vector3();
\r
393 return function panUp( distance, objectMatrix ) {
\r
395 if ( scope.screenSpacePanning === true ) {
\r
397 v.setFromMatrixColumn( objectMatrix, 1 );
\r
401 v.setFromMatrixColumn( objectMatrix, 0 );
\r
402 v.crossVectors( scope.object.up, v );
\r
406 v.multiplyScalar( distance );
\r
408 panOffset.add( v );
\r
414 // deltaX and deltaY are in pixels; right and down are positive
\r
415 var pan = function () {
\r
417 var offset = new Vector3();
\r
419 return function pan( deltaX, deltaY ) {
\r
421 var element = scope.domElement;
\r
423 if ( scope.object.isPerspectiveCamera ) {
\r
426 var position = scope.object.position;
\r
427 offset.copy( position ).sub( scope.target );
\r
428 var targetDistance = offset.length();
\r
430 // half of the fov is center to top of screen
\r
431 targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
\r
433 // we use only clientHeight here so aspect ratio does not distort speed
\r
434 panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );
\r
435 panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );
\r
437 } else if ( scope.object.isOrthographicCamera ) {
\r
440 panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );
\r
441 panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );
\r
445 // camera neither orthographic nor perspective
\r
446 console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
\r
447 scope.enablePan = false;
\r
455 function dollyOut( dollyScale ) {
\r
457 if ( scope.object.isPerspectiveCamera ) {
\r
459 scale /= dollyScale;
\r
461 } else if ( scope.object.isOrthographicCamera ) {
\r
463 scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) );
\r
464 scope.object.updateProjectionMatrix();
\r
465 zoomChanged = true;
\r
469 console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
\r
470 scope.enableZoom = false;
\r
476 function dollyIn( dollyScale ) {
\r
478 if ( scope.object.isPerspectiveCamera ) {
\r
480 scale *= dollyScale;
\r
482 } else if ( scope.object.isOrthographicCamera ) {
\r
484 scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) );
\r
485 scope.object.updateProjectionMatrix();
\r
486 zoomChanged = true;
\r
490 console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
\r
491 scope.enableZoom = false;
\r
498 // event callbacks - update the object state
\r
501 function handleMouseDownRotate( event ) {
\r
503 rotateStart.set( event.clientX, event.clientY );
\r
507 function handleMouseDownDolly( event ) {
\r
509 dollyStart.set( event.clientX, event.clientY );
\r
513 function handleMouseDownPan( event ) {
\r
515 panStart.set( event.clientX, event.clientY );
\r
519 function handleMouseMoveRotate( event ) {
\r
521 rotateEnd.set( event.clientX, event.clientY );
\r
523 rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
\r
525 var element = scope.domElement;
\r
527 rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
\r
529 rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
\r
531 rotateStart.copy( rotateEnd );
\r
537 function handleMouseMoveDolly( event ) {
\r
539 dollyEnd.set( event.clientX, event.clientY );
\r
541 dollyDelta.subVectors( dollyEnd, dollyStart );
\r
543 if ( dollyDelta.y > 0 ) {
\r
545 dollyOut( getZoomScale() );
\r
547 } else if ( dollyDelta.y < 0 ) {
\r
549 dollyIn( getZoomScale() );
\r
553 dollyStart.copy( dollyEnd );
\r
559 function handleMouseMovePan( event ) {
\r
561 panEnd.set( event.clientX, event.clientY );
\r
563 panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
\r
565 pan( panDelta.x, panDelta.y );
\r
567 panStart.copy( panEnd );
\r
573 function handleMouseUp( /*event*/ ) {
\r
579 function handleMouseWheel( event ) {
\r
581 if ( event.deltaY < 0 ) {
\r
583 dollyIn( getZoomScale() );
\r
585 } else if ( event.deltaY > 0 ) {
\r
587 dollyOut( getZoomScale() );
\r
595 function handleKeyDown( event ) {
\r
597 var needsUpdate = false;
\r
599 switch ( event.keyCode ) {
\r
601 case scope.keys.UP:
\r
602 pan( 0, scope.keyPanSpeed );
\r
603 needsUpdate = true;
\r
606 case scope.keys.BOTTOM:
\r
607 pan( 0, - scope.keyPanSpeed );
\r
608 needsUpdate = true;
\r
611 case scope.keys.LEFT:
\r
612 pan( scope.keyPanSpeed, 0 );
\r
613 needsUpdate = true;
\r
616 case scope.keys.RIGHT:
\r
617 pan( - scope.keyPanSpeed, 0 );
\r
618 needsUpdate = true;
\r
623 if ( needsUpdate ) {
\r
625 // prevent the browser from scrolling on cursor keys
\r
626 event.preventDefault();
\r
635 function handleTouchStartRotate( event ) {
\r
637 if ( event.touches.length == 1 ) {
\r
639 rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
\r
643 var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
\r
644 var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
\r
646 rotateStart.set( x, y );
\r
652 function handleTouchStartPan( event ) {
\r
654 if ( event.touches.length == 1 ) {
\r
656 panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
\r
660 var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
\r
661 var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
\r
663 panStart.set( x, y );
\r
669 function handleTouchStartDolly( event ) {
\r
671 var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
\r
672 var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
\r
674 var distance = Math.sqrt( dx * dx + dy * dy );
\r
676 dollyStart.set( 0, distance );
\r
680 function handleTouchStartDollyPan( event ) {
\r
682 if ( scope.enableZoom ) handleTouchStartDolly( event );
\r
684 if ( scope.enablePan ) handleTouchStartPan( event );
\r
688 function handleTouchStartDollyRotate( event ) {
\r
690 if ( scope.enableZoom ) handleTouchStartDolly( event );
\r
692 if ( scope.enableRotate ) handleTouchStartRotate( event );
\r
696 function handleTouchMoveRotate( event ) {
\r
698 if ( event.touches.length == 1 ) {
\r
700 rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
\r
704 var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
\r
705 var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
\r
707 rotateEnd.set( x, y );
\r
711 rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
\r
713 var element = scope.domElement;
\r
715 rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
\r
717 rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
\r
719 rotateStart.copy( rotateEnd );
\r
723 function handleTouchMovePan( event ) {
\r
725 if ( event.touches.length == 1 ) {
\r
727 panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
\r
731 var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
\r
732 var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
\r
734 panEnd.set( x, y );
\r
738 panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
\r
740 pan( panDelta.x, panDelta.y );
\r
742 panStart.copy( panEnd );
\r
746 function handleTouchMoveDolly( event ) {
\r
748 var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
\r
749 var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
\r
751 var distance = Math.sqrt( dx * dx + dy * dy );
\r
753 dollyEnd.set( 0, distance );
\r
755 dollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) );
\r
757 dollyOut( dollyDelta.y );
\r
759 dollyStart.copy( dollyEnd );
\r
763 function handleTouchMoveDollyPan( event ) {
\r
765 if ( scope.enableZoom ) handleTouchMoveDolly( event );
\r
767 if ( scope.enablePan ) handleTouchMovePan( event );
\r
771 function handleTouchMoveDollyRotate( event ) {
\r
773 if ( scope.enableZoom ) handleTouchMoveDolly( event );
\r
775 if ( scope.enableRotate ) handleTouchMoveRotate( event );
\r
779 function handleTouchEnd( /*event*/ ) {
\r
786 // event handlers - FSM: listen for events and reset state
\r
789 function onPointerDown( event ) {
\r
791 if ( scope.enabled === false ) return;
\r
793 switch ( event.pointerType ) {
\r
797 onMouseDown( event );
\r
806 function onPointerMove( event ) {
\r
808 if ( scope.enabled === false ) return;
\r
810 switch ( event.pointerType ) {
\r
814 onMouseMove( event );
\r
823 function onPointerUp( event ) {
\r
825 switch ( event.pointerType ) {
\r
829 onMouseUp( event );
\r
838 function onMouseDown( event ) {
\r
840 // Prevent the browser from scrolling.
\r
841 event.preventDefault();
\r
843 // Manually set the focus since calling preventDefault above
\r
844 // prevents the browser from setting it automatically.
\r
846 scope.domElement.focus ? scope.domElement.focus() : window.focus();
\r
850 switch ( event.button ) {
\r
854 mouseAction = scope.mouseButtons.LEFT;
\r
859 mouseAction = scope.mouseButtons.MIDDLE;
\r
864 mouseAction = scope.mouseButtons.RIGHT;
\r
873 switch ( mouseAction ) {
\r
877 if ( scope.enableZoom === false ) return;
\r
879 handleMouseDownDolly( event );
\r
881 state = STATE.DOLLY;
\r
887 if ( event.ctrlKey || event.metaKey || event.shiftKey ) {
\r
889 if ( scope.enablePan === false ) return;
\r
891 handleMouseDownPan( event );
\r
897 if ( scope.enableRotate === false ) return;
\r
899 handleMouseDownRotate( event );
\r
901 state = STATE.ROTATE;
\r
909 if ( event.ctrlKey || event.metaKey || event.shiftKey ) {
\r
911 if ( scope.enableRotate === false ) return;
\r
913 handleMouseDownRotate( event );
\r
915 state = STATE.ROTATE;
\r
919 if ( scope.enablePan === false ) return;
\r
921 handleMouseDownPan( event );
\r
931 state = STATE.NONE;
\r
935 if ( state !== STATE.NONE ) {
\r
937 scope.domElement.ownerDocument.addEventListener( 'pointermove', onPointerMove );
\r
938 scope.domElement.ownerDocument.addEventListener( 'pointerup', onPointerUp );
\r
940 scope.dispatchEvent( startEvent );
\r
946 function onMouseMove( event ) {
\r
948 if ( scope.enabled === false ) return;
\r
950 event.preventDefault();
\r
956 if ( scope.enableRotate === false ) return;
\r
958 handleMouseMoveRotate( event );
\r
964 if ( scope.enableZoom === false ) return;
\r
966 handleMouseMoveDolly( event );
\r
972 if ( scope.enablePan === false ) return;
\r
974 handleMouseMovePan( event );
\r
982 function onMouseUp( event ) {
\r
984 scope.domElement.ownerDocument.removeEventListener( 'pointermove', onPointerMove );
\r
985 scope.domElement.ownerDocument.removeEventListener( 'pointerup', onPointerUp );
\r
987 if ( scope.enabled === false ) return;
\r
989 handleMouseUp( event );
\r
991 scope.dispatchEvent( endEvent );
\r
993 state = STATE.NONE;
\r
997 function onMouseWheel( event ) {
\r
999 if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return;
\r
1001 event.preventDefault();
\r
1002 event.stopPropagation();
\r
1004 scope.dispatchEvent( startEvent );
\r
1006 handleMouseWheel( event );
\r
1008 scope.dispatchEvent( endEvent );
\r
1012 function onKeyDown( event ) {
\r
1014 if ( scope.enabled === false || scope.enablePan === false ) return;
\r
1016 handleKeyDown( event );
\r
1020 function onTouchStart( event ) {
\r
1022 if ( scope.enabled === false ) return;
\r
1024 event.preventDefault(); // prevent scrolling
\r
1026 switch ( event.touches.length ) {
\r
1030 switch ( scope.touches.ONE ) {
\r
1032 case TOUCH.ROTATE:
\r
1034 if ( scope.enableRotate === false ) return;
\r
1036 handleTouchStartRotate( event );
\r
1038 state = STATE.TOUCH_ROTATE;
\r
1044 if ( scope.enablePan === false ) return;
\r
1046 handleTouchStartPan( event );
\r
1048 state = STATE.TOUCH_PAN;
\r
1054 state = STATE.NONE;
\r
1062 switch ( scope.touches.TWO ) {
\r
1064 case TOUCH.DOLLY_PAN:
\r
1066 if ( scope.enableZoom === false && scope.enablePan === false ) return;
\r
1068 handleTouchStartDollyPan( event );
\r
1070 state = STATE.TOUCH_DOLLY_PAN;
\r
1074 case TOUCH.DOLLY_ROTATE:
\r
1076 if ( scope.enableZoom === false && scope.enableRotate === false ) return;
\r
1078 handleTouchStartDollyRotate( event );
\r
1080 state = STATE.TOUCH_DOLLY_ROTATE;
\r
1086 state = STATE.NONE;
\r
1094 state = STATE.NONE;
\r
1098 if ( state !== STATE.NONE ) {
\r
1100 scope.dispatchEvent( startEvent );
\r
1106 function onTouchMove( event ) {
\r
1108 if ( scope.enabled === false ) return;
\r
1110 event.preventDefault(); // prevent scrolling
\r
1111 event.stopPropagation();
\r
1113 switch ( state ) {
\r
1115 case STATE.TOUCH_ROTATE:
\r
1117 if ( scope.enableRotate === false ) return;
\r
1119 handleTouchMoveRotate( event );
\r
1125 case STATE.TOUCH_PAN:
\r
1127 if ( scope.enablePan === false ) return;
\r
1129 handleTouchMovePan( event );
\r
1135 case STATE.TOUCH_DOLLY_PAN:
\r
1137 if ( scope.enableZoom === false && scope.enablePan === false ) return;
\r
1139 handleTouchMoveDollyPan( event );
\r
1145 case STATE.TOUCH_DOLLY_ROTATE:
\r
1147 if ( scope.enableZoom === false && scope.enableRotate === false ) return;
\r
1149 handleTouchMoveDollyRotate( event );
\r
1157 state = STATE.NONE;
\r
1163 function onTouchEnd( event ) {
\r
1165 if ( scope.enabled === false ) return;
\r
1167 handleTouchEnd( event );
\r
1169 scope.dispatchEvent( endEvent );
\r
1171 state = STATE.NONE;
\r
1175 function onContextMenu( event ) {
\r
1177 if ( scope.enabled === false ) return;
\r
1179 event.preventDefault();
\r
1185 scope.domElement.addEventListener( 'contextmenu', onContextMenu );
\r
1187 scope.domElement.addEventListener( 'pointerdown', onPointerDown );
\r
1188 scope.domElement.addEventListener( 'wheel', onMouseWheel );
\r
1190 scope.domElement.addEventListener( 'touchstart', onTouchStart );
\r
1191 scope.domElement.addEventListener( 'touchend', onTouchEnd );
\r
1192 scope.domElement.addEventListener( 'touchmove', onTouchMove );
\r
1194 // force an update at start
\r
1200 OrbitControls.prototype = Object.create( EventDispatcher.prototype );
\r
1201 OrbitControls.prototype.constructor = OrbitControls;
\r
1204 // This set of controls performs orbiting, dollying (zooming), and panning.
\r
1205 // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
\r
1206 // This is very similar to OrbitControls, another set of touch behavior
\r
1208 // Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate
\r
1209 // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
\r
1210 // Pan - left mouse, or arrow keys / touch: one-finger move
\r
1212 var MapControls = function ( object, domElement ) {
\r
1214 OrbitControls.call( this, object, domElement );
\r
1216 this.screenSpacePanning = false; // pan orthogonal to world-space direction camera.up
\r
1218 this.mouseButtons.LEFT = MOUSE.PAN;
\r
1219 this.mouseButtons.RIGHT = MOUSE.ROTATE;
\r
1221 this.touches.ONE = TOUCH.PAN;
\r
1222 this.touches.TWO = TOUCH.DOLLY_ROTATE;
\r
1226 MapControls.prototype = Object.create( EventDispatcher.prototype );
\r
1227 MapControls.prototype.constructor = MapControls;
\r
1229 export { OrbitControls, MapControls };