1/** 2 * @author Eberhard Graether / http://egraether.com/ 3 * @author Mark Lundin / http://mark-lundin.com 4 * @author Patrick Fuller / http://patrick-fuller.com 5 * @author Max Smolens / https://github.com/msmolens 6 */ 7 8THREE.OrthographicTrackballControls = function ( object, domElement ) { 9 10 var _this = this; 11 var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }; 12 13 this.object = object; 14 this.domElement = ( domElement !== undefined ) ? domElement : document; 15 16 // API 17 18 this.enabled = true; 19 20 this.screen = { left: 0, top: 0, width: 0, height: 0 }; 21 22 this.radius = 0; 23 24 this.rotateSpeed = 1.0; 25 this.zoomSpeed = 1.2; 26 27 this.noRotate = false; 28 this.noZoom = false; 29 this.noPan = false; 30 this.noRoll = false; 31 32 this.staticMoving = false; 33 this.dynamicDampingFactor = 0.2; 34 35 this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; 36 37 // internals 38 39 this.target = new THREE.Vector3(); 40 41 var EPS = 0.000001; 42 43 var _changed = true; 44 45 var _state = STATE.NONE, 46 _prevState = STATE.NONE, 47 48 _eye = new THREE.Vector3(), 49 50 _rotateStart = new THREE.Vector3(), 51 _rotateEnd = new THREE.Vector3(), 52 53 _zoomStart = new THREE.Vector2(), 54 _zoomEnd = new THREE.Vector2(), 55 56 _touchZoomDistanceStart = 0, 57 _touchZoomDistanceEnd = 0, 58 59 _panStart = new THREE.Vector2(), 60 _panEnd = new THREE.Vector2(); 61 62 // for reset 63 64 this.target0 = this.target.clone(); 65 this.position0 = this.object.position.clone(); 66 this.up0 = this.object.up.clone(); 67 68 this.left0 = this.object.left; 69 this.right0 = this.object.right; 70 this.top0 = this.object.top; 71 this.bottom0 = this.object.bottom; 72 73 // events 74 75 var changeEvent = { type: 'change' }; 76 var startEvent = { type: 'start' }; 77 var endEvent = { type: 'end' }; 78 79 80 // methods 81 82 this.handleResize = function () { 83 84 if ( this.domElement === document ) { 85 86 this.screen.left = 0; 87 this.screen.top = 0; 88 this.screen.width = window.innerWidth; 89 this.screen.height = window.innerHeight; 90 91 } else { 92 93 var box = this.domElement.getBoundingClientRect(); 94 // adjustments come from similar code in the jquery offset() function 95 var d = this.domElement.ownerDocument.documentElement; 96 this.screen.left = box.left + window.pageXOffset - d.clientLeft; 97 this.screen.top = box.top + window.pageYOffset - d.clientTop; 98 this.screen.width = box.width; 99 this.screen.height = box.height; 100 101 } 102 103 this.radius = 0.5 * Math.min( this.screen.width, this.screen.height ); 104 105 this.left0 = this.object.left; 106 this.right0 = this.object.right; 107 this.top0 = this.object.top; 108 this.bottom0 = this.object.bottom; 109 110 }; 111 112 var getMouseOnScreen = ( function () { 113 114 var vector = new THREE.Vector2(); 115 116 return function getMouseOnScreen( pageX, pageY ) { 117 118 vector.set( 119 ( pageX - _this.screen.left ) / _this.screen.width, 120 ( pageY - _this.screen.top ) / _this.screen.height 121 ); 122 123 return vector; 124 125 }; 126 127 }() ); 128 129 var getMouseProjectionOnBall = ( function () { 130 131 var vector = new THREE.Vector3(); 132 var objectUp = new THREE.Vector3(); 133 var mouseOnBall = new THREE.Vector3(); 134 135 return function getMouseProjectionOnBall( pageX, pageY ) { 136 137 mouseOnBall.set( 138 ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / _this.radius, 139 ( _this.screen.height * 0.5 + _this.screen.top - pageY ) / _this.radius, 140 0.0 141 ); 142 143 var length = mouseOnBall.length(); 144 145 if ( _this.noRoll ) { 146 147 if ( length < Math.SQRT1_2 ) { 148 149 mouseOnBall.z = Math.sqrt( 1.0 - length * length ); 150 151 } else { 152 153 mouseOnBall.z = .5 / length; 154 155 } 156 157 } else if ( length > 1.0 ) { 158 159 mouseOnBall.normalize(); 160 161 } else { 162 163 mouseOnBall.z = Math.sqrt( 1.0 - length * length ); 164 165 } 166 167 _eye.copy( _this.object.position ).sub( _this.target ); 168 169 vector.copy( _this.object.up ).setLength( mouseOnBall.y ); 170 vector.add( objectUp.copy( _this.object.up ).cross( _eye ).setLength( mouseOnBall.x ) ); 171 vector.add( _eye.setLength( mouseOnBall.z ) ); 172 173 return vector; 174 175 }; 176 177 }() ); 178 179 this.rotateCamera = ( function () { 180 181 var axis = new THREE.Vector3(), 182 quaternion = new THREE.Quaternion(); 183 184 185 return function rotateCamera() { 186
187 var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() ); 188 189 if ( angle ) { 190 191 axis.crossVectors( _rotateStart, _rotateEnd ).normalize(); 192 193 angle *= _this.rotateSpeed; 194 195 quaternion.setFromAxisAngle( axis, - angle ); 196 197 _eye.applyQuaternion( quaternion ); 198 _this.object.up.applyQuaternion( quaternion ); 199 200 _rotateEnd.applyQuaternion( quaternion ); 201 202 if ( _this.staticMoving ) { 203 204 _rotateStart.copy( _rotateEnd ); 205 206 } else { 207 208 quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) ); 209 _rotateStart.applyQuaternion( quaternion ); 210 211 } 212 213 _changed = true; 214 215 } 216 217 }; 218 219 }() ); 220 221 this.zoomCamera = function () { 222 223 if ( _state === STATE.TOUCH_ZOOM_PAN ) { 224 225 var factor = _touchZoomDistanceEnd / _touchZoomDistanceStart; 226 _touchZoomDistanceStart = _touchZoomDistanceEnd; 227 228 _this.object.zoom *= factor; 229 230 _changed = true; 231 232 } else { 233 234 var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed; 235 236 if ( Math.abs( factor - 1.0 ) > EPS && factor > 0.0 ) { 237 238 _this.object.zoom /= factor; 239 240 if ( _this.staticMoving ) { 241 242 _zoomStart.copy( _zoomEnd ); 243 244 } else { 245 246 _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor; 247 248 } 249 250 _changed = true; 251 252 } 253 254 } 255 256 }; 257 258 this.panCamera = ( function () { 259 260 var mouseChange = new THREE.Vector2(), 261 objectUp = new THREE.Vector3(), 262 pan = new THREE.Vector3(); 263 264 return function panCamera() { 265 266 mouseChange.copy( _panEnd ).sub( _panStart ); 267 268 if ( mouseChange.lengthSq() ) { 269 270 // Scale movement to keep clicked/dragged position under cursor 271 var scale_x = ( _this.object.right - _this.object.left ) / _this.object.zoom; 272 var scale_y = ( _this.object.top - _this.object.bottom ) / _this.object.zoom; 273 mouseChange.x *= scale_x; 274 mouseChange.y *= scale_y; 275 276 pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x ); 277 pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) ); 278 279 _this.object.position.add( pan ); 280 _this.target.add( pan ); 281 282 if ( _this.staticMoving ) { 283 284 _panStart.copy( _panEnd ); 285 286 } else { 287 288 _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) ); 289 290 } 291 292 _changed = true; 293 294 } 295 296 }; 297 298 }() ); 299 300 this.update = function () { 301 302 _eye.subVectors( _this.object.position, _this.target ); 303 304 if ( ! _this.noRotate ) { 305 306 _this.rotateCamera(); 307 308 } 309 310 if ( ! _this.noZoom ) { 311 312 _this.zoomCamera(); 313 314 if ( _changed ) { 315 316 _this.object.updateProjectionMatrix(); 317 318 } 319 320 } 321 322 if ( ! _this.noPan ) { 323 324 _this.panCamera(); 325 326 } 327 328 _this.object.position.addVectors( _this.target, _eye ); 329 330 _this.object.lookAt( _this.target ); 331 332 if ( _changed ) { 333 334 _this.dispatchEvent( changeEvent ); 335 336 _changed = false; 337 338 } 339 340 }; 341 342 this.reset = function () { 343 344 _state = STATE.NONE; 345 _prevState = STATE.NONE; 346 347 _this.target.copy( _this.target0 ); 348 _this.object.position.copy( _this.position0 ); 349 _this.object.up.copy( _this.up0 ); 350 351 _eye.subVectors( _this.object.position, _this.target ); 352 353 _this.object.left = _this.left0; 354 _this.object.right = _this.right0; 355 _this.object.top = _this.top0; 356 _this.object.bottom = _this.bottom0; 357 358 _this.object.lookAt( _this.target ); 359 360 _this.dispatchEvent( changeEvent ); 361 362 _changed = false;
363 364 }; 365 366 // listeners 367 368 function keydown( event ) { 369 370 if ( _this.enabled === false ) return; 371 372 window.removeEventListener( 'keydown', keydown ); 373 374 _prevState = _state; 375 376 if ( _state !== STATE.NONE ) { 377 378 return; 379 380 } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && ! _this.noRotate ) { 381 382 _state = STATE.ROTATE; 383 384 } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && ! _this.noZoom ) { 385 386 _state = STATE.ZOOM; 387 388 } else if ( event.keyCode === _this.keys[ STATE.PAN ] && ! _this.noPan ) { 389 390 _state = STATE.PAN; 391 392 } 393 394 } 395 396 function keyup( event ) { 397 398 if ( _this.enabled === false ) return; 399 400 _state = _prevState; 401 402 window.addEventListener( 'keydown', keydown, false ); 403 404 } 405 406 function mousedown( event ) { 407 408 if ( _this.enabled === false ) return; 409 410 event.preventDefault(); 411 event.stopPropagation(); 412 413 if ( _state === STATE.NONE ) { 414 415 _state = event.button; 416 417 } 418 419 if ( _state === STATE.ROTATE && ! _this.noRotate ) { 420 421 _rotateStart.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) ); 422 _rotateEnd.copy( _rotateStart ); 423 424 } else if ( _state === STATE.ZOOM && ! _this.noZoom ) { 425 426 _zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 427 _zoomEnd.copy( _zoomStart ); 428 429 } else if ( _state === STATE.PAN && ! _this.noPan ) { 430 431 _panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 432 _panEnd.copy( _panStart ); 433 434 } 435 436 document.addEventListener( 'mousemove', mousemove, false ); 437 document.addEventListener( 'mouseup', mouseup, false ); 438 439 _this.dispatchEvent( startEvent ); 440 441 } 442 443 function mousemove( event ) { 444 445 if ( _this.enabled === false ) return; 446 447 event.preventDefault(); 448 event.stopPropagation(); 449 450 if ( _state === STATE.ROTATE && ! _this.noRotate ) { 451 452 _rotateEnd.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) ); 453 454 } else if ( _state === STATE.ZOOM && ! _this.noZoom ) { 455 456 _zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 457 458 } else if ( _state === STATE.PAN && ! _this.noPan ) { 459 460 _panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 461 462 } 463 464 } 465 466 function mouseup( event ) { 467 468 if ( _this.enabled === false ) return; 469 470 event.preventDefault(); 471 event.stopPropagation(); 472 473 _state = STATE.NONE; 474 475 document.removeEventListener( 'mousemove', mousemove ); 476 document.removeEventListener( 'mouseup', mouseup ); 477 _this.dispatchEvent( endEvent ); 478 479 } 480 481 function mousewheel( event ) { 482 483 if ( _this.enabled === false ) return; 484 485 event.preventDefault(); 486 event.stopPropagation(); 487 488 _zoomStart.y += event.deltaY * 0.01; 489 _this.dispatchEvent( startEvent ); 490 _this.dispatchEvent( endEvent ); 491 492 } 493 494 function touchstart( event ) { 495 496 if ( _this.enabled === false ) return; 497 498 switch ( event.touches.length ) { 499 500 case 1: 501 _state = STATE.TOUCH_ROTATE; 502 _rotateStart.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); 503 _rotateEnd.copy( _rotateStart ); 504 break; 505 506 case 2: 507 _state = STATE.TOUCH_ZOOM_PAN; 508 var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 509 var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 510 _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); 511 512 var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; 513 var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; 514 _panStart.copy( getMouseOnScreen( x, y ) ); 515 _panEnd.copy( _panStart ); 516 break; 517 518 default: 519 _state = STATE.NONE; 520 521 } 522 _this.dispatchEvent( startEvent ); 523 524 } 525 526 function touchmove( event ) { 527 528 if ( _this.enabled === false ) return; 529 530 event.preventDefault(); 531 event.stopPropagation(); 532 533 switch ( event.touches.length ) { 534 535 case 1: 536 _rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); 537 break; 538 539 case 2:
540 var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 541 var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 542 _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ); 543 544 var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; 545 var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; 546 _panEnd.copy( getMouseOnScreen( x, y ) ); 547 break; 548 549 default: 550 _state = STATE.NONE; 551 552 } 553 554 } 555 556 function touchend( event ) { 557 558 if ( _this.enabled === false ) return; 559 560 switch ( event.touches.length ) { 561 562 case 1: 563 _rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); 564 _rotateStart.copy( _rotateEnd ); 565 break; 566 567 case 2: 568 _touchZoomDistanceStart = _touchZoomDistanceEnd = 0; 569 570 var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; 571 var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; 572 _panEnd.copy( getMouseOnScreen( x, y ) ); 573 _panStart.copy( _panEnd ); 574 break; 575 576 } 577 578 _state = STATE.NONE; 579 _this.dispatchEvent( endEvent ); 580 581 } 582 583 function contextmenu( event ) { 584 585 event.preventDefault(); 586 587 } 588 589 this.dispose = function () { 590 591 this.domElement.removeEventListener( 'contextmenu', contextmenu, false ); 592 this.domElement.removeEventListener( 'mousedown', mousedown, false ); 593 this.domElement.removeEventListener( 'wheel', mousewheel, false ); 594 595 this.domElement.removeEventListener( 'touchstart', touchstart, false ); 596 this.domElement.removeEventListener( 'touchend', touchend, false ); 597 this.domElement.removeEventListener( 'touchmove', touchmove, false ); 598 599 document.removeEventListener( 'mousemove', mousemove, false ); 600 document.removeEventListener( 'mouseup', mouseup, false ); 601 602 window.removeEventListener( 'keydown', keydown, false ); 603 window.removeEventListener( 'keyup', keyup, false ); 604 605 }; 606 607 this.domElement.addEventListener( 'contextmenu', contextmenu, false ); 608 this.domElement.addEventListener( 'mousedown', mousedown, false ); 609 this.domElement.addEventListener( 'wheel', mousewheel, false ); 610 611 this.domElement.addEventListener( 'touchstart', touchstart, false ); 612 this.domElement.addEventListener( 'touchend', touchend, false ); 613 this.domElement.addEventListener( 'touchmove', touchmove, false ); 614 615 window.addEventListener( 'keydown', keydown, false ); 616 window.addEventListener( 'keyup', keyup, false ); 617 618 this.handleResize(); 619 620 // force an update at start 621 this.update(); 622 623}; 624 625THREE.OrthographicTrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype ); 626THREE.OrthographicTrackballControls.prototype.constructor = THREE.OrthographicTrackballControls;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.