DragControls.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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;
  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 } );
  75. return;
  76. }
  77. _raycaster.setFromCamera( _mouse, _camera );
  78. var intersects = _raycaster.intersectObjects( _objects );
  79. if ( intersects.length > 0 ) {
  80. _domElement.style.cursor = 'pointer';
  81. _hovered = intersects[ 0 ];
  82. scope.dispatchEvent( { type: 'hoveron', object: _hovered } );
  83. } else {
  84. scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
  85. _hovered = null;
  86. _domElement.style.cursor = 'auto';
  87. }
  88. }
  89. function onDocumentMouseDown( event ) {
  90. event.preventDefault();
  91. _mouse.x = ( event.clientX / _domElement.width ) * 2 - 1;
  92. _mouse.y = - ( event.clientY / _domElement.height ) * 2 + 1;
  93. _raycaster.setFromCamera( _mouse, _camera );
  94. var intersects = _raycaster.intersectObjects( _objects );
  95. var ray = _raycaster.ray;
  96. var normal = ray.direction; // normal ray to the camera position
  97. if ( intersects.length > 0 ) {
  98. _selected = intersects[ 0 ];
  99. _selected.ray = ray;
  100. _selected.normal = normal;
  101. _offset.copy( _selected.point ).sub( _selected.object.position );
  102. _domElement.style.cursor = 'move';
  103. scope.dispatchEvent( { type: 'dragstart', object: _selected } );
  104. }
  105. }
  106. function onDocumentMouseUp( event ) {
  107. event.preventDefault();
  108. if ( _selected ) {
  109. scope.dispatchEvent( { type: 'dragend', object: _selected } );
  110. _selected = null;
  111. }
  112. _domElement.style.cursor = 'auto';
  113. }
  114. // Backward compatibility
  115. this.on = function ( type, listener ) {
  116. console.warn( 'THREE.DragControls: on() has been deprecated. Use addEventListener() instead.' );
  117. scope.addEventListener( type, listener );
  118. };
  119. this.off = function ( type, listener ) {
  120. console.warn( 'THREE.DragControls: off() has been deprecated. Use removeEventListener() instead.' );
  121. scope.removeEventListener( type, listener );
  122. };
  123. this.notify = function ( type ) {
  124. console.error( 'THREE.DragControls: notify() has been deprecated. Use dispatchEvent() instead.' );
  125. scope.removeEventListener( type );
  126. };
  127. };
  128. THREE.DragControls.prototype = Object.create( THREE.EventDispatcher.prototype );
  129. THREE.DragControls.prototype.constructor = THREE.DragControls;