SpaceToolHandler.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import {
  2. assign,
  3. forEach,
  4. map
  5. } from 'min-dash';
  6. import {
  7. getWaypointsUpdatingConnections,
  8. resizeBounds
  9. } from '../../space-tool/SpaceUtil';
  10. import {
  11. getMovedSourceAnchor,
  12. getMovedTargetAnchor,
  13. getResizedSourceAnchor,
  14. getResizedTargetAnchor
  15. } from './helper/AnchorsHelper';
  16. /**
  17. * Add or remove space by moving and resizing shapes and updating connection waypoints.
  18. */
  19. export default function SpaceToolHandler(modeling) {
  20. this._modeling = modeling;
  21. }
  22. SpaceToolHandler.$inject = [ 'modeling' ];
  23. SpaceToolHandler.prototype.preExecute = function(context) {
  24. var delta = context.delta,
  25. direction = context.direction,
  26. movingShapes = context.movingShapes,
  27. resizingShapes = context.resizingShapes,
  28. start = context.start,
  29. oldBounds = {};
  30. // (1) move shapes
  31. this.moveShapes(movingShapes, delta);
  32. // (2a) save old bounds of resized shapes
  33. forEach(resizingShapes, function(shape) {
  34. oldBounds[shape.id] = getBounds(shape);
  35. });
  36. // (2b) resize shapes
  37. this.resizeShapes(resizingShapes, delta, direction);
  38. // (3) update connection waypoints
  39. this.updateConnectionWaypoints(
  40. getWaypointsUpdatingConnections(movingShapes, resizingShapes),
  41. delta,
  42. direction,
  43. start,
  44. movingShapes,
  45. resizingShapes,
  46. oldBounds
  47. );
  48. };
  49. SpaceToolHandler.prototype.execute = function() {};
  50. SpaceToolHandler.prototype.revert = function() {};
  51. SpaceToolHandler.prototype.moveShapes = function(shapes, delta) {
  52. var self = this;
  53. forEach(shapes, function(element) {
  54. self._modeling.moveShape(element, delta, null, {
  55. autoResize: false,
  56. layout: false,
  57. recurse: false
  58. });
  59. });
  60. };
  61. SpaceToolHandler.prototype.resizeShapes = function(shapes, delta, direction) {
  62. var self = this;
  63. forEach(shapes, function(shape) {
  64. var newBounds = resizeBounds(shape, direction, delta);
  65. self._modeling.resizeShape(shape, newBounds, null, {
  66. attachSupport: false,
  67. autoResize: false,
  68. layout: false
  69. });
  70. });
  71. };
  72. /**
  73. * Update connections waypoints according to the rules:
  74. * 1. Both source and target are moved/resized => move waypoints by the delta
  75. * 2. Only one of source and target is moved/resized => re-layout connection with moved start/end
  76. */
  77. SpaceToolHandler.prototype.updateConnectionWaypoints = function(
  78. connections,
  79. delta,
  80. direction,
  81. start,
  82. movingShapes,
  83. resizingShapes,
  84. oldBounds
  85. ) {
  86. var self = this,
  87. affectedShapes = movingShapes.concat(resizingShapes);
  88. forEach(connections, function(connection) {
  89. var source = connection.source,
  90. target = connection.target,
  91. waypoints = copyWaypoints(connection),
  92. axis = getAxisFromDirection(direction),
  93. layoutHints = {};
  94. if (includes(affectedShapes, source) && includes(affectedShapes, target)) {
  95. // move waypoints
  96. waypoints = map(waypoints, function(waypoint) {
  97. if (shouldMoveWaypoint(waypoint, start, direction)) {
  98. // move waypoint
  99. waypoint[ axis ] = waypoint[ axis ] + delta[ axis ];
  100. }
  101. if (waypoint.original && shouldMoveWaypoint(waypoint.original, start, direction)) {
  102. // move waypoint original
  103. waypoint.original[ axis ] = waypoint.original[ axis ] + delta[ axis ];
  104. }
  105. return waypoint;
  106. });
  107. self._modeling.updateWaypoints(connection, waypoints, {
  108. labelBehavior: false
  109. });
  110. } else if (includes(affectedShapes, source) || includes(affectedShapes, target)) {
  111. // re-layout connection with moved start/end
  112. if (includes(movingShapes, source)) {
  113. layoutHints.connectionStart = getMovedSourceAnchor(connection, source, delta);
  114. } else if (includes(movingShapes, target)) {
  115. layoutHints.connectionEnd = getMovedTargetAnchor(connection, target, delta);
  116. } else if (includes(resizingShapes, source)) {
  117. layoutHints.connectionStart = getResizedSourceAnchor(
  118. connection, source, oldBounds[source.id]
  119. );
  120. } else if (includes(resizingShapes, target)) {
  121. layoutHints.connectionEnd = getResizedTargetAnchor(
  122. connection, target, oldBounds[target.id]
  123. );
  124. }
  125. self._modeling.layoutConnection(connection, layoutHints);
  126. }
  127. });
  128. };
  129. // helpers //////////
  130. function copyWaypoint(waypoint) {
  131. return assign({}, waypoint);
  132. }
  133. function copyWaypoints(connection) {
  134. return map(connection.waypoints, function(waypoint) {
  135. waypoint = copyWaypoint(waypoint);
  136. if (waypoint.original) {
  137. waypoint.original = copyWaypoint(waypoint.original);
  138. }
  139. return waypoint;
  140. });
  141. }
  142. function getAxisFromDirection(direction) {
  143. switch (direction) {
  144. case 'n':
  145. return 'y';
  146. case 'w':
  147. return 'x';
  148. case 's':
  149. return 'y';
  150. case 'e':
  151. return 'x';
  152. }
  153. }
  154. function shouldMoveWaypoint(waypoint, start, direction) {
  155. var relevantAxis = getAxisFromDirection(direction);
  156. if (/e|s/.test(direction)) {
  157. return waypoint[ relevantAxis ] > start;
  158. } else if (/n|w/.test(direction)) {
  159. return waypoint[ relevantAxis ] < start;
  160. }
  161. }
  162. function includes(array, item) {
  163. return array.indexOf(item) !== -1;
  164. }
  165. function getBounds(shape) {
  166. return {
  167. x: shape.x,
  168. y: shape.y,
  169. height: shape.height,
  170. width: shape.width
  171. };
  172. }