LayoutConnectionBehavior.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import inherits from 'inherits';
  2. import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
  3. import { pointsAligned } from 'diagram-js/lib/util/Geometry';
  4. import {
  5. assign
  6. } from 'min-dash';
  7. var HIGH_PRIORITY = 3000;
  8. /**
  9. * Snaps connections with Manhattan layout.
  10. */
  11. export default function LayoutConnectionBehavior(eventBus, gridSnapping, modeling) {
  12. CommandInterceptor.call(this, eventBus);
  13. this._gridSnapping = gridSnapping;
  14. var self = this;
  15. this.postExecuted([
  16. 'connection.create',
  17. 'connection.layout'
  18. ], HIGH_PRIORITY, function(event) {
  19. var context = event.context,
  20. connection = context.connection,
  21. hints = context.hints || {},
  22. waypoints = connection.waypoints;
  23. if (hints.connectionStart || hints.connectionEnd || hints.createElementsBehavior === false) {
  24. return;
  25. }
  26. if (!hasMiddleSegments(waypoints)) {
  27. return;
  28. }
  29. modeling.updateWaypoints(connection, self.snapMiddleSegments(waypoints));
  30. });
  31. }
  32. LayoutConnectionBehavior.$inject = [
  33. 'eventBus',
  34. 'gridSnapping',
  35. 'modeling'
  36. ];
  37. inherits(LayoutConnectionBehavior, CommandInterceptor);
  38. /**
  39. * Snap middle segments of a given connection.
  40. *
  41. * @param {Array<Point>} waypoints
  42. *
  43. * @returns {Array<Point>}
  44. */
  45. LayoutConnectionBehavior.prototype.snapMiddleSegments = function(waypoints) {
  46. var gridSnapping = this._gridSnapping,
  47. snapped;
  48. waypoints = waypoints.slice();
  49. for (var i = 1; i < waypoints.length - 2; i++) {
  50. snapped = snapSegment(gridSnapping, waypoints[i], waypoints[i + 1]);
  51. waypoints[i] = snapped[0];
  52. waypoints[i + 1] = snapped[1];
  53. }
  54. return waypoints;
  55. };
  56. // helpers //////////
  57. /**
  58. * Check whether a connection has a middle segments.
  59. *
  60. * @param {Array} waypoints
  61. *
  62. * @returns {boolean}
  63. */
  64. function hasMiddleSegments(waypoints) {
  65. return waypoints.length > 3;
  66. }
  67. /**
  68. * Check whether an alignment is horizontal.
  69. *
  70. * @param {string} aligned
  71. *
  72. * @returns {boolean}
  73. */
  74. function horizontallyAligned(aligned) {
  75. return aligned === 'h';
  76. }
  77. /**
  78. * Check whether an alignment is vertical.
  79. *
  80. * @param {string} aligned
  81. *
  82. * @returns {boolean}
  83. */
  84. function verticallyAligned(aligned) {
  85. return aligned === 'v';
  86. }
  87. /**
  88. * Get middle segments from a given connection.
  89. *
  90. * @param {Array} waypoints
  91. *
  92. * @returns {Array}
  93. */
  94. function snapSegment(gridSnapping, segmentStart, segmentEnd) {
  95. var aligned = pointsAligned(segmentStart, segmentEnd);
  96. var snapped = {};
  97. if (horizontallyAligned(aligned)) {
  98. // snap horizontally
  99. snapped.y = gridSnapping.snapValue(segmentStart.y);
  100. }
  101. if (verticallyAligned(aligned)) {
  102. // snap vertically
  103. snapped.x = gridSnapping.snapValue(segmentStart.x);
  104. }
  105. if ('x' in snapped || 'y' in snapped) {
  106. segmentStart = assign({}, segmentStart, snapped);
  107. segmentEnd = assign({}, segmentEnd, snapped);
  108. }
  109. return [ segmentStart, segmentEnd ];
  110. }