aboutsummaryrefslogtreecommitdiff
path: root/lib/OrbitControls.js
diff options
context:
space:
mode:
authorFederico Igne <git@federicoigne.com>2022-08-13 11:33:30 +0100
committerFederico Igne <git@federicoigne.com>2022-08-13 11:33:30 +0100
commit2fd9cc46ff2428bb2fa891f47002e9d3e7585583 (patch)
tree81b8b0122a00e9cd06d5f55091a3b087e430ddb0 /lib/OrbitControls.js
downloadrubik-2fd9cc46ff2428bb2fa891f47002e9d3e7585583.tar.gz
rubik-2fd9cc46ff2428bb2fa891f47002e9d3e7585583.zip
init: import project
Diffstat (limited to 'lib/OrbitControls.js')
-rwxr-xr-xlib/OrbitControls.js625
1 files changed, 625 insertions, 0 deletions
diff --git a/lib/OrbitControls.js b/lib/OrbitControls.js
new file mode 100755
index 0000000..56c1f8b
--- /dev/null
+++ b/lib/OrbitControls.js
@@ -0,0 +1,625 @@
1/**
2 * @author qiao / https://github.com/qiao
3 * @author mrdoob / http://mrdoob.com
4 * @author alteredq / http://alteredqualia.com/
5 * @author WestLangley / http://github.com/WestLangley
6 * @author erich666 / http://erichaines.com
7 */
8/*global THREE, console */
9
10// This set of controls performs orbiting, dollying (zooming), and panning. It maintains
11// the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is
12// supported.
13//
14// Orbit - left mouse / touch: one finger move
15// Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
16// Pan - right mouse, or arrow keys / touch: three finter swipe
17//
18// This is a drop-in replacement for (most) TrackballControls used in examples.
19// That is, include this js file and wherever you see:
20// controls = new THREE.TrackballControls( camera );
21// controls.target.z = 150;
22// Simple substitute "OrbitControls" and the control should work as-is.
23
24THREE.OrbitControls = function ( object, domElement ) {
25
26 this.object = object;
27 this.domElement = ( domElement !== undefined ) ? domElement : document;
28
29 // API
30
31 // Set to false to disable this control
32 this.enabled = true;
33
34 // "target" sets the location of focus, where the control orbits around
35 // and where it pans with respect to.
36 this.target = new THREE.Vector3();
37
38 // center is old, deprecated; use "target" instead
39 this.center = this.target;
40
41 // This option actually enables dollying in and out; left as "zoom" for
42 // backwards compatibility
43 this.noZoom = false;
44 this.zoomSpeed = 1.0;
45
46 // Limits to how far you can dolly in and out
47 this.minDistance = 0;
48 this.maxDistance = Infinity;
49
50 // Set to true to disable this control
51 this.noRotate = false;
52 this.rotateSpeed = 1.0;
53
54 // Set to true to disable this control
55 this.noPan = false;
56 this.keyPanSpeed = 7.0; // pixels moved per arrow key push
57
58 // Set to true to automatically rotate around the target
59 this.autoRotate = false;
60 this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
61
62 // How far you can orbit vertically, upper and lower limits.
63 // Range is 0 to Math.PI radians.
64 this.minPolarAngle = 0; // radians
65 this.maxPolarAngle = Math.PI; // radians
66
67 // Set to true to disable use of the keys
68 this.noKeys = false;
69
70 // The four arrow keys
71 this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
72
73 ////////////
74 // internals
75
76 var scope = this;
77
78 var EPS = 0.000001;
79
80 var rotateStart = new THREE.Vector2();
81 var rotateEnd = new THREE.Vector2();
82 var rotateDelta = new THREE.Vector2();
83
84 var panStart = new THREE.Vector2();
85 var panEnd = new THREE.Vector2();
86 var panDelta = new THREE.Vector2();
87 var panOffset = new THREE.Vector3();
88
89 var offset = new THREE.Vector3();
90
91 var dollyStart = new THREE.Vector2();
92 var dollyEnd = new THREE.Vector2();
93 var dollyDelta = new THREE.Vector2();
94
95 var phiDelta = 0;
96 var thetaDelta = 0;
97 var scale = 1;
98 var pan = new THREE.Vector3();
99
100 var lastPosition = new THREE.Vector3();
101
102 var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
103
104 var state = STATE.NONE;
105
106 // for reset
107
108 this.target0 = this.target.clone();
109 this.position0 = this.object.position.clone();
110
111 // events
112
113 var changeEvent = { type: 'change' };
114 var startEvent = { type: 'start'};
115 var endEvent = { type: 'end'};
116
117 this.rotateLeft = function ( angle ) {
118
119 if ( angle === undefined ) {
120
121 angle = getAutoRotationAngle();
122
123 }
124
125 thetaDelta -= angle;
126
127 };
128
129 this.rotateUp = function ( angle ) {
130
131 if ( angle === undefined ) {
132
133 angle = getAutoRotationAngle();
134
135 }
136
137 phiDelta -= angle;
138
139 };
140
141 // pass in distance in world space to move left
142 this.panLeft = function ( distance ) {
143
144 var te = this.object.matrix.elements;
145
146 // get X column of matrix
147 panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] );
148 panOffset.multiplyScalar( - distance );
149
150 pan.add( panOffset );
151
152 };
153
154 // pass in distance in world space to move up
155 this.panUp = function ( distance ) {
156
157 var te = this.object.matrix.elements;
158
159 // get Y column of matrix
160 panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] );
161 panOffset.multiplyScalar( distance );
162
163 pan.add( panOffset );
164
165 };
166
167 // pass in x,y of change desired in pixel space,
168 // right and down are positive
169 this.pan = function ( deltaX, deltaY ) {
170
171 var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
172
173 if ( scope.object.fov !== undefined ) {
174
175 // perspective
176 var position = scope.object.position;
177 var offset = position.clone().sub( scope.target );
178 var targetDistance = offset.length();
179
180 // half of the fov is center to top of screen
181 targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
182
183 // we actually don't use screenWidth, since perspective camera is fixed to screen height
184 scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight );
185 scope.panUp( 2 * deltaY * targetDistance / element.clientHeight );
186
187 } else if ( scope.object.top !== undefined ) {
188
189 // orthographic
190 scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth );
191 scope.panUp( deltaY * (scope.object.top - scope.object.bottom) / element.clientHeight );
192
193 } else {
194
195 // camera neither orthographic or perspective
196 console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
197
198 }
199
200 };
201
202 this.dollyIn = function ( dollyScale ) {
203
204 if ( dollyScale === undefined ) {
205
206 dollyScale = getZoomScale();
207
208 }
209
210 scale /= dollyScale;
211
212 };
213
214 this.dollyOut = function ( dollyScale ) {
215
216 if ( dollyScale === undefined ) {
217
218 dollyScale = getZoomScale();
219
220 }
221
222 scale *= dollyScale;
223
224 };
225
226 this.update = function () {
227
228 var position = this.object.position;
229
230 offset.copy( position ).sub( this.target );
231
232 // angle from z-axis around y-axis
233
234 var theta = Math.atan2( offset.x, offset.z );
235
236 // angle from y-axis
237
238 var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
239
240 if ( this.autoRotate ) {
241
242 this.rotateLeft( getAutoRotationAngle() );
243
244 }
245
246 theta += thetaDelta;
247 phi += phiDelta;
248
249 // restrict phi to be between desired limits
250 phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
251
252 // restrict phi to be betwee EPS and PI-EPS
253 phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
254
255 var radius = offset.length() * scale;
256
257 // restrict radius to be between desired limits
258 radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
259
260 // move target to panned location
261 this.target.add( pan );
262
263 offset.x = radius * Math.sin( phi ) * Math.sin( theta );
264 offset.y = radius * Math.cos( phi );
265 offset.z = radius * Math.sin( phi ) * Math.cos( theta );
266
267 position.copy( this.target ).add( offset );
268
269 this.object.lookAt( this.target );
270
271 thetaDelta = 0;
272 phiDelta = 0;
273 scale = 1;
274 pan.set( 0, 0, 0 );
275
276 if ( lastPosition.distanceTo( this.object.position ) > 0 ) {
277
278 this.dispatchEvent( changeEvent );
279
280 lastPosition.copy( this.object.position );
281
282 }
283
284 };
285
286
287 this.reset = function () {
288
289 state = STATE.NONE;
290
291 this.target.copy( this.target0 );
292 this.object.position.copy( this.position0 );
293
294 this.update();
295
296 };
297
298 function getAutoRotationAngle() {
299
300 return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
301
302 }
303
304 function getZoomScale() {
305
306 return Math.pow( 0.95, scope.zoomSpeed );
307
308 }
309
310 function onMouseDown( event ) {
311
312 if ( scope.enabled === false ) return;
313 event.preventDefault();
314
315 if ( event.button === 0 ) {
316 if ( scope.noRotate === true ) return;
317
318 state = STATE.ROTATE;
319
320 rotateStart.set( event.clientX, event.clientY );
321
322 } else if ( event.button === 1 ) {
323 if ( scope.noZoom === true ) return;
324
325 state = STATE.DOLLY;
326
327 dollyStart.set( event.clientX, event.clientY );
328
329 } else if ( event.button === 2 ) {
330 if ( scope.noPan === true ) return;
331
332 state = STATE.PAN;
333
334 panStart.set( event.clientX, event.clientY );
335
336 }
337
338 scope.domElement.addEventListener( 'mousemove', onMouseMove, false );
339 scope.domElement.addEventListener( 'mouseup', onMouseUp, false );
340 scope.dispatchEvent( startEvent );
341
342 }
343
344 function onMouseMove( event ) {
345
346 if ( scope.enabled === false ) return;
347
348 event.preventDefault();
349
350 var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
351
352 if ( state === STATE.ROTATE ) {
353
354 if ( scope.noRotate === true ) return;
355
356 rotateEnd.set( event.clientX, event.clientY );
357 rotateDelta.subVectors( rotateEnd, rotateStart );
358
359 // rotating across whole screen goes 360 degrees around
360 scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
361
362 // rotating up and down along whole screen attempts to go 360, but limited to 180
363 scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
364
365 rotateStart.copy( rotateEnd );
366
367 } else if ( state === STATE.DOLLY ) {
368
369 if ( scope.noZoom === true ) return;
370
371 dollyEnd.set( event.clientX, event.clientY );
372 dollyDelta.subVectors( dollyEnd, dollyStart );
373
374 if ( dollyDelta.y > 0 ) {
375
376 scope.dollyIn();
377
378 } else {
379
380 scope.dollyOut();
381
382 }
383
384 dollyStart.copy( dollyEnd );
385
386 } else if ( state === STATE.PAN ) {
387
388 if ( scope.noPan === true ) return;
389
390 panEnd.set( event.clientX, event.clientY );
391 panDelta.subVectors( panEnd, panStart );
392
393 scope.pan( panDelta.x, panDelta.y );
394
395 panStart.copy( panEnd );
396
397 }
398
399 scope.update();
400
401 }
402
403 function onMouseUp( /* event */ ) {
404
405 if ( scope.enabled === false ) return;
406
407 scope.domElement.removeEventListener( 'mousemove', onMouseMove, false );
408 scope.domElement.removeEventListener( 'mouseup', onMouseUp, false );
409 scope.dispatchEvent( endEvent );
410 state = STATE.NONE;
411
412 }
413
414 function onMouseWheel( event ) {
415
416 if ( scope.enabled === false || scope.noZoom === true ) return;
417
418 event.preventDefault();
419
420 var delta = 0;
421
422 if ( event.wheelDelta !== undefined ) { // WebKit / Opera / Explorer 9
423
424 delta = event.wheelDelta;
425
426 } else if ( event.detail !== undefined ) { // Firefox
427
428 delta = - event.detail;
429
430 }
431
432 if ( delta > 0 ) {
433
434 scope.dollyOut();
435
436 } else {
437
438 scope.dollyIn();
439
440 }
441
442 scope.update();
443 scope.dispatchEvent( startEvent );
444 scope.dispatchEvent( endEvent );
445
446 }
447
448 function onKeyDown( event ) {
449
450 if ( scope.enabled === false || scope.noKeys === true || scope.noPan === true ) return;
451
452 switch ( event.keyCode ) {
453
454 case scope.keys.UP:
455 scope.pan( 0, scope.keyPanSpeed );
456 scope.update();
457 break;
458
459 case scope.keys.BOTTOM:
460 scope.pan( 0, - scope.keyPanSpeed );
461 scope.update();
462 break;
463
464 case scope.keys.LEFT:
465 scope.pan( scope.keyPanSpeed, 0 );
466 scope.update();
467 break;
468
469 case scope.keys.RIGHT:
470 scope.pan( - scope.keyPanSpeed, 0 );
471 scope.update();
472 break;
473
474 }
475
476 }
477
478 function touchstart( event ) {
479
480 if ( scope.enabled === false ) return;
481
482 switch ( event.touches.length ) {
483
484 case 1: // one-fingered touch: rotate
485
486 if ( scope.noRotate === true ) return;
487
488 state = STATE.TOUCH_ROTATE;
489
490 rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
491 break;
492
493 case 2: // two-fingered touch: dolly
494
495 if ( scope.noZoom === true ) return;
496
497 state = STATE.TOUCH_DOLLY;
498
499 var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
500 var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
501 var distance = Math.sqrt( dx * dx + dy * dy );
502 dollyStart.set( 0, distance );
503 break;
504
505 case 3: // three-fingered touch: pan
506
507 if ( scope.noPan === true ) return;
508
509 state = STATE.TOUCH_PAN;
510
511 panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
512 break;
513
514 default:
515
516 state = STATE.NONE;
517
518 }
519
520 scope.dispatchEvent( startEvent );
521
522 }
523
524 function touchmove( event ) {
525
526 if ( scope.enabled === false ) return;
527
528 event.preventDefault();
529 event.stopPropagation();
530
531 var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
532
533 switch ( event.touches.length ) {
534
535 case 1: // one-fingered touch: rotate
536
537 if ( scope.noRotate === true ) return;
538 if ( state !== STATE.TOUCH_ROTATE ) return;
539
540 rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
541 rotateDelta.subVectors( rotateEnd, rotateStart );
542
543 // rotating across whole screen goes 360 degrees around
544 scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
545 // rotating up and down along whole screen attempts to go 360, but limited to 180
546 scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
547
548 rotateStart.copy( rotateEnd );
549
550 scope.update();
551 break;
552
553 case 2: // two-fingered touch: dolly
554
555 if ( scope.noZoom === true ) return;
556 if ( state !== STATE.TOUCH_DOLLY ) return;
557
558 var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
559 var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
560 var distance = Math.sqrt( dx * dx + dy * dy );
561
562 dollyEnd.set( 0, distance );
563 dollyDelta.subVectors( dollyEnd, dollyStart );
564
565 if ( dollyDelta.y > 0 ) {
566
567 scope.dollyOut();
568
569 } else {
570
571 scope.dollyIn();
572
573 }
574
575 dollyStart.copy( dollyEnd );
576
577 scope.update();
578 break;
579
580 case 3: // three-fingered touch: pan
581
582 if ( scope.noPan === true ) return;
583 if ( state !== STATE.TOUCH_PAN ) return;
584
585 panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
586 panDelta.subVectors( panEnd, panStart );
587
588 scope.pan( panDelta.x, panDelta.y );
589
590 panStart.copy( panEnd );
591
592 scope.update();
593 break;
594
595 default:
596
597 state = STATE.NONE;
598
599 }
600
601 }
602
603 function touchend( /* event */ ) {
604
605 if ( scope.enabled === false ) return;
606
607 scope.dispatchEvent( endEvent );
608 state = STATE.NONE;
609
610 }
611
612 this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
613 this.domElement.addEventListener( 'mousedown', onMouseDown, false );
614 this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
615 this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
616
617 this.domElement.addEventListener( 'touchstart', touchstart, false );
618 this.domElement.addEventListener( 'touchend', touchend, false );
619 this.domElement.addEventListener( 'touchmove', touchmove, false );
620
621 window.addEventListener( 'keydown', onKeyDown, false );
622
623};
624
625THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );