DragControls.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * @author zz85 / https://github.com/zz85
  3. * @author mrdoob / http://mrdoob.com
  4. * Running this will allow you to drag three.js objects around the screen.
  5. */
  6. THREE.DragControls = function ( _camera, _objects, _domElement ) {
  7. var _raycaster = new THREE.Raycaster();
  8. var _mouse = new THREE.Vector3(),
  9. _offset = new THREE.Vector3();
  10. var _selected, _hovered = null;
  11. var p3subp1 = new THREE.Vector3();
  12. var targetposition = new THREE.Vector3();
  13. this.enabled = false;
  14. var scope = this;
  15. this.setObjects = function ( objects ) {
  16. if ( Array.isArray( objects ) === false ) {
  17. console.error( 'THREE.DragControls.setObjects() expects an Array.' );
  18. return;
  19. }
  20. _objects = objects;
  21. };
  22. this.setObjects( _objects );
  23. this.activate = function () {
  24. _domElement.addEventListener( 'mousemove', onDocumentMouseMove, false );
  25. _domElement.addEventListener( 'mousedown', onDocumentMouseDown, false );
  26. _domElement.addEventListener( 'mouseup', onDocumentMouseUp, false );
  27. };
  28. this.deactivate = function () {
  29. _domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false );
  30. _domElement.removeEventListener( 'mousedown', onDocumentMouseDown, false );
  31. _domElement.removeEventListener( 'mouseup', onDocumentMouseUp, false );
  32. };
  33. this.dispose = function () {
  34. scope.deactivate();
  35. };
  36. this.activate();
  37. function onDocumentMouseMove( event ) {
  38. event.preventDefault();
  39. _mouse.x = ( event.clientX / _domElement.width ) * 2 - 1;
  40. _mouse.y = - ( event.clientY / _domElement.height ) * 2 + 1;
  41. _raycaster.setFromCamera( _mouse, _camera );
  42. var ray = _raycaster.ray;
  43. if ( _selected && scope.enabled ) {
  44. var normal = _selected.normal;
  45. // I found this article useful about plane-line intersections
  46. // http://paulbourke.net/geometry/planeline/
  47. var denom = normal.dot( ray.direction );
  48. if ( denom == 0 ) {
  49. // bail
  50. console.log( 'no or infinite solutions' );
  51. return;
  52. }
  53. var num = normal.dot( p3subp1.copy( _selected.point ).sub( ray.origin ) );
  54. var u = num / denom;
  55. targetposition.copy( ray.direction ).multiplyScalar( u ).add( ray.origin ).sub( _offset );
  56. // _selected.object.position.copy(targetposition);
  57. var xLock, yLock;
  58. var moveX, moveY, moveZ;
  59. if ( xLock ) {
  60. moveX = true;
  61. moveY = false;
  62. moveZ = false;
  63. } else if ( yLock ) {
  64. moveX = false;
  65. moveY = true;
  66. moveZ = false;
  67. } else {
  68. moveX = moveY = moveZ = true;
  69. }
  70. // Reverse Matrix?
  71. if ( moveX ) _selected.object.position.x = targetposition.x;
  72. if ( moveY ) _selected.object.position.y = targetposition.y;
  73. if ( moveZ ) _selected.object.position.z = targetposition.z;
  74. scope.dispatchEvent( { type: 'drag', object: _selected.object } );
  75. return;
  76. }
  77. _raycaster.setFromCamera( _mouse, _camera );
  78. var intersects = _raycaster.intersectObjects( _objects );
  79. if ( intersects.length > 0 ) {
  80. var object = intersects[ 0 ].object;
  81. if ( _hovered !== object ) {
  82. scope.dispatchEvent( { type: 'hoveron', object: object } );
  83. _domElement.style.cursor = 'pointer';
  84. _hovered = object;
  85. }
  86. } else {
  87. if ( _hovered !== null ) {
  88. scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
  89. _domElement.style.cursor = 'auto';
  90. _hovered = null;
  91. }
  92. }
  93. }
  94. function onDocumentMouseDown( event ) {
  95. event.preventDefault();
  96. _mouse.x = ( event.clientX / _domElement.width ) * 2 - 1;
  97. _mouse.y = - ( event.clientY / _domElement.height ) * 2 + 1;
  98. _raycaster.setFromCamera( _mouse, _camera );
  99. var intersects = _raycaster.intersectObjects( _objects );
  100. var ray = _raycaster.ray;
  101. var normal = ray.direction; // normal ray to the camera position
  102. if ( intersects.length > 0 ) {
  103. _selected = intersects[ 0 ];
  104. _selected.ray = ray;
  105. _selected.normal = normal;
  106. _offset.copy( _selected.point ).sub( _selected.object.position );
  107. _domElement.style.cursor = 'move';
  108. scope.dispatchEvent( { type: 'dragstart', object: _selected.object } );
  109. }
  110. }
  111. function onDocumentMouseUp( event ) {
  112. event.preventDefault();
  113. if ( _selected ) {
  114. scope.dispatchEvent( { type: 'dragend', object: _selected.object } );
  115. _selected = null;
  116. }
  117. _domElement.style.cursor = 'auto';
  118. }
  119. // Backward compatibility
  120. this.on = function ( type, listener ) {
  121. console.warn( 'THREE.DragControls: on() has been deprecated. Use addEventListener() instead.' );
  122. scope.addEventListener( type, listener );
  123. };
  124. this.off = function ( type, listener ) {
  125. console.warn( 'THREE.DragControls: off() has been deprecated. Use removeEventListener() instead.' );
  126. scope.removeEventListener( type, listener );
  127. };
  128. this.notify = function ( type ) {
  129. console.error( 'THREE.DragControls: notify() has been deprecated. Use dispatchEvent() instead.' );
  130. scope.dispatchEvent( { type: type } );
  131. };
  132. };
  133. THREE.DragControls.prototype = Object.create( THREE.EventDispatcher.prototype );
  134. THREE.DragControls.prototype.constructor = THREE.DragControls;