BendpointSnapping.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import {
  2. assign,
  3. forEach,
  4. isArray
  5. } from 'min-dash';
  6. var abs= Math.abs,
  7. round = Math.round;
  8. var TOLERANCE = 10;
  9. export default function BendpointSnapping(eventBus) {
  10. function snapTo(values, value) {
  11. if (isArray(values)) {
  12. var i = values.length;
  13. while (i--) if (abs(values[i] - value) <= TOLERANCE) {
  14. return values[i];
  15. }
  16. } else {
  17. values = +values;
  18. var rem = value % values;
  19. if (rem < TOLERANCE) {
  20. return value - rem;
  21. }
  22. if (rem > values - TOLERANCE) {
  23. return value - rem + values;
  24. }
  25. }
  26. return value;
  27. }
  28. function mid(element) {
  29. if (element.width) {
  30. return {
  31. x: round(element.width / 2 + element.x),
  32. y: round(element.height / 2 + element.y)
  33. };
  34. }
  35. }
  36. // connection segment snapping //////////////////////
  37. function getConnectionSegmentSnaps(context) {
  38. var snapPoints = context.snapPoints,
  39. connection = context.connection,
  40. waypoints = connection.waypoints,
  41. segmentStart = context.segmentStart,
  42. segmentStartIndex = context.segmentStartIndex,
  43. segmentEnd = context.segmentEnd,
  44. segmentEndIndex = context.segmentEndIndex,
  45. axis = context.axis;
  46. if (snapPoints) {
  47. return snapPoints;
  48. }
  49. var referenceWaypoints = [
  50. waypoints[segmentStartIndex - 1],
  51. segmentStart,
  52. segmentEnd,
  53. waypoints[segmentEndIndex + 1]
  54. ];
  55. if (segmentStartIndex < 2) {
  56. referenceWaypoints.unshift(mid(connection.source));
  57. }
  58. if (segmentEndIndex > waypoints.length - 3) {
  59. referenceWaypoints.unshift(mid(connection.target));
  60. }
  61. context.snapPoints = snapPoints = { horizontal: [] , vertical: [] };
  62. forEach(referenceWaypoints, function(p) {
  63. // we snap on existing bendpoints only,
  64. // not placeholders that are inserted during add
  65. if (p) {
  66. p = p.original || p;
  67. if (axis === 'y') {
  68. snapPoints.horizontal.push(p.y);
  69. }
  70. if (axis === 'x') {
  71. snapPoints.vertical.push(p.x);
  72. }
  73. }
  74. });
  75. return snapPoints;
  76. }
  77. eventBus.on('connectionSegment.move.move', 1500, function(event) {
  78. var context = event.context,
  79. snapPoints = getConnectionSegmentSnaps(context),
  80. x = event.x,
  81. y = event.y,
  82. sx, sy;
  83. if (!snapPoints) {
  84. return;
  85. }
  86. // snap
  87. sx = snapTo(snapPoints.vertical, x);
  88. sy = snapTo(snapPoints.horizontal, y);
  89. // correction x/y
  90. var cx = (x - sx),
  91. cy = (y - sy);
  92. // update delta
  93. assign(event, {
  94. dx: event.dx - cx,
  95. dy: event.dy - cy,
  96. x: sx,
  97. y: sy
  98. });
  99. });
  100. // bendpoint snapping //////////////////////
  101. function getBendpointSnaps(context) {
  102. var snapPoints = context.snapPoints,
  103. waypoints = context.connection.waypoints,
  104. bendpointIndex = context.bendpointIndex;
  105. if (snapPoints) {
  106. return snapPoints;
  107. }
  108. var referenceWaypoints = [ waypoints[bendpointIndex - 1], waypoints[bendpointIndex + 1] ];
  109. context.snapPoints = snapPoints = { horizontal: [] , vertical: [] };
  110. forEach(referenceWaypoints, function(p) {
  111. // we snap on existing bendpoints only,
  112. // not placeholders that are inserted during add
  113. if (p) {
  114. p = p.original || p;
  115. snapPoints.horizontal.push(p.y);
  116. snapPoints.vertical.push(p.x);
  117. }
  118. });
  119. return snapPoints;
  120. }
  121. eventBus.on('bendpoint.move.move', 1500, function(event) {
  122. var context = event.context,
  123. snapPoints = getBendpointSnaps(context),
  124. target = context.target,
  125. targetMid = target && mid(target),
  126. x = event.x,
  127. y = event.y,
  128. sx, sy;
  129. if (!snapPoints) {
  130. return;
  131. }
  132. // snap
  133. sx = snapTo(targetMid ? snapPoints.vertical.concat([ targetMid.x ]) : snapPoints.vertical, x);
  134. sy = snapTo(targetMid ? snapPoints.horizontal.concat([ targetMid.y ]) : snapPoints.horizontal, y);
  135. // correction x/y
  136. var cx = (x - sx),
  137. cy = (y - sy);
  138. // update delta
  139. assign(event, {
  140. dx: event.dx - cx,
  141. dy: event.dy - cy,
  142. x: event.x - cx,
  143. y: event.y - cy
  144. });
  145. });
  146. }
  147. BendpointSnapping.$inject = [ 'eventBus' ];