BendpointMove.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import { filterRedundantWaypoints } from '../../layout/LayoutUtil';
  2. var round = Math.round;
  3. var RECONNECT_START = 'reconnectStart',
  4. RECONNECT_END = 'reconnectEnd',
  5. UPDATE_WAYPOINTS = 'updateWaypoints';
  6. /**
  7. * Move bendpoints through drag and drop to add/remove bendpoints or reconnect connection.
  8. */
  9. export default function BendpointMove(injector, eventBus, canvas, dragging, rules, modeling) {
  10. this._injector = injector;
  11. this.start = function(event, connection, bendpointIndex, insert) {
  12. var gfx = canvas.getGraphics(connection),
  13. source = connection.source,
  14. target = connection.target,
  15. waypoints = connection.waypoints,
  16. type;
  17. if (!insert && bendpointIndex === 0) {
  18. type = RECONNECT_START;
  19. } else
  20. if (!insert && bendpointIndex === waypoints.length - 1) {
  21. type = RECONNECT_END;
  22. } else {
  23. type = UPDATE_WAYPOINTS;
  24. }
  25. var command = type === UPDATE_WAYPOINTS ? 'connection.updateWaypoints' : 'connection.reconnect';
  26. var allowed = rules.allowed(command, {
  27. connection: connection,
  28. source: source,
  29. target: target
  30. });
  31. if (allowed === false) {
  32. allowed = rules.allowed(command, {
  33. connection: connection,
  34. source: target,
  35. target: source
  36. });
  37. }
  38. if (allowed === false) {
  39. return;
  40. }
  41. dragging.init(event, 'bendpoint.move', {
  42. data: {
  43. connection: connection,
  44. connectionGfx: gfx,
  45. context: {
  46. allowed: allowed,
  47. bendpointIndex: bendpointIndex,
  48. connection: connection,
  49. source: source,
  50. target: target,
  51. insert: insert,
  52. type: type
  53. }
  54. }
  55. });
  56. };
  57. eventBus.on('bendpoint.move.hover', function(event) {
  58. var context = event.context,
  59. connection = context.connection,
  60. source = connection.source,
  61. target = connection.target,
  62. hover = event.hover,
  63. type = context.type;
  64. // cache hover state
  65. context.hover = hover;
  66. var allowed;
  67. if (!hover) {
  68. return;
  69. }
  70. var command = type === UPDATE_WAYPOINTS ? 'connection.updateWaypoints' : 'connection.reconnect';
  71. allowed = context.allowed = rules.allowed(command, {
  72. connection: connection,
  73. source: type === RECONNECT_START ? hover : source,
  74. target: type === RECONNECT_END ? hover : target
  75. });
  76. if (allowed) {
  77. context.source = type === RECONNECT_START ? hover : source;
  78. context.target = type === RECONNECT_END ? hover : target;
  79. return;
  80. }
  81. if (allowed === false) {
  82. allowed = context.allowed = rules.allowed(command, {
  83. connection: connection,
  84. source: type === RECONNECT_END ? hover : target,
  85. target: type === RECONNECT_START ? hover : source
  86. });
  87. }
  88. if (allowed) {
  89. context.source = type === RECONNECT_END ? hover : target;
  90. context.target = type === RECONNECT_START ? hover : source;
  91. }
  92. });
  93. eventBus.on([ 'bendpoint.move.out', 'bendpoint.move.cleanup' ], function(event) {
  94. var context = event.context,
  95. type = context.type;
  96. context.hover = null;
  97. context.source = null;
  98. context.target = null;
  99. if (type !== UPDATE_WAYPOINTS) {
  100. context.allowed = false;
  101. }
  102. });
  103. eventBus.on('bendpoint.move.end', function(event) {
  104. var context = event.context,
  105. allowed = context.allowed,
  106. bendpointIndex = context.bendpointIndex,
  107. connection = context.connection,
  108. insert = context.insert,
  109. newWaypoints = connection.waypoints.slice(),
  110. source = context.source,
  111. target = context.target,
  112. type = context.type,
  113. hints = context.hints || {};
  114. // ensure integer values (important if zoom level was > 1 during move)
  115. var docking = {
  116. x: round(event.x),
  117. y: round(event.y)
  118. };
  119. if (!allowed) {
  120. return false;
  121. }
  122. if (type === UPDATE_WAYPOINTS) {
  123. if (insert) {
  124. // insert new bendpoint
  125. newWaypoints.splice(bendpointIndex, 0, docking);
  126. } else {
  127. // swap previous waypoint with moved one
  128. newWaypoints[bendpointIndex] = docking;
  129. }
  130. // pass hints about actual moved bendpoint
  131. // useful for connection/label layout
  132. hints.bendpointMove = {
  133. insert: insert,
  134. bendpointIndex: bendpointIndex
  135. };
  136. newWaypoints = this.cropWaypoints(connection, newWaypoints);
  137. modeling.updateWaypoints(connection, filterRedundantWaypoints(newWaypoints), hints);
  138. } else {
  139. if (type === RECONNECT_START) {
  140. hints.docking = 'source';
  141. if (isReverse(context)) {
  142. hints.docking = 'target';
  143. hints.newWaypoints = newWaypoints.reverse();
  144. }
  145. } else if (type === RECONNECT_END) {
  146. hints.docking = 'target';
  147. if (isReverse(context)) {
  148. hints.docking = 'source';
  149. hints.newWaypoints = newWaypoints.reverse();
  150. }
  151. }
  152. modeling.reconnect(connection, source, target, docking, hints);
  153. }
  154. }, this);
  155. }
  156. BendpointMove.$inject = [
  157. 'injector',
  158. 'eventBus',
  159. 'canvas',
  160. 'dragging',
  161. 'rules',
  162. 'modeling'
  163. ];
  164. BendpointMove.prototype.cropWaypoints = function(connection, newWaypoints) {
  165. var connectionDocking = this._injector.get('connectionDocking', false);
  166. if (!connectionDocking) {
  167. return newWaypoints;
  168. }
  169. var waypoints = connection.waypoints;
  170. connection.waypoints = newWaypoints;
  171. connection.waypoints = connectionDocking.getCroppedWaypoints(connection);
  172. newWaypoints = connection.waypoints;
  173. connection.waypoints = waypoints;
  174. return newWaypoints;
  175. };
  176. // helpers //////////
  177. export function isReverse(context) {
  178. var hover = context.hover,
  179. source = context.source,
  180. target = context.target,
  181. type = context.type;
  182. if (type === RECONNECT_START) {
  183. return hover && target && hover === target && source !== target;
  184. }
  185. if (type === RECONNECT_END) {
  186. return hover && source && hover === source && source !== target;
  187. }
  188. }