Move.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import {
  2. assign,
  3. filter,
  4. groupBy
  5. } from 'min-dash';
  6. var LOW_PRIORITY = 500,
  7. MEDIUM_PRIORITY = 1250,
  8. HIGH_PRIORITY = 1500;
  9. import { getOriginal as getOriginalEvent } from '../../util/Event';
  10. var round = Math.round;
  11. function mid(element) {
  12. return {
  13. x: element.x + round(element.width / 2),
  14. y: element.y + round(element.height / 2)
  15. };
  16. }
  17. /**
  18. * A plugin that makes shapes draggable / droppable.
  19. *
  20. * @param {EventBus} eventBus
  21. * @param {Dragging} dragging
  22. * @param {Modeling} modeling
  23. * @param {Selection} selection
  24. * @param {Rules} rules
  25. */
  26. export default function MoveEvents(
  27. eventBus, dragging, modeling,
  28. selection, rules) {
  29. // rules
  30. function canMove(shapes, delta, position, target) {
  31. return rules.allowed('elements.move', {
  32. shapes: shapes,
  33. delta: delta,
  34. position: position,
  35. target: target
  36. });
  37. }
  38. // move events
  39. // assign a high priority to this handler to setup the environment
  40. // others may hook up later, e.g. at default priority and modify
  41. // the move environment.
  42. //
  43. // This sets up the context with
  44. //
  45. // * shape: the primary shape being moved
  46. // * shapes: a list of shapes to be moved
  47. // * validatedShapes: a list of shapes that are being checked
  48. // against the rules before and during move
  49. //
  50. eventBus.on('shape.move.start', HIGH_PRIORITY, function(event) {
  51. var context = event.context,
  52. shape = event.shape,
  53. shapes = selection.get().slice();
  54. // move only single shape if the dragged element
  55. // is not part of the current selection
  56. if (shapes.indexOf(shape) === -1) {
  57. shapes = [ shape ];
  58. }
  59. // ensure we remove nested elements in the collection
  60. // and add attachers for a proper dragger
  61. shapes = removeNested(shapes);
  62. // attach shapes to drag context
  63. assign(context, {
  64. shapes: shapes,
  65. validatedShapes: shapes,
  66. shape: shape
  67. });
  68. });
  69. // assign a high priority to this handler to setup the environment
  70. // others may hook up later, e.g. at default priority and modify
  71. // the move environment
  72. //
  73. eventBus.on('shape.move.start', MEDIUM_PRIORITY, function(event) {
  74. var context = event.context,
  75. validatedShapes = context.validatedShapes,
  76. canExecute;
  77. canExecute = context.canExecute = canMove(validatedShapes);
  78. // check if we can move the elements
  79. if (!canExecute) {
  80. return false;
  81. }
  82. });
  83. // assign a low priority to this handler
  84. // to let others modify the move event before we update
  85. // the context
  86. //
  87. eventBus.on('shape.move.move', LOW_PRIORITY, function(event) {
  88. var context = event.context,
  89. validatedShapes = context.validatedShapes,
  90. hover = event.hover,
  91. delta = { x: event.dx, y: event.dy },
  92. position = { x: event.x, y: event.y },
  93. canExecute;
  94. // check if we can move the elements
  95. canExecute = canMove(validatedShapes, delta, position, hover);
  96. context.delta = delta;
  97. context.canExecute = canExecute;
  98. // simply ignore move over
  99. if (canExecute === null) {
  100. context.target = null;
  101. return;
  102. }
  103. context.target = hover;
  104. });
  105. eventBus.on('shape.move.end', function(event) {
  106. var context = event.context;
  107. var delta = context.delta,
  108. canExecute = context.canExecute,
  109. isAttach = canExecute === 'attach',
  110. shapes = context.shapes;
  111. if (!canExecute) {
  112. return false;
  113. }
  114. // ensure we have actual pixel values deltas
  115. // (important when zoom level was > 1 during move)
  116. delta.x = round(delta.x);
  117. delta.y = round(delta.y);
  118. modeling.moveElements(shapes, delta, context.target, {
  119. primaryShape: context.shape,
  120. attach: isAttach
  121. });
  122. });
  123. // move activation
  124. eventBus.on('element.mousedown', function(event) {
  125. var originalEvent = getOriginalEvent(event);
  126. if (!originalEvent) {
  127. throw new Error('must supply DOM mousedown event');
  128. }
  129. return start(originalEvent, event.element);
  130. });
  131. function start(event, element, activate) {
  132. // do not move connections or the root element
  133. if (element.waypoints || !element.parent) {
  134. return;
  135. }
  136. var referencePoint = mid(element);
  137. dragging.init(event, referencePoint, 'shape.move', {
  138. cursor: 'grabbing',
  139. autoActivate: activate,
  140. data: {
  141. shape: element,
  142. context: {}
  143. }
  144. });
  145. // we've handled the event
  146. return true;
  147. }
  148. // API
  149. this.start = start;
  150. }
  151. MoveEvents.$inject = [
  152. 'eventBus',
  153. 'dragging',
  154. 'modeling',
  155. 'selection',
  156. 'rules'
  157. ];
  158. /**
  159. * Return a filtered list of elements that do not contain
  160. * those nested into others.
  161. *
  162. * @param {Array<djs.model.Base>} elements
  163. *
  164. * @return {Array<djs.model.Base>} filtered
  165. */
  166. function removeNested(elements) {
  167. var ids = groupBy(elements, 'id');
  168. return filter(elements, function(element) {
  169. while ((element = element.parent)) {
  170. // parent in selection
  171. if (ids[element.id]) {
  172. return false;
  173. }
  174. }
  175. return true;
  176. });
  177. }