OrbitControls.js


SUBMITTED BY: Guest

DATE: July 22, 2014, 6:38 p.m.

FORMAT: Text only

SIZE: 9.1 kB

HITS: 998

  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. */
  7. THREE.OrbitControls = function ( object, domElement ) {
  8. this.object = object;
  9. this.domElement = ( domElement !== undefined ) ? domElement : document;
  10. // API
  11. this.enabled = true;
  12. this.center = new THREE.Vector3();
  13. this.userZoom = true;
  14. this.userZoomSpeed = 1.0;
  15. this.userRotate = true;
  16. this.userRotateSpeed = 1.0;
  17. this.userPan = true;
  18. this.userPanSpeed = 2.0;
  19. this.autoRotate = false;
  20. this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
  21. this.minPolarAngle = 0; // radians
  22. this.maxPolarAngle = Math.PI; // radians
  23. this.minDistance = 0;
  24. this.maxDistance = Infinity;
  25. // 65 /*A*/, 83 /*S*/, 68 /*D*/
  26. this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40, ROTATE: 65, ZOOM: 83, PAN: 68 };
  27. // internals
  28. var scope = this;
  29. var EPS = 0.000001;
  30. var PIXELS_PER_ROUND = 1800;
  31. var rotateStart = new THREE.Vector2();
  32. var rotateEnd = new THREE.Vector2();
  33. var rotateDelta = new THREE.Vector2();
  34. var zoomStart = new THREE.Vector2();
  35. var zoomEnd = new THREE.Vector2();
  36. var zoomDelta = new THREE.Vector2();
  37. var phiDelta = 0;
  38. var thetaDelta = 0;
  39. var scale = 1;
  40. var lastPosition = new THREE.Vector3();
  41. var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2 };
  42. var state = STATE.NONE;
  43. // events
  44. var changeEvent = { type: 'change' };
  45. this.rotateLeft = function ( angle ) {
  46. if ( angle === undefined ) {
  47. angle = getAutoRotationAngle();
  48. }
  49. thetaDelta -= angle;
  50. };
  51. this.rotateRight = function ( angle ) {
  52. if ( angle === undefined ) {
  53. angle = getAutoRotationAngle();
  54. }
  55. thetaDelta += angle;
  56. };
  57. this.rotateUp = function ( angle ) {
  58. if ( angle === undefined ) {
  59. angle = getAutoRotationAngle();
  60. }
  61. phiDelta -= angle;
  62. };
  63. this.rotateDown = function ( angle ) {
  64. if ( angle === undefined ) {
  65. angle = getAutoRotationAngle();
  66. }
  67. phiDelta += angle;
  68. };
  69. this.zoomIn = function ( zoomScale ) {
  70. if ( zoomScale === undefined ) {
  71. zoomScale = getZoomScale();
  72. }
  73. scale /= zoomScale;
  74. };
  75. this.zoomOut = function ( zoomScale ) {
  76. if ( zoomScale === undefined ) {
  77. zoomScale = getZoomScale();
  78. }
  79. scale *= zoomScale;
  80. };
  81. this.pan = function ( distance ) {
  82. distance.transformDirection( this.object.matrix );
  83. distance.multiplyScalar( scope.userPanSpeed );
  84. this.object.position.add( distance );
  85. this.center.add( distance );
  86. };
  87. this.update = function () {
  88. var position = this.object.position;
  89. var offset = position.clone().sub( this.center );
  90. // angle from z-axis around y-axis
  91. var theta = Math.atan2( offset.x, offset.z );
  92. // angle from y-axis
  93. var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
  94. if ( this.autoRotate ) {
  95. this.rotateLeft( getAutoRotationAngle() );
  96. }
  97. theta += thetaDelta;
  98. phi += phiDelta;
  99. // restrict phi to be between desired limits
  100. phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
  101. // restrict phi to be betwee EPS and PI-EPS
  102. phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
  103. var radius = offset.length() * scale;
  104. // restrict radius to be between desired limits
  105. radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
  106. offset.x = radius * Math.sin( phi ) * Math.sin( theta );
  107. offset.y = radius * Math.cos( phi );
  108. offset.z = radius * Math.sin( phi ) * Math.cos( theta );
  109. position.copy( this.center ).add( offset );
  110. this.object.lookAt( this.center );
  111. thetaDelta = 0;
  112. phiDelta = 0;
  113. scale = 1;
  114. if ( lastPosition.distanceTo( this.object.position ) > 0 ) {
  115. this.dispatchEvent( changeEvent );
  116. lastPosition.copy( this.object.position );
  117. }
  118. };
  119. function getAutoRotationAngle() {
  120. return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
  121. }
  122. function getZoomScale() {
  123. return Math.pow( 0.95, scope.userZoomSpeed );
  124. }
  125. function onMouseDown( event ) {
  126. if ( scope.enabled === false ) return;
  127. if ( scope.userRotate === false ) return;
  128. event.preventDefault();
  129. if ( state === STATE.NONE )
  130. {
  131. if ( event.button === 0 )
  132. state = STATE.ROTATE;
  133. if ( event.button === 1 )
  134. state = STATE.ZOOM;
  135. if ( event.button === 2 )
  136. state = STATE.PAN;
  137. }
  138. if ( state === STATE.ROTATE ) {
  139. //state = STATE.ROTATE;
  140. rotateStart.set( event.clientX, event.clientY );
  141. } else if ( state === STATE.ZOOM ) {
  142. //state = STATE.ZOOM;
  143. zoomStart.set( event.clientX, event.clientY );
  144. } else if ( state === STATE.PAN ) {
  145. //state = STATE.PAN;
  146. }
  147. document.addEventListener( 'mousemove', onMouseMove, false );
  148. document.addEventListener( 'mouseup', onMouseUp, false );
  149. }
  150. function onMouseMove( event ) {
  151. if ( scope.enabled === false ) return;
  152. event.preventDefault();
  153. if ( state === STATE.ROTATE ) {
  154. rotateEnd.set( event.clientX, event.clientY );
  155. rotateDelta.subVectors( rotateEnd, rotateStart );
  156. scope.rotateLeft( 2 * Math.PI * rotateDelta.x / PIXELS_PER_ROUND * scope.userRotateSpeed );
  157. scope.rotateUp( 2 * Math.PI * rotateDelta.y / PIXELS_PER_ROUND * scope.userRotateSpeed );
  158. rotateStart.copy( rotateEnd );
  159. } else if ( state === STATE.ZOOM ) {
  160. zoomEnd.set( event.clientX, event.clientY );
  161. zoomDelta.subVectors( zoomEnd, zoomStart );
  162. if ( zoomDelta.y > 0 ) {
  163. scope.zoomIn();
  164. } else {
  165. scope.zoomOut();
  166. }
  167. zoomStart.copy( zoomEnd );
  168. } else if ( state === STATE.PAN ) {
  169. var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
  170. var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
  171. scope.pan( new THREE.Vector3( - movementX, movementY, 0 ) );
  172. }
  173. }
  174. function onMouseUp( event ) {
  175. if ( scope.enabled === false ) return;
  176. if ( scope.userRotate === false ) return;
  177. document.removeEventListener( 'mousemove', onMouseMove, false );
  178. document.removeEventListener( 'mouseup', onMouseUp, false );
  179. state = STATE.NONE;
  180. }
  181. function onMouseWheel( event ) {
  182. if ( scope.enabled === false ) return;
  183. if ( scope.userZoom === false ) return;
  184. var delta = 0;
  185. if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
  186. delta = event.wheelDelta;
  187. } else if ( event.detail ) { // Firefox
  188. delta = - event.detail;
  189. }
  190. if ( delta > 0 ) {
  191. scope.zoomOut();
  192. } else {
  193. scope.zoomIn();
  194. }
  195. }
  196. function onKeyDown( event ) {
  197. if ( scope.enabled === false ) return;
  198. if ( scope.userPan === false ) return;
  199. switch ( event.keyCode ) {
  200. /*case scope.keys.UP:
  201. scope.pan( new THREE.Vector3( 0, 1, 0 ) );
  202. break;
  203. case scope.keys.BOTTOM:
  204. scope.pan( new THREE.Vector3( 0, - 1, 0 ) );
  205. break;
  206. case scope.keys.LEFT:
  207. scope.pan( new THREE.Vector3( - 1, 0, 0 ) );
  208. break;
  209. case scope.keys.RIGHT:
  210. scope.pan( new THREE.Vector3( 1, 0, 0 ) );
  211. break;
  212. */
  213. case scope.keys.ROTATE:
  214. state = STATE.ROTATE;
  215. break;
  216. case scope.keys.ZOOM:
  217. state = STATE.ZOOM;
  218. break;
  219. case scope.keys.PAN:
  220. state = STATE.PAN;
  221. break;
  222. }
  223. }
  224. function onKeyUp( event ) {
  225. switch ( event.keyCode ) {
  226. case scope.keys.ROTATE:
  227. case scope.keys.ZOOM:
  228. case scope.keys.PAN:
  229. state = STATE.NONE;
  230. break;
  231. }
  232. }
  233. this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
  234. this.domElement.addEventListener( 'mousedown', onMouseDown, false );
  235. this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
  236. this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
  237. window.addEventListener( 'keydown', onKeyDown, false );
  238. window.addEventListener( 'keyup', onKeyUp, false );
  239. };
  240. THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );

comments powered by Disqus