@logicflow/core 2.1.10 → 2.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -449,7 +449,9 @@ var PolylineEdgeModel = /** @class */ (function (_super) {
449
449
  y: this.endPoint.y,
450
450
  }, this.sourceNode, this.targetNode, this.offset || 0);
451
451
  this.pointsList = this.orthogonalizePath(pointsList);
452
- this.points = pointsList.map(function (point) { return "".concat(point.x, ",").concat(point.y); }).join(' ');
452
+ this.points = this.pointsList
453
+ .map(function (point) { return "".concat(point.x, ",").concat(point.y); })
454
+ .join(' ');
453
455
  };
454
456
  PolylineEdgeModel.prototype.updateStartPoint = function (anchor) {
455
457
  this.startPoint = Object.assign({}, anchor);
package/es/util/edge.d.ts CHANGED
@@ -14,6 +14,15 @@ export declare const filterRepeatPoints: (points: Point[]) => Point[];
14
14
  export declare const getSimplePolyline: (sPoint: Point, tPoint: Point) => Point[];
15
15
  export declare const getExpandedBBox: (bbox: BoxBounds, offset: number) => BoxBounds;
16
16
  export declare const pointDirection: (point: Point, bbox: BoxBounds) => Direction;
17
+ /**
18
+ * 计算扩展包围盒上的相邻点(起点或终点的下一个/上一个拐点)
19
+ * - 使用原始节点 bbox 来判定点相对中心的方向,避免 offset 扩展后宽高改变导致方向误判
20
+ * - 若 start 相对中心为水平方向,则返回扩展盒在 x 上的边界,y 保持不变
21
+ * - 若为垂直方向,则返回扩展盒在 y 上的边界,x 保持不变
22
+ * @param expendBBox 扩展后的包围盒(包含 offset)
23
+ * @param bbox 原始节点包围盒(用于正确的方向判定)
24
+ * @param point 起点或终点坐标
25
+ */
17
26
  export declare const getExpandedBBoxPoint: (expendBBox: BoxBounds, bbox: BoxBounds, point: Point) => Point;
18
27
  export declare const mergeBBox: (b1: BoxBounds, b2: BoxBounds) => BoxBounds;
19
28
  export declare const getBBoxOfPoints: (points?: Point[], offset?: number) => BoxBounds;
@@ -32,10 +41,36 @@ export declare const rebuildPath: (pathPoints: Point[], pointById: PolyPointMap,
32
41
  export declare const removeClosePointFromOpenList: (arr: Point[], item: Point) => void;
33
42
  export declare const isSegmentsIntersected: (p0: Point, p1: Point, p2: Point, p3: Point) => boolean;
34
43
  export declare const isSegmentCrossingBBox: (p1: Point, p2: Point, bbox: BoxBounds) => boolean;
44
+ /**
45
+ * 基于轴对齐规则获取某点的相邻可连通点(不穿越节点)
46
+ * - 仅考虑 x 或 y 相同的候选点,保证严格水平/垂直
47
+ * - 使用 isSegmentCrossingBBox 校验线段不穿越源/目标节点
48
+ */
35
49
  export declare const getNextNeighborPoints: (points: Point[], point: Point, bbox1: BoxBounds, bbox2: BoxBounds) => Point[];
50
+ /**
51
+ * 使用 A* + 曼哈顿启发式在候选点图上查找正交路径
52
+ * - 开放集/关闭集管理遍历
53
+ * - gScore 为累计实际代价,fScore = gScore + 启发式
54
+ * - 邻居仅为与当前点 x 或 y 相同且不穿越节点的点
55
+ * 参考:https://zh.wikipedia.org/wiki/A*%E6%90%9C%E5%B0%8B%E6%BC%94%E7%AE%97%E6%B3%95
56
+ */
36
57
  export declare const pathFinder: (points: Point[], start: Point, goal: Point, sBBox: BoxBounds, tBBox: BoxBounds, os: Point, ot: Point) => Point[];
37
58
  export declare const getBoxByOriginNode: (node: BaseNodeModel) => BoxBounds;
59
+ /**
60
+ * 去除共线冗余中间点,保持每条直线段仅保留两端点
61
+ * - 若三点在同一水平线或同一垂直线,移除中间点
62
+ */
38
63
  export declare const pointFilter: (points: Point[]) => Point[];
64
+ /**
65
+ * 计算折线点(正交候选点 + A* 路径)
66
+ * 步骤:
67
+ * 1) 取源/目标节点的扩展包围盒与相邻点 sPoint/tPoint
68
+ * 2) 若两个扩展盒重合,使用简单路径 getSimplePoints
69
+ * 3) 构造 lineBBox/sMixBBox/tMixBBox,并收集其角点与中心交点
70
+ * 4) 过滤掉落在两个扩展盒内部的点,形成 connectPoints
71
+ * 5) 以 sPoint/tPoint 为起止,用 A* 查找路径
72
+ * 6) 拼入原始 start/end,并用 pointFilter 去除冗余共线点
73
+ */
39
74
  export declare const getPolylinePoints: (start: Point, end: Point, sNode: BaseNodeModel, tNode: BaseNodeModel, offset: number) => Point[];
40
75
  /**
41
76
  * 获取折线中最长的一个线
@@ -47,6 +82,10 @@ export declare const isSegmentsCrossNode: (start: Point, end: Point, node: BaseN
47
82
  export declare const getCrossPointInRect: (start: Point, end: Point, node: BaseNodeModel) => Point | false | undefined;
48
83
  export declare const segmentDirection: (start: Point, end: Point) => Direction | undefined;
49
84
  export declare const points2PointsList: (points: string) => Point[];
85
+ /**
86
+ * 当扩展 bbox 重合时的简化拐点计算
87
+ * - 根据起止段的方向(水平/垂直)插入 1~2 个中间点,避免折线重合与穿越
88
+ */
50
89
  export declare const getSimplePoints: (start: Point, end: Point, sPoint: Point, tPoint: Point) => Point[];
51
90
  export declare const getBytesLength: (word: string) => number;
52
91
  export declare const getTextWidth: (text: string, font: string) => number;
package/es/util/edge.js CHANGED
@@ -113,6 +113,15 @@ export var pointDirection = function (point, bbox) {
113
113
  : SegmentDirection.VERTICAL;
114
114
  };
115
115
  /* 获取扩展图形上的点,即起始终点相邻的点,上一个或者下一个节点 */
116
+ /**
117
+ * 计算扩展包围盒上的相邻点(起点或终点的下一个/上一个拐点)
118
+ * - 使用原始节点 bbox 来判定点相对中心的方向,避免 offset 扩展后宽高改变导致方向误判
119
+ * - 若 start 相对中心为水平方向,则返回扩展盒在 x 上的边界,y 保持不变
120
+ * - 若为垂直方向,则返回扩展盒在 y 上的边界,x 保持不变
121
+ * @param expendBBox 扩展后的包围盒(包含 offset)
122
+ * @param bbox 原始节点包围盒(用于正确的方向判定)
123
+ * @param point 起点或终点坐标
124
+ */
116
125
  export var getExpandedBBoxPoint = function (expendBBox, bbox, point) {
117
126
  // https://github.com/didi/LogicFlow/issues/817
118
127
  // 没有修复前传入的参数bbox实际是expendBBox
@@ -313,7 +322,11 @@ export var isSegmentCrossingBBox = function (p1, p2, bbox) {
313
322
  isSegmentsIntersected(p1, p2, pb, pc) ||
314
323
  isSegmentsIntersected(p1, p2, pc, pd));
315
324
  };
316
- /* 获取下一个相邻的点 */
325
+ /**
326
+ * 基于轴对齐规则获取某点的相邻可连通点(不穿越节点)
327
+ * - 仅考虑 x 或 y 相同的候选点,保证严格水平/垂直
328
+ * - 使用 isSegmentCrossingBBox 校验线段不穿越源/目标节点
329
+ */
317
330
  export var getNextNeighborPoints = function (points, point, bbox1, bbox2) {
318
331
  var neighbors = [];
319
332
  points.forEach(function (p) {
@@ -328,9 +341,12 @@ export var getNextNeighborPoints = function (points, point, bbox1, bbox2) {
328
341
  });
329
342
  return filterRepeatPoints(neighbors);
330
343
  };
331
- /* 路径查找,AStar查找+曼哈顿距离
332
- * 算法wiki:https://zh.wikipedia.org/wiki/A*%E6%90%9C%E5%B0%8B%E6%BC%94%E7%AE%97%E6%B3%95
333
- * 方法无法复用,且调用了很多polyline相关的方法,暂不抽离到src/algorithm中
344
+ /**
345
+ * 使用 A* + 曼哈顿启发式在候选点图上查找正交路径
346
+ * - 开放集/关闭集管理遍历
347
+ * - gScore 为累计实际代价,fScore = gScore + 启发式
348
+ * - 邻居仅为与当前点 x 或 y 相同且不穿越节点的点
349
+ * 参考:https://zh.wikipedia.org/wiki/A*%E6%90%9C%E5%B0%8B%E6%BC%94%E7%AE%97%E6%B3%95
334
350
  */
335
351
  export var pathFinder = function (points, start, goal, sBBox, tBBox, os, ot) {
336
352
  // 定义已经遍历过的点
@@ -371,6 +387,7 @@ export var pathFinder = function (points, start, goal, sBBox, tBBox, os, ot) {
371
387
  removeClosePointFromOpenList(openSet, current);
372
388
  closedSet.push(current);
373
389
  getNextNeighborPoints(points, current, sBBox, tBBox).forEach(function (neighbor) {
390
+ var _a;
374
391
  if (closedSet.indexOf(neighbor) !== -1) {
375
392
  return;
376
393
  }
@@ -378,7 +395,8 @@ export var pathFinder = function (points, start, goal, sBBox, tBBox, os, ot) {
378
395
  openSet.push(neighbor);
379
396
  }
380
397
  if ((current === null || current === void 0 ? void 0 : current.id) && (neighbor === null || neighbor === void 0 ? void 0 : neighbor.id)) {
381
- var tentativeGScore = fScore[current.id] + estimateDistance(current, neighbor);
398
+ // 修复:累计代价应基于 gScore[current] 而非 fScore[current]
399
+ var tentativeGScore = ((_a = gScore[current.id]) !== null && _a !== void 0 ? _a : 0) + estimateDistance(current, neighbor);
382
400
  if (gScore[neighbor.id] && tentativeGScore >= gScore[neighbor.id]) {
383
401
  return;
384
402
  }
@@ -400,7 +418,10 @@ export var pathFinder = function (points, start, goal, sBBox, tBBox, os, ot) {
400
418
  export var getBoxByOriginNode = function (node) {
401
419
  return getNodeBBox(node);
402
420
  };
403
- /* 保证一条直线上只有2个节点: 删除x/y相同的中间节点 */
421
+ /**
422
+ * 去除共线冗余中间点,保持每条直线段仅保留两端点
423
+ * - 若三点在同一水平线或同一垂直线,移除中间点
424
+ */
404
425
  export var pointFilter = function (points) {
405
426
  var i = 1;
406
427
  while (i < points.length - 1) {
@@ -417,7 +438,16 @@ export var pointFilter = function (points) {
417
438
  }
418
439
  return points;
419
440
  };
420
- /* 计算折线点 */
441
+ /**
442
+ * 计算折线点(正交候选点 + A* 路径)
443
+ * 步骤:
444
+ * 1) 取源/目标节点的扩展包围盒与相邻点 sPoint/tPoint
445
+ * 2) 若两个扩展盒重合,使用简单路径 getSimplePoints
446
+ * 3) 构造 lineBBox/sMixBBox/tMixBBox,并收集其角点与中心交点
447
+ * 4) 过滤掉落在两个扩展盒内部的点,形成 connectPoints
448
+ * 5) 以 sPoint/tPoint 为起止,用 A* 查找路径
449
+ * 6) 拼入原始 start/end,并用 pointFilter 去除冗余共线点
450
+ */
421
451
  export var getPolylinePoints = function (start, end, sNode, tNode, offset) {
422
452
  var sBBox = getBoxByOriginNode(sNode);
423
453
  var tBBox = getBoxByOriginNode(tNode);
@@ -554,6 +584,10 @@ export var points2PointsList = function (points) {
554
584
  });
555
585
  return pointsList;
556
586
  };
587
+ /**
588
+ * 当扩展 bbox 重合时的简化拐点计算
589
+ * - 根据起止段的方向(水平/垂直)插入 1~2 个中间点,避免折线重合与穿越
590
+ */
557
591
  export var getSimplePoints = function (start, end, sPoint, tPoint) {
558
592
  var points = [];
559
593
  // start,sPoint的方向,水平或者垂直,即路径第一条线段的方向
@@ -452,7 +452,9 @@ var PolylineEdgeModel = /** @class */ (function (_super) {
452
452
  y: this.endPoint.y,
453
453
  }, this.sourceNode, this.targetNode, this.offset || 0);
454
454
  this.pointsList = this.orthogonalizePath(pointsList);
455
- this.points = pointsList.map(function (point) { return "".concat(point.x, ",").concat(point.y); }).join(' ');
455
+ this.points = this.pointsList
456
+ .map(function (point) { return "".concat(point.x, ",").concat(point.y); })
457
+ .join(' ');
456
458
  };
457
459
  PolylineEdgeModel.prototype.updateStartPoint = function (anchor) {
458
460
  this.startPoint = Object.assign({}, anchor);
@@ -14,6 +14,15 @@ export declare const filterRepeatPoints: (points: Point[]) => Point[];
14
14
  export declare const getSimplePolyline: (sPoint: Point, tPoint: Point) => Point[];
15
15
  export declare const getExpandedBBox: (bbox: BoxBounds, offset: number) => BoxBounds;
16
16
  export declare const pointDirection: (point: Point, bbox: BoxBounds) => Direction;
17
+ /**
18
+ * 计算扩展包围盒上的相邻点(起点或终点的下一个/上一个拐点)
19
+ * - 使用原始节点 bbox 来判定点相对中心的方向,避免 offset 扩展后宽高改变导致方向误判
20
+ * - 若 start 相对中心为水平方向,则返回扩展盒在 x 上的边界,y 保持不变
21
+ * - 若为垂直方向,则返回扩展盒在 y 上的边界,x 保持不变
22
+ * @param expendBBox 扩展后的包围盒(包含 offset)
23
+ * @param bbox 原始节点包围盒(用于正确的方向判定)
24
+ * @param point 起点或终点坐标
25
+ */
17
26
  export declare const getExpandedBBoxPoint: (expendBBox: BoxBounds, bbox: BoxBounds, point: Point) => Point;
18
27
  export declare const mergeBBox: (b1: BoxBounds, b2: BoxBounds) => BoxBounds;
19
28
  export declare const getBBoxOfPoints: (points?: Point[], offset?: number) => BoxBounds;
@@ -32,10 +41,36 @@ export declare const rebuildPath: (pathPoints: Point[], pointById: PolyPointMap,
32
41
  export declare const removeClosePointFromOpenList: (arr: Point[], item: Point) => void;
33
42
  export declare const isSegmentsIntersected: (p0: Point, p1: Point, p2: Point, p3: Point) => boolean;
34
43
  export declare const isSegmentCrossingBBox: (p1: Point, p2: Point, bbox: BoxBounds) => boolean;
44
+ /**
45
+ * 基于轴对齐规则获取某点的相邻可连通点(不穿越节点)
46
+ * - 仅考虑 x 或 y 相同的候选点,保证严格水平/垂直
47
+ * - 使用 isSegmentCrossingBBox 校验线段不穿越源/目标节点
48
+ */
35
49
  export declare const getNextNeighborPoints: (points: Point[], point: Point, bbox1: BoxBounds, bbox2: BoxBounds) => Point[];
50
+ /**
51
+ * 使用 A* + 曼哈顿启发式在候选点图上查找正交路径
52
+ * - 开放集/关闭集管理遍历
53
+ * - gScore 为累计实际代价,fScore = gScore + 启发式
54
+ * - 邻居仅为与当前点 x 或 y 相同且不穿越节点的点
55
+ * 参考:https://zh.wikipedia.org/wiki/A*%E6%90%9C%E5%B0%8B%E6%BC%94%E7%AE%97%E6%B3%95
56
+ */
36
57
  export declare const pathFinder: (points: Point[], start: Point, goal: Point, sBBox: BoxBounds, tBBox: BoxBounds, os: Point, ot: Point) => Point[];
37
58
  export declare const getBoxByOriginNode: (node: BaseNodeModel) => BoxBounds;
59
+ /**
60
+ * 去除共线冗余中间点,保持每条直线段仅保留两端点
61
+ * - 若三点在同一水平线或同一垂直线,移除中间点
62
+ */
38
63
  export declare const pointFilter: (points: Point[]) => Point[];
64
+ /**
65
+ * 计算折线点(正交候选点 + A* 路径)
66
+ * 步骤:
67
+ * 1) 取源/目标节点的扩展包围盒与相邻点 sPoint/tPoint
68
+ * 2) 若两个扩展盒重合,使用简单路径 getSimplePoints
69
+ * 3) 构造 lineBBox/sMixBBox/tMixBBox,并收集其角点与中心交点
70
+ * 4) 过滤掉落在两个扩展盒内部的点,形成 connectPoints
71
+ * 5) 以 sPoint/tPoint 为起止,用 A* 查找路径
72
+ * 6) 拼入原始 start/end,并用 pointFilter 去除冗余共线点
73
+ */
39
74
  export declare const getPolylinePoints: (start: Point, end: Point, sNode: BaseNodeModel, tNode: BaseNodeModel, offset: number) => Point[];
40
75
  /**
41
76
  * 获取折线中最长的一个线
@@ -47,6 +82,10 @@ export declare const isSegmentsCrossNode: (start: Point, end: Point, node: BaseN
47
82
  export declare const getCrossPointInRect: (start: Point, end: Point, node: BaseNodeModel) => Point | false | undefined;
48
83
  export declare const segmentDirection: (start: Point, end: Point) => Direction | undefined;
49
84
  export declare const points2PointsList: (points: string) => Point[];
85
+ /**
86
+ * 当扩展 bbox 重合时的简化拐点计算
87
+ * - 根据起止段的方向(水平/垂直)插入 1~2 个中间点,避免折线重合与穿越
88
+ */
50
89
  export declare const getSimplePoints: (start: Point, end: Point, sPoint: Point, tPoint: Point) => Point[];
51
90
  export declare const getBytesLength: (word: string) => number;
52
91
  export declare const getTextWidth: (text: string, font: string) => number;
package/lib/util/edge.js CHANGED
@@ -122,6 +122,15 @@ var pointDirection = function (point, bbox) {
122
122
  };
123
123
  exports.pointDirection = pointDirection;
124
124
  /* 获取扩展图形上的点,即起始终点相邻的点,上一个或者下一个节点 */
125
+ /**
126
+ * 计算扩展包围盒上的相邻点(起点或终点的下一个/上一个拐点)
127
+ * - 使用原始节点 bbox 来判定点相对中心的方向,避免 offset 扩展后宽高改变导致方向误判
128
+ * - 若 start 相对中心为水平方向,则返回扩展盒在 x 上的边界,y 保持不变
129
+ * - 若为垂直方向,则返回扩展盒在 y 上的边界,x 保持不变
130
+ * @param expendBBox 扩展后的包围盒(包含 offset)
131
+ * @param bbox 原始节点包围盒(用于正确的方向判定)
132
+ * @param point 起点或终点坐标
133
+ */
125
134
  var getExpandedBBoxPoint = function (expendBBox, bbox, point) {
126
135
  // https://github.com/didi/LogicFlow/issues/817
127
136
  // 没有修复前传入的参数bbox实际是expendBBox
@@ -337,7 +346,11 @@ var isSegmentCrossingBBox = function (p1, p2, bbox) {
337
346
  (0, exports.isSegmentsIntersected)(p1, p2, pc, pd));
338
347
  };
339
348
  exports.isSegmentCrossingBBox = isSegmentCrossingBBox;
340
- /* 获取下一个相邻的点 */
349
+ /**
350
+ * 基于轴对齐规则获取某点的相邻可连通点(不穿越节点)
351
+ * - 仅考虑 x 或 y 相同的候选点,保证严格水平/垂直
352
+ * - 使用 isSegmentCrossingBBox 校验线段不穿越源/目标节点
353
+ */
341
354
  var getNextNeighborPoints = function (points, point, bbox1, bbox2) {
342
355
  var neighbors = [];
343
356
  points.forEach(function (p) {
@@ -353,9 +366,12 @@ var getNextNeighborPoints = function (points, point, bbox1, bbox2) {
353
366
  return (0, exports.filterRepeatPoints)(neighbors);
354
367
  };
355
368
  exports.getNextNeighborPoints = getNextNeighborPoints;
356
- /* 路径查找,AStar查找+曼哈顿距离
357
- * 算法wiki:https://zh.wikipedia.org/wiki/A*%E6%90%9C%E5%B0%8B%E6%BC%94%E7%AE%97%E6%B3%95
358
- * 方法无法复用,且调用了很多polyline相关的方法,暂不抽离到src/algorithm中
369
+ /**
370
+ * 使用 A* + 曼哈顿启发式在候选点图上查找正交路径
371
+ * - 开放集/关闭集管理遍历
372
+ * - gScore 为累计实际代价,fScore = gScore + 启发式
373
+ * - 邻居仅为与当前点 x 或 y 相同且不穿越节点的点
374
+ * 参考:https://zh.wikipedia.org/wiki/A*%E6%90%9C%E5%B0%8B%E6%BC%94%E7%AE%97%E6%B3%95
359
375
  */
360
376
  var pathFinder = function (points, start, goal, sBBox, tBBox, os, ot) {
361
377
  // 定义已经遍历过的点
@@ -396,6 +412,7 @@ var pathFinder = function (points, start, goal, sBBox, tBBox, os, ot) {
396
412
  (0, exports.removeClosePointFromOpenList)(openSet, current);
397
413
  closedSet.push(current);
398
414
  (0, exports.getNextNeighborPoints)(points, current, sBBox, tBBox).forEach(function (neighbor) {
415
+ var _a;
399
416
  if (closedSet.indexOf(neighbor) !== -1) {
400
417
  return;
401
418
  }
@@ -403,7 +420,8 @@ var pathFinder = function (points, start, goal, sBBox, tBBox, os, ot) {
403
420
  openSet.push(neighbor);
404
421
  }
405
422
  if ((current === null || current === void 0 ? void 0 : current.id) && (neighbor === null || neighbor === void 0 ? void 0 : neighbor.id)) {
406
- var tentativeGScore = fScore[current.id] + (0, exports.estimateDistance)(current, neighbor);
423
+ // 修复:累计代价应基于 gScore[current] 而非 fScore[current]
424
+ var tentativeGScore = ((_a = gScore[current.id]) !== null && _a !== void 0 ? _a : 0) + (0, exports.estimateDistance)(current, neighbor);
407
425
  if (gScore[neighbor.id] && tentativeGScore >= gScore[neighbor.id]) {
408
426
  return;
409
427
  }
@@ -427,7 +445,10 @@ var getBoxByOriginNode = function (node) {
427
445
  return (0, _1.getNodeBBox)(node);
428
446
  };
429
447
  exports.getBoxByOriginNode = getBoxByOriginNode;
430
- /* 保证一条直线上只有2个节点: 删除x/y相同的中间节点 */
448
+ /**
449
+ * 去除共线冗余中间点,保持每条直线段仅保留两端点
450
+ * - 若三点在同一水平线或同一垂直线,移除中间点
451
+ */
431
452
  var pointFilter = function (points) {
432
453
  var i = 1;
433
454
  while (i < points.length - 1) {
@@ -445,7 +466,16 @@ var pointFilter = function (points) {
445
466
  return points;
446
467
  };
447
468
  exports.pointFilter = pointFilter;
448
- /* 计算折线点 */
469
+ /**
470
+ * 计算折线点(正交候选点 + A* 路径)
471
+ * 步骤:
472
+ * 1) 取源/目标节点的扩展包围盒与相邻点 sPoint/tPoint
473
+ * 2) 若两个扩展盒重合,使用简单路径 getSimplePoints
474
+ * 3) 构造 lineBBox/sMixBBox/tMixBBox,并收集其角点与中心交点
475
+ * 4) 过滤掉落在两个扩展盒内部的点,形成 connectPoints
476
+ * 5) 以 sPoint/tPoint 为起止,用 A* 查找路径
477
+ * 6) 拼入原始 start/end,并用 pointFilter 去除冗余共线点
478
+ */
449
479
  var getPolylinePoints = function (start, end, sNode, tNode, offset) {
450
480
  var sBBox = (0, exports.getBoxByOriginNode)(sNode);
451
481
  var tBBox = (0, exports.getBoxByOriginNode)(tNode);
@@ -589,6 +619,10 @@ var points2PointsList = function (points) {
589
619
  return pointsList;
590
620
  };
591
621
  exports.points2PointsList = points2PointsList;
622
+ /**
623
+ * 当扩展 bbox 重合时的简化拐点计算
624
+ * - 根据起止段的方向(水平/垂直)插入 1~2 个中间点,避免折线重合与穿越
625
+ */
592
626
  var getSimplePoints = function (start, end, sPoint, tPoint) {
593
627
  var points = [];
594
628
  // start,sPoint的方向,水平或者垂直,即路径第一条线段的方向
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logicflow/core",
3
- "version": "2.1.10",
3
+ "version": "2.1.11",
4
4
  "description": "LogicFlow, help you quickly create flowcharts",
5
5
  "main": "lib/index.js",
6
6
  "module": "es/index.js",
@@ -504,7 +504,9 @@ export class PolylineEdgeModel extends BaseEdgeModel {
504
504
  this.offset || 0,
505
505
  )
506
506
  this.pointsList = this.orthogonalizePath(pointsList)
507
- this.points = pointsList.map((point) => `${point.x},${point.y}`).join(' ')
507
+ this.points = this.pointsList
508
+ .map((point) => `${point.x},${point.y}`)
509
+ .join(' ')
508
510
  }
509
511
 
510
512
  @action
package/src/util/edge.ts CHANGED
@@ -107,6 +107,15 @@ export const pointDirection = (point: Point, bbox: BoxBounds): Direction => {
107
107
  }
108
108
 
109
109
  /* 获取扩展图形上的点,即起始终点相邻的点,上一个或者下一个节点 */
110
+ /**
111
+ * 计算扩展包围盒上的相邻点(起点或终点的下一个/上一个拐点)
112
+ * - 使用原始节点 bbox 来判定点相对中心的方向,避免 offset 扩展后宽高改变导致方向误判
113
+ * - 若 start 相对中心为水平方向,则返回扩展盒在 x 上的边界,y 保持不变
114
+ * - 若为垂直方向,则返回扩展盒在 y 上的边界,x 保持不变
115
+ * @param expendBBox 扩展后的包围盒(包含 offset)
116
+ * @param bbox 原始节点包围盒(用于正确的方向判定)
117
+ * @param point 起点或终点坐标
118
+ */
110
119
  export const getExpandedBBoxPoint = (
111
120
  expendBBox: BoxBounds,
112
121
  bbox: BoxBounds,
@@ -377,7 +386,11 @@ export const isSegmentCrossingBBox = (
377
386
  )
378
387
  }
379
388
 
380
- /* 获取下一个相邻的点 */
389
+ /**
390
+ * 基于轴对齐规则获取某点的相邻可连通点(不穿越节点)
391
+ * - 仅考虑 x 或 y 相同的候选点,保证严格水平/垂直
392
+ * - 使用 isSegmentCrossingBBox 校验线段不穿越源/目标节点
393
+ */
381
394
  export const getNextNeighborPoints = (
382
395
  points: Point[],
383
396
  point: Point,
@@ -400,9 +413,12 @@ export const getNextNeighborPoints = (
400
413
  return filterRepeatPoints(neighbors)
401
414
  }
402
415
 
403
- /* 路径查找,AStar查找+曼哈顿距离
404
- * 算法wiki:https://zh.wikipedia.org/wiki/A*%E6%90%9C%E5%B0%8B%E6%BC%94%E7%AE%97%E6%B3%95
405
- * 方法无法复用,且调用了很多polyline相关的方法,暂不抽离到src/algorithm中
416
+ /**
417
+ * 使用 A* + 曼哈顿启发式在候选点图上查找正交路径
418
+ * - 开放集/关闭集管理遍历
419
+ * - gScore 为累计实际代价,fScore = gScore + 启发式
420
+ * - 邻居仅为与当前点 x 或 y 相同且不穿越节点的点
421
+ * 参考:https://zh.wikipedia.org/wiki/A*%E6%90%9C%E5%B0%8B%E6%BC%94%E7%AE%97%E6%B3%95
406
422
  */
407
423
  export const pathFinder = (
408
424
  points: Point[],
@@ -474,8 +490,9 @@ export const pathFinder = (
474
490
  }
475
491
 
476
492
  if (current?.id && neighbor?.id) {
493
+ // 修复:累计代价应基于 gScore[current] 而非 fScore[current]
477
494
  const tentativeGScore =
478
- fScore[current.id] + estimateDistance(current, neighbor)
495
+ (gScore[current.id] ?? 0) + estimateDistance(current, neighbor)
479
496
  if (gScore[neighbor.id] && tentativeGScore >= gScore[neighbor.id]) {
480
497
  return
481
498
  }
@@ -494,7 +511,10 @@ export const pathFinder = (
494
511
  export const getBoxByOriginNode = (node: BaseNodeModel): BoxBounds => {
495
512
  return getNodeBBox(node)
496
513
  }
497
- /* 保证一条直线上只有2个节点: 删除x/y相同的中间节点 */
514
+ /**
515
+ * 去除共线冗余中间点,保持每条直线段仅保留两端点
516
+ * - 若三点在同一水平线或同一垂直线,移除中间点
517
+ */
498
518
  export const pointFilter = (points: Point[]): Point[] => {
499
519
  let i = 1
500
520
  while (i < points.length - 1) {
@@ -513,7 +533,16 @@ export const pointFilter = (points: Point[]): Point[] => {
513
533
  return points
514
534
  }
515
535
 
516
- /* 计算折线点 */
536
+ /**
537
+ * 计算折线点(正交候选点 + A* 路径)
538
+ * 步骤:
539
+ * 1) 取源/目标节点的扩展包围盒与相邻点 sPoint/tPoint
540
+ * 2) 若两个扩展盒重合,使用简单路径 getSimplePoints
541
+ * 3) 构造 lineBBox/sMixBBox/tMixBBox,并收集其角点与中心交点
542
+ * 4) 过滤掉落在两个扩展盒内部的点,形成 connectPoints
543
+ * 5) 以 sPoint/tPoint 为起止,用 A* 查找路径
544
+ * 6) 拼入原始 start/end,并用 pointFilter 去除冗余共线点
545
+ */
517
546
  export const getPolylinePoints = (
518
547
  start: Point,
519
548
  end: Point,
@@ -699,6 +728,10 @@ export const points2PointsList = (points: string): Point[] => {
699
728
  return pointsList
700
729
  }
701
730
 
731
+ /**
732
+ * 当扩展 bbox 重合时的简化拐点计算
733
+ * - 根据起止段的方向(水平/垂直)插入 1~2 个中间点,避免折线重合与穿越
734
+ */
702
735
  export const getSimplePoints = (
703
736
  start: Point,
704
737
  end: Point,