drag.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * drag.js - click & drag DOM elements
  3. *
  4. * originally based on Youngpup's dom-drag.js, www.youngpup.net
  5. */
  6. /**********************************************************
  7. Further modified from the example by Tim Taylor
  8. http://tool-man.org/examples/sorting.html
  9. Changed onMouseMove where it calls group.onDrag and then
  10. adjusts the offset for changes to the DOM. If the item
  11. being moved changed parents it would be off so changed to
  12. get the absolute offset (recursive northwestOffset).
  13. **********************************************************/
  14. var Drag = {
  15. BIG_Z_INDEX : 10000,
  16. group : null,
  17. isDragging : false,
  18. makeDraggable : function(group) {
  19. group.handle = group;
  20. group.handle.group = group;
  21. group.minX = null;
  22. group.minY = null;
  23. group.maxX = null;
  24. group.maxY = null;
  25. group.threshold = 0;
  26. group.thresholdY = 0;
  27. group.thresholdX = 0;
  28. group.onDragStart = new Function();
  29. group.onDragEnd = new Function();
  30. group.onDrag = new Function();
  31. // TODO: use element.prototype.myFunc
  32. group.setDragHandle = Drag.setDragHandle;
  33. group.setDragThreshold = Drag.setDragThreshold;
  34. group.setDragThresholdX = Drag.setDragThresholdX;
  35. group.setDragThresholdY = Drag.setDragThresholdY;
  36. group.constrain = Drag.constrain;
  37. group.constrainVertical = Drag.constrainVertical;
  38. group.constrainHorizontal = Drag.constrainHorizontal;
  39. group.onmousedown = Drag.onMouseDown;
  40. },
  41. constrainVertical : function() {
  42. var nwOffset = Coordinates.northwestOffset(this, true);
  43. this.minX = nwOffset.x;
  44. this.maxX = nwOffset.x;
  45. },
  46. constrainHorizontal : function() {
  47. var nwOffset = Coordinates.northwestOffset(this, true);
  48. this.minY = nwOffset.y;
  49. this.maxY = nwOffset.y;
  50. },
  51. constrain : function(nwPosition, sePosition) {
  52. this.minX = nwPosition.x;
  53. this.minY = nwPosition.y;
  54. this.maxX = sePosition.x;
  55. this.maxY = sePosition.y;
  56. },
  57. setDragHandle : function(handle) {
  58. if (handle && handle != null)
  59. this.handle = handle;
  60. else
  61. this.handle = this;
  62. this.handle.group = this;
  63. this.onmousedown = null;
  64. this.handle.onmousedown = Drag.onMouseDown;
  65. },
  66. setDragThreshold : function(threshold) {
  67. if (isNaN(parseInt(threshold))) return;
  68. this.threshold = threshold;
  69. },
  70. setDragThresholdX : function(threshold) {
  71. if (isNaN(parseInt(threshold))) return;
  72. this.thresholdX = threshold;
  73. },
  74. setDragThresholdY : function(threshold) {
  75. if (isNaN(parseInt(threshold))) return;
  76. this.thresholdY = threshold;
  77. },
  78. onMouseDown : function(event) {
  79. event = Drag.fixEvent(event);
  80. Drag.group = this.group;
  81. var group = this.group;
  82. var mouse = event.windowCoordinate;
  83. var nwOffset = Coordinates.northwestOffset(group, true);
  84. var nwPosition = Coordinates.northwestPosition(group);
  85. var sePosition = Coordinates.southeastPosition(group);
  86. var seOffset = Coordinates.southeastOffset(group, true);
  87. group.originalOpacity = group.style.opacity;
  88. group.originalZIndex = group.style.zIndex;
  89. group.initialWindowCoordinate = mouse;
  90. // TODO: need a better name, but don't yet understand how it
  91. // participates in the magic while dragging
  92. group.dragCoordinate = mouse;
  93. Drag.showStatus(mouse, nwPosition, sePosition, nwOffset, seOffset);
  94. group.onDragStart(nwPosition, sePosition, nwOffset, seOffset);
  95. // TODO: need better constraint API
  96. if (group.minX != null)
  97. group.minMouseX = mouse.x - nwPosition.x +
  98. group.minX - nwOffset.x;
  99. if (group.maxX != null)
  100. group.maxMouseX = group.minMouseX + group.maxX - group.minX;
  101. if (group.minY != null)
  102. group.minMouseY = mouse.y - nwPosition.y +
  103. group.minY - nwOffset.y;
  104. if (group.maxY != null)
  105. group.maxMouseY = group.minMouseY + group.maxY - group.minY;
  106. group.mouseMin = new Coordinate(group.minMouseX, group.minMouseY);
  107. group.mouseMax = new Coordinate(group.maxMouseX, group.maxMouseY);
  108. document.onmousemove = Drag.onMouseMove;
  109. document.onmouseup = Drag.onMouseUp;
  110. return false;
  111. },
  112. showStatus : function(mouse, nwPosition, sePosition, nwOffset, seOffset) {
  113. /*window.status =
  114. "mouse: " + mouse.toString() + " " +
  115. "NW pos: " + nwPosition.toString() + " " +
  116. "SE pos: " + sePosition.toString() + " " +
  117. "NW offset: " + nwOffset.toString() + " " +
  118. "SE offset: " + seOffset.toString();*/
  119. },
  120. onMouseMove : function(event) {
  121. event = Drag.fixEvent(event);
  122. var group = Drag.group;
  123. var mouse = event.windowCoordinate;
  124. var nwOffset = Coordinates.northwestOffset(group, true);
  125. var nwPosition = Coordinates.northwestPosition(group);
  126. var sePosition = Coordinates.southeastPosition(group);
  127. var seOffset = Coordinates.southeastOffset(group, true);
  128. Drag.showStatus(mouse, nwPosition, sePosition, nwOffset, seOffset);
  129. if (!Drag.isDragging) {
  130. if (group.threshold > 0) {
  131. var distance = group.initialWindowCoordinate.distance(
  132. mouse);
  133. if (distance < group.threshold) return true;
  134. } else if (group.thresholdY > 0) {
  135. var deltaY = Math.abs(group.initialWindowCoordinate.y - mouse.y);
  136. if (deltaY < group.thresholdY) return true;
  137. } else if (group.thresholdX > 0) {
  138. var deltaX = Math.abs(group.initialWindowCoordinate.x - mouse.x);
  139. if (deltaX < group.thresholdX) return true;
  140. }
  141. Drag.isDragging = true;
  142. group.style["zIndex"] = Drag.BIG_Z_INDEX;
  143. group.style["opacity"] = 0.75;
  144. }
  145. // TODO: need better constraint API
  146. var adjusted = mouse.constrain(group.mouseMin, group.mouseMax);
  147. nwPosition = nwPosition.plus(adjusted.minus(group.dragCoordinate));
  148. nwPosition.reposition(group);
  149. group.dragCoordinate = adjusted;
  150. // once dragging has started, the position of the group
  151. // relative to the mouse should stay fixed. They can get out
  152. // of sync if the DOM is manipulated while dragging, so we
  153. // correct the error here
  154. //
  155. // TODO: what we really want to do is find the offset from
  156. // our corner to the mouse coordinate and adjust to keep it
  157. // the same
  158. // changed to be recursive/use absolute offset for corrections
  159. var offsetBefore = Coordinates.northwestOffset(group, true);
  160. group.onDrag(nwPosition, sePosition, nwOffset, seOffset);
  161. var offsetAfter = Coordinates.northwestOffset(group, true);
  162. if (!offsetBefore.equals(offsetAfter)) {
  163. var errorDelta = offsetBefore.minus(offsetAfter);
  164. nwPosition = Coordinates.northwestPosition(group).plus(errorDelta);
  165. nwPosition.reposition(group);
  166. }
  167. return false;
  168. },
  169. onMouseUp : function(event) {
  170. event = Drag.fixEvent(event);
  171. var group = Drag.group;
  172. var mouse = event.windowCoordinate;
  173. var nwOffset = Coordinates.northwestOffset(group, true);
  174. var nwPosition = Coordinates.northwestPosition(group);
  175. var sePosition = Coordinates.southeastPosition(group);
  176. var seOffset = Coordinates.southeastOffset(group, true);
  177. document.onmousemove = null;
  178. document.onmouseup = null;
  179. group.onDragEnd(nwPosition, sePosition, nwOffset, seOffset);
  180. if (Drag.isDragging) {
  181. // restoring zIndex before opacity avoids visual flicker in Firefox
  182. group.style["zIndex"] = group.originalZIndex;
  183. group.style["opacity"] = group.originalOpacity;
  184. }
  185. Drag.group = null;
  186. Drag.isDragging = false;
  187. return false;
  188. },
  189. fixEvent : function(event) {
  190. if (typeof event == 'undefined') event = window.event;
  191. Coordinates.fixEvent(event);
  192. return event;
  193. }
  194. };