util.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.reconstructRoute = exports.getRectPoints = exports.getCost = exports.normalizePoint = exports.getKey = exports.align = exports.round = exports.getGrid = exports.getGridOffsets = exports.getDirectionChange = exports.getDirectionAngle = exports.getTargetEndpoint = exports.getSourceEndpoint = exports.getTargetBBox = exports.getSourceBBox = void 0;
  4. const x6_geometry_1 = require("@antv/x6-geometry");
  5. function getSourceBBox(view, options) {
  6. const bbox = view.sourceBBox.clone();
  7. if (options && options.paddingBox) {
  8. return bbox.moveAndExpand(options.paddingBox);
  9. }
  10. return bbox;
  11. }
  12. exports.getSourceBBox = getSourceBBox;
  13. function getTargetBBox(view, options) {
  14. const bbox = view.targetBBox.clone();
  15. if (options && options.paddingBox) {
  16. return bbox.moveAndExpand(options.paddingBox);
  17. }
  18. return bbox;
  19. }
  20. exports.getTargetBBox = getTargetBBox;
  21. function getSourceEndpoint(view, options) {
  22. if (view.sourceAnchor) {
  23. return view.sourceAnchor;
  24. }
  25. const sourceBBox = getSourceBBox(view, options);
  26. return sourceBBox.getCenter();
  27. }
  28. exports.getSourceEndpoint = getSourceEndpoint;
  29. function getTargetEndpoint(view, options) {
  30. if (view.targetAnchor) {
  31. return view.targetAnchor;
  32. }
  33. const targetBBox = getTargetBBox(view, options);
  34. return targetBBox.getCenter();
  35. }
  36. exports.getTargetEndpoint = getTargetEndpoint;
  37. // returns a direction index from start point to end point
  38. // corrects for grid deformation between start and end
  39. function getDirectionAngle(start, end, directionCount, grid, options) {
  40. const quadrant = 360 / directionCount;
  41. const angleTheta = start.theta(fixAngleEnd(start, end, grid, options));
  42. const normalizedAngle = x6_geometry_1.Angle.normalize(angleTheta + quadrant / 2);
  43. return quadrant * Math.floor(normalizedAngle / quadrant);
  44. }
  45. exports.getDirectionAngle = getDirectionAngle;
  46. function fixAngleEnd(start, end, grid, options) {
  47. const step = options.step;
  48. const diffX = end.x - start.x;
  49. const diffY = end.y - start.y;
  50. const gridStepsX = diffX / grid.x;
  51. const gridStepsY = diffY / grid.y;
  52. const distanceX = gridStepsX * step;
  53. const distanceY = gridStepsY * step;
  54. return new x6_geometry_1.Point(start.x + distanceX, start.y + distanceY);
  55. }
  56. /**
  57. * Returns the change in direction between two direction angles.
  58. */
  59. function getDirectionChange(angle1, angle2) {
  60. const change = Math.abs(angle1 - angle2);
  61. return change > 180 ? 360 - change : change;
  62. }
  63. exports.getDirectionChange = getDirectionChange;
  64. // fix direction offsets according to current grid
  65. function getGridOffsets(grid, options) {
  66. const step = options.step;
  67. options.directions.forEach((direction) => {
  68. direction.gridOffsetX = (direction.offsetX / step) * grid.x;
  69. direction.gridOffsetY = (direction.offsetY / step) * grid.y;
  70. });
  71. return options.directions;
  72. }
  73. exports.getGridOffsets = getGridOffsets;
  74. // get grid size in x and y dimensions, adapted to source and target positions
  75. function getGrid(step, source, target) {
  76. return {
  77. source: source.clone(),
  78. x: getGridDimension(target.x - source.x, step),
  79. y: getGridDimension(target.y - source.y, step),
  80. };
  81. }
  82. exports.getGrid = getGrid;
  83. function getGridDimension(diff, step) {
  84. // return step if diff = 0
  85. if (!diff) {
  86. return step;
  87. }
  88. const abs = Math.abs(diff);
  89. const count = Math.round(abs / step);
  90. // return `abs` if less than one step apart
  91. if (!count) {
  92. return abs;
  93. }
  94. // otherwise, return corrected step
  95. const roundedDiff = count * step;
  96. const remainder = abs - roundedDiff;
  97. const correction = remainder / count;
  98. return step + correction;
  99. }
  100. function snapGrid(point, grid) {
  101. const source = grid.source;
  102. const x = x6_geometry_1.GeometryUtil.snapToGrid(point.x - source.x, grid.x) + source.x;
  103. const y = x6_geometry_1.GeometryUtil.snapToGrid(point.y - source.y, grid.y) + source.y;
  104. return new x6_geometry_1.Point(x, y);
  105. }
  106. function round(point, precision) {
  107. return point.round(precision);
  108. }
  109. exports.round = round;
  110. function align(point, grid, precision) {
  111. return round(snapGrid(point.clone(), grid), precision);
  112. }
  113. exports.align = align;
  114. function getKey(point) {
  115. return point.toString();
  116. }
  117. exports.getKey = getKey;
  118. function normalizePoint(point) {
  119. return new x6_geometry_1.Point(point.x === 0 ? 0 : Math.abs(point.x) / point.x, point.y === 0 ? 0 : Math.abs(point.y) / point.y);
  120. }
  121. exports.normalizePoint = normalizePoint;
  122. function getCost(from, anchors) {
  123. let min = Infinity;
  124. for (let i = 0, len = anchors.length; i < len; i += 1) {
  125. const dist = from.manhattanDistance(anchors[i]);
  126. if (dist < min) {
  127. min = dist;
  128. }
  129. }
  130. return min;
  131. }
  132. exports.getCost = getCost;
  133. // Find points around the bbox taking given directions into account
  134. // lines are drawn from anchor in given directions, intersections recorded
  135. // if anchor is outside bbox, only those directions that intersect get a rect point
  136. // the anchor itself is returned as rect point (representing some directions)
  137. // (since those directions are unobstructed by the bbox)
  138. function getRectPoints(anchor, bbox, directionList, grid, options) {
  139. const precision = options.precision;
  140. const directionMap = options.directionMap;
  141. const centerVector = anchor.diff(bbox.getCenter());
  142. const rectPoints = Object.keys(directionMap).reduce((res, key) => {
  143. if (directionList.includes(key)) {
  144. const direction = directionMap[key];
  145. // Create a line that is guaranteed to intersect the bbox if bbox
  146. // is in the direction even if anchor lies outside of bbox.
  147. const ending = new x6_geometry_1.Point(anchor.x + direction.x * (Math.abs(centerVector.x) + bbox.width), anchor.y + direction.y * (Math.abs(centerVector.y) + bbox.height));
  148. const intersectionLine = new x6_geometry_1.Line(anchor, ending);
  149. // Get the farther intersection, in case there are two
  150. // (that happens if anchor lies next to bbox)
  151. const intersections = intersectionLine.intersect(bbox) || [];
  152. let farthestIntersectionDistance;
  153. let farthestIntersection = null;
  154. for (let i = 0; i < intersections.length; i += 1) {
  155. const intersection = intersections[i];
  156. const distance = anchor.squaredDistance(intersection);
  157. if (farthestIntersectionDistance == null ||
  158. distance > farthestIntersectionDistance) {
  159. farthestIntersectionDistance = distance;
  160. farthestIntersection = intersection;
  161. }
  162. }
  163. // If an intersection was found in this direction, it is our rectPoint
  164. if (farthestIntersection) {
  165. let target = align(farthestIntersection, grid, precision);
  166. // If the rectPoint lies inside the bbox, offset it by one more step
  167. if (bbox.containsPoint(target)) {
  168. target = align(target.translate(direction.x * grid.x, direction.y * grid.y), grid, precision);
  169. }
  170. res.push(target);
  171. }
  172. }
  173. return res;
  174. }, []);
  175. // if anchor lies outside of bbox, add it to the array of points
  176. if (!bbox.containsPoint(anchor)) {
  177. rectPoints.push(align(anchor, grid, precision));
  178. }
  179. return rectPoints;
  180. }
  181. exports.getRectPoints = getRectPoints;
  182. // reconstructs a route by concatenating points with their parents
  183. function reconstructRoute(parents, points, tailPoint, from, to) {
  184. const route = [];
  185. let prevDiff = normalizePoint(to.diff(tailPoint));
  186. // tailPoint is assumed to be aligned already
  187. let currentKey = getKey(tailPoint);
  188. let parent = parents[currentKey];
  189. let point;
  190. while (parent) {
  191. // point is assumed to be aligned already
  192. point = points[currentKey];
  193. const diff = normalizePoint(point.diff(parent));
  194. if (!diff.equals(prevDiff)) {
  195. route.unshift(point);
  196. prevDiff = diff;
  197. }
  198. // parent is assumed to be aligned already
  199. currentKey = getKey(parent);
  200. parent = parents[currentKey];
  201. }
  202. // leadPoint is assumed to be aligned already
  203. const leadPoint = points[currentKey];
  204. const fromDiff = normalizePoint(leadPoint.diff(from));
  205. if (!fromDiff.equals(prevDiff)) {
  206. route.unshift(leadPoint);
  207. }
  208. return route;
  209. }
  210. exports.reconstructRoute = reconstructRoute;
  211. //# sourceMappingURL=util.js.map