@logicflow/core 2.1.8 → 2.1.10
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.
- package/.turbo/turbo-build$colon$dev.log +2 -2
- package/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +12 -0
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/es/model/GraphModel.js +1 -1
- package/es/model/edge/PolylineEdgeModel.d.ts +7 -0
- package/es/model/edge/PolylineEdgeModel.js +133 -6
- package/es/tool/MultipleSelectTool.js +4 -0
- package/es/view/overlay/CanvasOverlay.js +3 -0
- package/lib/model/GraphModel.js +1 -1
- package/lib/model/edge/PolylineEdgeModel.d.ts +7 -0
- package/lib/model/edge/PolylineEdgeModel.js +133 -6
- package/lib/tool/MultipleSelectTool.js +4 -0
- package/lib/view/overlay/CanvasOverlay.js +3 -0
- package/package.json +1 -1
- package/src/model/GraphModel.ts +2 -1
- package/src/model/edge/PolylineEdgeModel.ts +159 -16
- package/src/tool/MultipleSelectTool.tsx +7 -0
- package/src/view/overlay/CanvasOverlay.tsx +2 -0
- package/stats.html +1 -1
package/es/model/GraphModel.js
CHANGED
|
@@ -12,6 +12,13 @@ export declare class PolylineEdgeModel extends BaseEdgeModel {
|
|
|
12
12
|
offset?: number;
|
|
13
13
|
dbClickPosition?: Point;
|
|
14
14
|
initEdgeData(data: LogicFlow.EdgeConfig): void;
|
|
15
|
+
setAttributes(): void;
|
|
16
|
+
orthogonalizePath(points: Point[]): Point[];
|
|
17
|
+
/**
|
|
18
|
+
* 计算默认 offset:箭头与折线重叠长度 + 5
|
|
19
|
+
* 重叠长度采用箭头样式中的 offset(沿边方向的长度)
|
|
20
|
+
*/
|
|
21
|
+
private getDefaultOffset;
|
|
15
22
|
getEdgeStyle(): {
|
|
16
23
|
[x: string]: unknown;
|
|
17
24
|
fill?: string | undefined;
|
|
@@ -69,12 +69,139 @@ var PolylineEdgeModel = /** @class */ (function (_super) {
|
|
|
69
69
|
return _this;
|
|
70
70
|
}
|
|
71
71
|
PolylineEdgeModel.prototype.initEdgeData = function (data) {
|
|
72
|
-
|
|
72
|
+
var providedOffset = get(data, 'properties.offset');
|
|
73
|
+
// 当用户未传入 offset 时,按“箭头与折线重叠长度 + 5”作为默认值
|
|
74
|
+
// 其中“重叠长度”采用箭头样式中的 offset(沿边方向的长度)
|
|
75
|
+
this.offset =
|
|
76
|
+
typeof providedOffset === 'number'
|
|
77
|
+
? providedOffset
|
|
78
|
+
: this.getDefaultOffset();
|
|
73
79
|
if (data.pointsList) {
|
|
74
|
-
|
|
80
|
+
var corrected = this.orthogonalizePath(data.pointsList);
|
|
81
|
+
data.pointsList = corrected;
|
|
82
|
+
this.pointsList = corrected;
|
|
75
83
|
}
|
|
76
84
|
_super.prototype.initEdgeData.call(this, data);
|
|
77
85
|
};
|
|
86
|
+
PolylineEdgeModel.prototype.setAttributes = function () {
|
|
87
|
+
var newOffset = this.properties.offset;
|
|
88
|
+
if (newOffset && newOffset !== this.offset) {
|
|
89
|
+
this.offset = newOffset;
|
|
90
|
+
this.updatePoints();
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
PolylineEdgeModel.prototype.orthogonalizePath = function (points) {
|
|
94
|
+
// 输入非法或不足两点时直接返回副本
|
|
95
|
+
if (!Array.isArray(points) || points.length < 2) {
|
|
96
|
+
return points;
|
|
97
|
+
}
|
|
98
|
+
// pushUnique: 向数组中添加唯一点,避免重复
|
|
99
|
+
var pushUnique = function (arr, p) {
|
|
100
|
+
var last = arr[arr.length - 1];
|
|
101
|
+
if (!last || last.x !== p.x || last.y !== p.y) {
|
|
102
|
+
arr.push({ x: p.x, y: p.y });
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
// isAxisAligned: 检查两点是否在同一条轴上
|
|
106
|
+
var isAxisAligned = function (a, b) { return a.x === b.x || a.y === b.y; };
|
|
107
|
+
// manhattanDistance: 计算两点在曼哈顿距离上的距离
|
|
108
|
+
var manhattanDistance = function (a, b) {
|
|
109
|
+
return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
110
|
+
};
|
|
111
|
+
// 1) 生成严格正交路径,尽量延续前一段方向以减少折点
|
|
112
|
+
var orthogonal = [];
|
|
113
|
+
pushUnique(orthogonal, points[0]);
|
|
114
|
+
// previousDirection: 记录前一段的方向,用于判断当前段的PreferredCorner
|
|
115
|
+
var previousDirection;
|
|
116
|
+
// 遍历所有点对,生成正交路径
|
|
117
|
+
for (var i = 0; i < points.length - 1; i++) {
|
|
118
|
+
var current = orthogonal[orthogonal.length - 1];
|
|
119
|
+
var next = points[i + 1];
|
|
120
|
+
if (!current || !next)
|
|
121
|
+
continue;
|
|
122
|
+
if (isAxisAligned(current, next)) {
|
|
123
|
+
pushUnique(orthogonal, next);
|
|
124
|
+
previousDirection =
|
|
125
|
+
current.x === next.x
|
|
126
|
+
? SegmentDirection.VERTICAL
|
|
127
|
+
: SegmentDirection.HORIZONTAL;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
var cornerHV = { x: next.x, y: current.y };
|
|
131
|
+
var cornerVH = { x: current.x, y: next.y };
|
|
132
|
+
// 根据前一段的方向,优先选择能延续该方向的拐角点,以减少折点数量;
|
|
133
|
+
// 若前一段为垂直方向,则优先选择垂直-水平拐角(cornerVH);
|
|
134
|
+
// 若前一段为水平方向,则优先选择水平-垂直拐角(cornerHV);
|
|
135
|
+
// 若前一段无方向(初始情况),则比较两个拐角的曼哈顿距离,选更近者。
|
|
136
|
+
var preferredCorner = previousDirection === SegmentDirection.VERTICAL
|
|
137
|
+
? cornerVH
|
|
138
|
+
: previousDirection === SegmentDirection.HORIZONTAL
|
|
139
|
+
? cornerHV
|
|
140
|
+
: manhattanDistance(current, cornerHV) <=
|
|
141
|
+
manhattanDistance(current, cornerVH)
|
|
142
|
+
? cornerHV
|
|
143
|
+
: cornerVH;
|
|
144
|
+
if (preferredCorner.x !== current.x || preferredCorner.y !== current.y) {
|
|
145
|
+
pushUnique(orthogonal, preferredCorner);
|
|
146
|
+
}
|
|
147
|
+
pushUnique(orthogonal, next);
|
|
148
|
+
var a = orthogonal[orthogonal.length - 2];
|
|
149
|
+
var b = orthogonal[orthogonal.length - 1];
|
|
150
|
+
previousDirection =
|
|
151
|
+
a && b
|
|
152
|
+
? a.x === b.x
|
|
153
|
+
? SegmentDirection.VERTICAL
|
|
154
|
+
: SegmentDirection.HORIZONTAL
|
|
155
|
+
: previousDirection;
|
|
156
|
+
}
|
|
157
|
+
// 2) 去除冗余共线中间点
|
|
158
|
+
var simplified = [];
|
|
159
|
+
for (var i = 0; i < orthogonal.length; i++) {
|
|
160
|
+
var prev = orthogonal[i - 1];
|
|
161
|
+
var curr = orthogonal[i];
|
|
162
|
+
var next = orthogonal[i + 1];
|
|
163
|
+
// 如果当前点与前一个点和后一个点在同一条水平线或垂直线上,则跳过该点,去除冗余的共线中间点
|
|
164
|
+
if (prev &&
|
|
165
|
+
curr &&
|
|
166
|
+
next &&
|
|
167
|
+
((prev.x === curr.x && curr.x === next.x) || // 水平共线
|
|
168
|
+
(prev.y === curr.y && curr.y === next.y)) // 垂直共线
|
|
169
|
+
) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
pushUnique(simplified, curr);
|
|
173
|
+
}
|
|
174
|
+
// 3) 保留原始起点与终点位置
|
|
175
|
+
if (simplified.length >= 2) {
|
|
176
|
+
simplified[0] = { x: points[0].x, y: points[0].y };
|
|
177
|
+
simplified[simplified.length - 1] = {
|
|
178
|
+
x: points[points.length - 1].x,
|
|
179
|
+
y: points[points.length - 1].y,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
// 4) 结果校验:任意相邻段都必须为水平/垂直;失败则退化为起止两点
|
|
183
|
+
var isOrthogonal = simplified.length < 2 ||
|
|
184
|
+
simplified.every(function (_, idx, arr) {
|
|
185
|
+
if (idx === 0)
|
|
186
|
+
return true;
|
|
187
|
+
return isAxisAligned(arr[idx - 1], arr[idx]);
|
|
188
|
+
});
|
|
189
|
+
return isOrthogonal
|
|
190
|
+
? simplified
|
|
191
|
+
: [
|
|
192
|
+
{ x: points[0].x, y: points[0].y },
|
|
193
|
+
{ x: points[points.length - 1].x, y: points[points.length - 1].y },
|
|
194
|
+
];
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* 计算默认 offset:箭头与折线重叠长度 + 5
|
|
198
|
+
* 重叠长度采用箭头样式中的 offset(沿边方向的长度)
|
|
199
|
+
*/
|
|
200
|
+
PolylineEdgeModel.prototype.getDefaultOffset = function () {
|
|
201
|
+
var arrowStyle = this.getArrowStyle();
|
|
202
|
+
var arrowOverlap = typeof arrowStyle.offset === 'number' ? arrowStyle.offset : 0;
|
|
203
|
+
return arrowOverlap + 5;
|
|
204
|
+
};
|
|
78
205
|
PolylineEdgeModel.prototype.getEdgeStyle = function () {
|
|
79
206
|
var polyline = this.graphModel.theme.polyline;
|
|
80
207
|
var style = _super.prototype.getEdgeStyle.call(this);
|
|
@@ -286,7 +413,7 @@ var PolylineEdgeModel = /** @class */ (function (_super) {
|
|
|
286
413
|
return list;
|
|
287
414
|
};
|
|
288
415
|
PolylineEdgeModel.prototype.updatePath = function (pointList) {
|
|
289
|
-
this.pointsList = pointList;
|
|
416
|
+
this.pointsList = this.orthogonalizePath(pointList);
|
|
290
417
|
this.points = this.getPath(this.pointsList);
|
|
291
418
|
};
|
|
292
419
|
PolylineEdgeModel.prototype.getData = function () {
|
|
@@ -321,7 +448,7 @@ var PolylineEdgeModel = /** @class */ (function (_super) {
|
|
|
321
448
|
x: this.endPoint.x,
|
|
322
449
|
y: this.endPoint.y,
|
|
323
450
|
}, this.sourceNode, this.targetNode, this.offset || 0);
|
|
324
|
-
this.pointsList = pointsList;
|
|
451
|
+
this.pointsList = this.orthogonalizePath(pointsList);
|
|
325
452
|
this.points = pointsList.map(function (point) { return "".concat(point.x, ",").concat(point.y); }).join(' ');
|
|
326
453
|
};
|
|
327
454
|
PolylineEdgeModel.prototype.updateStartPoint = function (anchor) {
|
|
@@ -544,13 +671,13 @@ var PolylineEdgeModel = /** @class */ (function (_super) {
|
|
|
544
671
|
// 起终点拖拽调整过程中,进行折线路径更新
|
|
545
672
|
PolylineEdgeModel.prototype.updateAfterAdjustStartAndEnd = function (_a) {
|
|
546
673
|
var startPoint = _a.startPoint, endPoint = _a.endPoint, sourceNode = _a.sourceNode, targetNode = _a.targetNode;
|
|
547
|
-
this.pointsList = getPolylinePoints({
|
|
674
|
+
this.pointsList = this.orthogonalizePath(getPolylinePoints({
|
|
548
675
|
x: startPoint.x,
|
|
549
676
|
y: startPoint.y,
|
|
550
677
|
}, {
|
|
551
678
|
x: endPoint.x,
|
|
552
679
|
y: endPoint.y,
|
|
553
|
-
}, sourceNode, targetNode, this.offset || 0);
|
|
680
|
+
}, sourceNode, targetNode, this.offset || 0));
|
|
554
681
|
this.initPoints();
|
|
555
682
|
};
|
|
556
683
|
__decorate([
|
|
@@ -55,6 +55,10 @@ var MultipleSelect = /** @class */ (function (_super) {
|
|
|
55
55
|
function MultipleSelect(props) {
|
|
56
56
|
var _this = _super.call(this, props) || this;
|
|
57
57
|
_this.handleMouseDown = function (ev) {
|
|
58
|
+
// 多选区域的拖拽步长随缩放变化
|
|
59
|
+
var _a = _this.props, gridSize = _a.graphModel.gridSize, lf = _a.lf;
|
|
60
|
+
var SCALE_X = lf.getTransform().SCALE_X;
|
|
61
|
+
_this.stepDrag.setStep(gridSize * SCALE_X);
|
|
58
62
|
_this.stepDrag.handleMouseDown(ev);
|
|
59
63
|
};
|
|
60
64
|
// 使多选区域的滚轮事件可以触发画布的滚轮事件
|
|
@@ -103,6 +103,9 @@ var CanvasOverlay = /** @class */ (function (_super) {
|
|
|
103
103
|
if (selectElements.size > 0) {
|
|
104
104
|
graphModel.clearSelectElements();
|
|
105
105
|
}
|
|
106
|
+
// 如果是拖拽状态,不触发点击事件
|
|
107
|
+
if (_this.state.isDragging)
|
|
108
|
+
return;
|
|
106
109
|
graphModel.eventCenter.emit(EventType.BLANK_CLICK, { e: ev });
|
|
107
110
|
}
|
|
108
111
|
};
|
package/lib/model/GraphModel.js
CHANGED
|
@@ -12,6 +12,13 @@ export declare class PolylineEdgeModel extends BaseEdgeModel {
|
|
|
12
12
|
offset?: number;
|
|
13
13
|
dbClickPosition?: Point;
|
|
14
14
|
initEdgeData(data: LogicFlow.EdgeConfig): void;
|
|
15
|
+
setAttributes(): void;
|
|
16
|
+
orthogonalizePath(points: Point[]): Point[];
|
|
17
|
+
/**
|
|
18
|
+
* 计算默认 offset:箭头与折线重叠长度 + 5
|
|
19
|
+
* 重叠长度采用箭头样式中的 offset(沿边方向的长度)
|
|
20
|
+
*/
|
|
21
|
+
private getDefaultOffset;
|
|
15
22
|
getEdgeStyle(): {
|
|
16
23
|
[x: string]: unknown;
|
|
17
24
|
fill?: string | undefined;
|
|
@@ -72,12 +72,139 @@ var PolylineEdgeModel = /** @class */ (function (_super) {
|
|
|
72
72
|
return _this;
|
|
73
73
|
}
|
|
74
74
|
PolylineEdgeModel.prototype.initEdgeData = function (data) {
|
|
75
|
-
|
|
75
|
+
var providedOffset = (0, lodash_es_1.get)(data, 'properties.offset');
|
|
76
|
+
// 当用户未传入 offset 时,按“箭头与折线重叠长度 + 5”作为默认值
|
|
77
|
+
// 其中“重叠长度”采用箭头样式中的 offset(沿边方向的长度)
|
|
78
|
+
this.offset =
|
|
79
|
+
typeof providedOffset === 'number'
|
|
80
|
+
? providedOffset
|
|
81
|
+
: this.getDefaultOffset();
|
|
76
82
|
if (data.pointsList) {
|
|
77
|
-
|
|
83
|
+
var corrected = this.orthogonalizePath(data.pointsList);
|
|
84
|
+
data.pointsList = corrected;
|
|
85
|
+
this.pointsList = corrected;
|
|
78
86
|
}
|
|
79
87
|
_super.prototype.initEdgeData.call(this, data);
|
|
80
88
|
};
|
|
89
|
+
PolylineEdgeModel.prototype.setAttributes = function () {
|
|
90
|
+
var newOffset = this.properties.offset;
|
|
91
|
+
if (newOffset && newOffset !== this.offset) {
|
|
92
|
+
this.offset = newOffset;
|
|
93
|
+
this.updatePoints();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
PolylineEdgeModel.prototype.orthogonalizePath = function (points) {
|
|
97
|
+
// 输入非法或不足两点时直接返回副本
|
|
98
|
+
if (!Array.isArray(points) || points.length < 2) {
|
|
99
|
+
return points;
|
|
100
|
+
}
|
|
101
|
+
// pushUnique: 向数组中添加唯一点,避免重复
|
|
102
|
+
var pushUnique = function (arr, p) {
|
|
103
|
+
var last = arr[arr.length - 1];
|
|
104
|
+
if (!last || last.x !== p.x || last.y !== p.y) {
|
|
105
|
+
arr.push({ x: p.x, y: p.y });
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
// isAxisAligned: 检查两点是否在同一条轴上
|
|
109
|
+
var isAxisAligned = function (a, b) { return a.x === b.x || a.y === b.y; };
|
|
110
|
+
// manhattanDistance: 计算两点在曼哈顿距离上的距离
|
|
111
|
+
var manhattanDistance = function (a, b) {
|
|
112
|
+
return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
|
113
|
+
};
|
|
114
|
+
// 1) 生成严格正交路径,尽量延续前一段方向以减少折点
|
|
115
|
+
var orthogonal = [];
|
|
116
|
+
pushUnique(orthogonal, points[0]);
|
|
117
|
+
// previousDirection: 记录前一段的方向,用于判断当前段的PreferredCorner
|
|
118
|
+
var previousDirection;
|
|
119
|
+
// 遍历所有点对,生成正交路径
|
|
120
|
+
for (var i = 0; i < points.length - 1; i++) {
|
|
121
|
+
var current = orthogonal[orthogonal.length - 1];
|
|
122
|
+
var next = points[i + 1];
|
|
123
|
+
if (!current || !next)
|
|
124
|
+
continue;
|
|
125
|
+
if (isAxisAligned(current, next)) {
|
|
126
|
+
pushUnique(orthogonal, next);
|
|
127
|
+
previousDirection =
|
|
128
|
+
current.x === next.x
|
|
129
|
+
? constant_1.SegmentDirection.VERTICAL
|
|
130
|
+
: constant_1.SegmentDirection.HORIZONTAL;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
var cornerHV = { x: next.x, y: current.y };
|
|
134
|
+
var cornerVH = { x: current.x, y: next.y };
|
|
135
|
+
// 根据前一段的方向,优先选择能延续该方向的拐角点,以减少折点数量;
|
|
136
|
+
// 若前一段为垂直方向,则优先选择垂直-水平拐角(cornerVH);
|
|
137
|
+
// 若前一段为水平方向,则优先选择水平-垂直拐角(cornerHV);
|
|
138
|
+
// 若前一段无方向(初始情况),则比较两个拐角的曼哈顿距离,选更近者。
|
|
139
|
+
var preferredCorner = previousDirection === constant_1.SegmentDirection.VERTICAL
|
|
140
|
+
? cornerVH
|
|
141
|
+
: previousDirection === constant_1.SegmentDirection.HORIZONTAL
|
|
142
|
+
? cornerHV
|
|
143
|
+
: manhattanDistance(current, cornerHV) <=
|
|
144
|
+
manhattanDistance(current, cornerVH)
|
|
145
|
+
? cornerHV
|
|
146
|
+
: cornerVH;
|
|
147
|
+
if (preferredCorner.x !== current.x || preferredCorner.y !== current.y) {
|
|
148
|
+
pushUnique(orthogonal, preferredCorner);
|
|
149
|
+
}
|
|
150
|
+
pushUnique(orthogonal, next);
|
|
151
|
+
var a = orthogonal[orthogonal.length - 2];
|
|
152
|
+
var b = orthogonal[orthogonal.length - 1];
|
|
153
|
+
previousDirection =
|
|
154
|
+
a && b
|
|
155
|
+
? a.x === b.x
|
|
156
|
+
? constant_1.SegmentDirection.VERTICAL
|
|
157
|
+
: constant_1.SegmentDirection.HORIZONTAL
|
|
158
|
+
: previousDirection;
|
|
159
|
+
}
|
|
160
|
+
// 2) 去除冗余共线中间点
|
|
161
|
+
var simplified = [];
|
|
162
|
+
for (var i = 0; i < orthogonal.length; i++) {
|
|
163
|
+
var prev = orthogonal[i - 1];
|
|
164
|
+
var curr = orthogonal[i];
|
|
165
|
+
var next = orthogonal[i + 1];
|
|
166
|
+
// 如果当前点与前一个点和后一个点在同一条水平线或垂直线上,则跳过该点,去除冗余的共线中间点
|
|
167
|
+
if (prev &&
|
|
168
|
+
curr &&
|
|
169
|
+
next &&
|
|
170
|
+
((prev.x === curr.x && curr.x === next.x) || // 水平共线
|
|
171
|
+
(prev.y === curr.y && curr.y === next.y)) // 垂直共线
|
|
172
|
+
) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
pushUnique(simplified, curr);
|
|
176
|
+
}
|
|
177
|
+
// 3) 保留原始起点与终点位置
|
|
178
|
+
if (simplified.length >= 2) {
|
|
179
|
+
simplified[0] = { x: points[0].x, y: points[0].y };
|
|
180
|
+
simplified[simplified.length - 1] = {
|
|
181
|
+
x: points[points.length - 1].x,
|
|
182
|
+
y: points[points.length - 1].y,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
// 4) 结果校验:任意相邻段都必须为水平/垂直;失败则退化为起止两点
|
|
186
|
+
var isOrthogonal = simplified.length < 2 ||
|
|
187
|
+
simplified.every(function (_, idx, arr) {
|
|
188
|
+
if (idx === 0)
|
|
189
|
+
return true;
|
|
190
|
+
return isAxisAligned(arr[idx - 1], arr[idx]);
|
|
191
|
+
});
|
|
192
|
+
return isOrthogonal
|
|
193
|
+
? simplified
|
|
194
|
+
: [
|
|
195
|
+
{ x: points[0].x, y: points[0].y },
|
|
196
|
+
{ x: points[points.length - 1].x, y: points[points.length - 1].y },
|
|
197
|
+
];
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* 计算默认 offset:箭头与折线重叠长度 + 5
|
|
201
|
+
* 重叠长度采用箭头样式中的 offset(沿边方向的长度)
|
|
202
|
+
*/
|
|
203
|
+
PolylineEdgeModel.prototype.getDefaultOffset = function () {
|
|
204
|
+
var arrowStyle = this.getArrowStyle();
|
|
205
|
+
var arrowOverlap = typeof arrowStyle.offset === 'number' ? arrowStyle.offset : 0;
|
|
206
|
+
return arrowOverlap + 5;
|
|
207
|
+
};
|
|
81
208
|
PolylineEdgeModel.prototype.getEdgeStyle = function () {
|
|
82
209
|
var polyline = this.graphModel.theme.polyline;
|
|
83
210
|
var style = _super.prototype.getEdgeStyle.call(this);
|
|
@@ -289,7 +416,7 @@ var PolylineEdgeModel = /** @class */ (function (_super) {
|
|
|
289
416
|
return list;
|
|
290
417
|
};
|
|
291
418
|
PolylineEdgeModel.prototype.updatePath = function (pointList) {
|
|
292
|
-
this.pointsList = pointList;
|
|
419
|
+
this.pointsList = this.orthogonalizePath(pointList);
|
|
293
420
|
this.points = this.getPath(this.pointsList);
|
|
294
421
|
};
|
|
295
422
|
PolylineEdgeModel.prototype.getData = function () {
|
|
@@ -324,7 +451,7 @@ var PolylineEdgeModel = /** @class */ (function (_super) {
|
|
|
324
451
|
x: this.endPoint.x,
|
|
325
452
|
y: this.endPoint.y,
|
|
326
453
|
}, this.sourceNode, this.targetNode, this.offset || 0);
|
|
327
|
-
this.pointsList = pointsList;
|
|
454
|
+
this.pointsList = this.orthogonalizePath(pointsList);
|
|
328
455
|
this.points = pointsList.map(function (point) { return "".concat(point.x, ",").concat(point.y); }).join(' ');
|
|
329
456
|
};
|
|
330
457
|
PolylineEdgeModel.prototype.updateStartPoint = function (anchor) {
|
|
@@ -547,13 +674,13 @@ var PolylineEdgeModel = /** @class */ (function (_super) {
|
|
|
547
674
|
// 起终点拖拽调整过程中,进行折线路径更新
|
|
548
675
|
PolylineEdgeModel.prototype.updateAfterAdjustStartAndEnd = function (_a) {
|
|
549
676
|
var startPoint = _a.startPoint, endPoint = _a.endPoint, sourceNode = _a.sourceNode, targetNode = _a.targetNode;
|
|
550
|
-
this.pointsList = (0, util_1.getPolylinePoints)({
|
|
677
|
+
this.pointsList = this.orthogonalizePath((0, util_1.getPolylinePoints)({
|
|
551
678
|
x: startPoint.x,
|
|
552
679
|
y: startPoint.y,
|
|
553
680
|
}, {
|
|
554
681
|
x: endPoint.x,
|
|
555
682
|
y: endPoint.y,
|
|
556
|
-
}, sourceNode, targetNode, this.offset || 0);
|
|
683
|
+
}, sourceNode, targetNode, this.offset || 0));
|
|
557
684
|
this.initPoints();
|
|
558
685
|
};
|
|
559
686
|
__decorate([
|
|
@@ -57,6 +57,10 @@ var MultipleSelect = /** @class */ (function (_super) {
|
|
|
57
57
|
function MultipleSelect(props) {
|
|
58
58
|
var _this = _super.call(this, props) || this;
|
|
59
59
|
_this.handleMouseDown = function (ev) {
|
|
60
|
+
// 多选区域的拖拽步长随缩放变化
|
|
61
|
+
var _a = _this.props, gridSize = _a.graphModel.gridSize, lf = _a.lf;
|
|
62
|
+
var SCALE_X = lf.getTransform().SCALE_X;
|
|
63
|
+
_this.stepDrag.setStep(gridSize * SCALE_X);
|
|
60
64
|
_this.stepDrag.handleMouseDown(ev);
|
|
61
65
|
};
|
|
62
66
|
// 使多选区域的滚轮事件可以触发画布的滚轮事件
|
|
@@ -106,6 +106,9 @@ var CanvasOverlay = /** @class */ (function (_super) {
|
|
|
106
106
|
if (selectElements.size > 0) {
|
|
107
107
|
graphModel.clearSelectElements();
|
|
108
108
|
}
|
|
109
|
+
// 如果是拖拽状态,不触发点击事件
|
|
110
|
+
if (_this.state.isDragging)
|
|
111
|
+
return;
|
|
109
112
|
graphModel.eventCenter.emit(constant_1.EventType.BLANK_CLICK, { e: ev });
|
|
110
113
|
}
|
|
111
114
|
};
|
package/package.json
CHANGED
package/src/model/GraphModel.ts
CHANGED
|
@@ -34,13 +34,154 @@ export class PolylineEdgeModel extends BaseEdgeModel {
|
|
|
34
34
|
@observable dbClickPosition?: Point
|
|
35
35
|
|
|
36
36
|
initEdgeData(data: LogicFlow.EdgeConfig): void {
|
|
37
|
-
|
|
37
|
+
const providedOffset = get(data, 'properties.offset')
|
|
38
|
+
// 当用户未传入 offset 时,按“箭头与折线重叠长度 + 5”作为默认值
|
|
39
|
+
// 其中“重叠长度”采用箭头样式中的 offset(沿边方向的长度)
|
|
40
|
+
this.offset =
|
|
41
|
+
typeof providedOffset === 'number'
|
|
42
|
+
? providedOffset
|
|
43
|
+
: this.getDefaultOffset()
|
|
38
44
|
if (data.pointsList) {
|
|
39
|
-
|
|
45
|
+
const corrected = this.orthogonalizePath(data.pointsList)
|
|
46
|
+
;(data as any).pointsList = corrected
|
|
47
|
+
this.pointsList = corrected
|
|
40
48
|
}
|
|
41
49
|
super.initEdgeData(data)
|
|
42
50
|
}
|
|
43
51
|
|
|
52
|
+
setAttributes() {
|
|
53
|
+
const { offset: newOffset } = this.properties
|
|
54
|
+
if (newOffset && newOffset !== this.offset) {
|
|
55
|
+
this.offset = newOffset
|
|
56
|
+
this.updatePoints()
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
orthogonalizePath(points: Point[]): Point[] {
|
|
61
|
+
// 输入非法或不足两点时直接返回副本
|
|
62
|
+
if (!Array.isArray(points) || points.length < 2) {
|
|
63
|
+
return points
|
|
64
|
+
}
|
|
65
|
+
// pushUnique: 向数组中添加唯一点,避免重复
|
|
66
|
+
const pushUnique = (arr: Point[], p: Point) => {
|
|
67
|
+
const last = arr[arr.length - 1]
|
|
68
|
+
if (!last || last.x !== p.x || last.y !== p.y) {
|
|
69
|
+
arr.push({ x: p.x, y: p.y })
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// isAxisAligned: 检查两点是否在同一条轴上
|
|
73
|
+
const isAxisAligned = (a: Point, b: Point) => a.x === b.x || a.y === b.y
|
|
74
|
+
// manhattanDistance: 计算两点在曼哈顿距离上的距离
|
|
75
|
+
const manhattanDistance = (a: Point, b: Point) =>
|
|
76
|
+
Math.abs(a.x - b.x) + Math.abs(a.y - b.y)
|
|
77
|
+
|
|
78
|
+
// 1) 生成严格正交路径,尽量延续前一段方向以减少折点
|
|
79
|
+
const orthogonal: Point[] = []
|
|
80
|
+
pushUnique(orthogonal, points[0])
|
|
81
|
+
// previousDirection: 记录前一段的方向,用于判断当前段的PreferredCorner
|
|
82
|
+
let previousDirection: SegmentDirection | undefined
|
|
83
|
+
// 遍历所有点对,生成正交路径
|
|
84
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
85
|
+
const current = orthogonal[orthogonal.length - 1]
|
|
86
|
+
const next = points[i + 1]
|
|
87
|
+
if (!current || !next) continue
|
|
88
|
+
|
|
89
|
+
if (isAxisAligned(current, next)) {
|
|
90
|
+
pushUnique(orthogonal, next)
|
|
91
|
+
previousDirection =
|
|
92
|
+
current.x === next.x
|
|
93
|
+
? SegmentDirection.VERTICAL
|
|
94
|
+
: SegmentDirection.HORIZONTAL
|
|
95
|
+
continue
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const cornerHV: Point = { x: next.x, y: current.y }
|
|
99
|
+
const cornerVH: Point = { x: current.x, y: next.y }
|
|
100
|
+
|
|
101
|
+
// 根据前一段的方向,优先选择能延续该方向的拐角点,以减少折点数量;
|
|
102
|
+
// 若前一段为垂直方向,则优先选择垂直-水平拐角(cornerVH);
|
|
103
|
+
// 若前一段为水平方向,则优先选择水平-垂直拐角(cornerHV);
|
|
104
|
+
// 若前一段无方向(初始情况),则比较两个拐角的曼哈顿距离,选更近者。
|
|
105
|
+
const preferredCorner =
|
|
106
|
+
previousDirection === SegmentDirection.VERTICAL
|
|
107
|
+
? cornerVH
|
|
108
|
+
: previousDirection === SegmentDirection.HORIZONTAL
|
|
109
|
+
? cornerHV
|
|
110
|
+
: manhattanDistance(current, cornerHV) <=
|
|
111
|
+
manhattanDistance(current, cornerVH)
|
|
112
|
+
? cornerHV
|
|
113
|
+
: cornerVH
|
|
114
|
+
|
|
115
|
+
if (preferredCorner.x !== current.x || preferredCorner.y !== current.y) {
|
|
116
|
+
pushUnique(orthogonal, preferredCorner)
|
|
117
|
+
}
|
|
118
|
+
pushUnique(orthogonal, next)
|
|
119
|
+
|
|
120
|
+
const a = orthogonal[orthogonal.length - 2]
|
|
121
|
+
const b = orthogonal[orthogonal.length - 1]
|
|
122
|
+
previousDirection =
|
|
123
|
+
a && b
|
|
124
|
+
? a.x === b.x
|
|
125
|
+
? SegmentDirection.VERTICAL
|
|
126
|
+
: SegmentDirection.HORIZONTAL
|
|
127
|
+
: previousDirection
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 2) 去除冗余共线中间点
|
|
131
|
+
const simplified: Point[] = []
|
|
132
|
+
for (let i = 0; i < orthogonal.length; i++) {
|
|
133
|
+
const prev = orthogonal[i - 1]
|
|
134
|
+
const curr = orthogonal[i]
|
|
135
|
+
const next = orthogonal[i + 1]
|
|
136
|
+
// 如果当前点与前一个点和后一个点在同一条水平线或垂直线上,则跳过该点,去除冗余的共线中间点
|
|
137
|
+
if (
|
|
138
|
+
prev &&
|
|
139
|
+
curr &&
|
|
140
|
+
next &&
|
|
141
|
+
((prev.x === curr.x && curr.x === next.x) || // 水平共线
|
|
142
|
+
(prev.y === curr.y && curr.y === next.y)) // 垂直共线
|
|
143
|
+
) {
|
|
144
|
+
continue
|
|
145
|
+
}
|
|
146
|
+
pushUnique(simplified, curr)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 3) 保留原始起点与终点位置
|
|
150
|
+
if (simplified.length >= 2) {
|
|
151
|
+
simplified[0] = { x: points[0].x, y: points[0].y }
|
|
152
|
+
simplified[simplified.length - 1] = {
|
|
153
|
+
x: points[points.length - 1].x,
|
|
154
|
+
y: points[points.length - 1].y,
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 4) 结果校验:任意相邻段都必须为水平/垂直;失败则退化为起止两点
|
|
159
|
+
const isOrthogonal =
|
|
160
|
+
simplified.length < 2 ||
|
|
161
|
+
simplified.every((_, idx, arr) => {
|
|
162
|
+
if (idx === 0) return true
|
|
163
|
+
return isAxisAligned(arr[idx - 1], arr[idx])
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
return isOrthogonal
|
|
167
|
+
? simplified
|
|
168
|
+
: [
|
|
169
|
+
{ x: points[0].x, y: points[0].y },
|
|
170
|
+
{ x: points[points.length - 1].x, y: points[points.length - 1].y },
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 计算默认 offset:箭头与折线重叠长度 + 5
|
|
176
|
+
* 重叠长度采用箭头样式中的 offset(沿边方向的长度)
|
|
177
|
+
*/
|
|
178
|
+
private getDefaultOffset(): number {
|
|
179
|
+
const arrowStyle = this.getArrowStyle()
|
|
180
|
+
const arrowOverlap =
|
|
181
|
+
typeof arrowStyle.offset === 'number' ? arrowStyle.offset : 0
|
|
182
|
+
return arrowOverlap + 5
|
|
183
|
+
}
|
|
184
|
+
|
|
44
185
|
getEdgeStyle() {
|
|
45
186
|
const { polyline } = this.graphModel.theme
|
|
46
187
|
const style = super.getEdgeStyle()
|
|
@@ -319,7 +460,7 @@ export class PolylineEdgeModel extends BaseEdgeModel {
|
|
|
319
460
|
}
|
|
320
461
|
|
|
321
462
|
updatePath(pointList: Point[]) {
|
|
322
|
-
this.pointsList = pointList
|
|
463
|
+
this.pointsList = this.orthogonalizePath(pointList)
|
|
323
464
|
this.points = this.getPath(this.pointsList)
|
|
324
465
|
}
|
|
325
466
|
|
|
@@ -362,7 +503,7 @@ export class PolylineEdgeModel extends BaseEdgeModel {
|
|
|
362
503
|
this.targetNode,
|
|
363
504
|
this.offset || 0,
|
|
364
505
|
)
|
|
365
|
-
this.pointsList = pointsList
|
|
506
|
+
this.pointsList = this.orthogonalizePath(pointsList)
|
|
366
507
|
this.points = pointsList.map((point) => `${point.x},${point.y}`).join(' ')
|
|
367
508
|
}
|
|
368
509
|
|
|
@@ -651,18 +792,20 @@ export class PolylineEdgeModel extends BaseEdgeModel {
|
|
|
651
792
|
sourceNode: BaseNodeModel
|
|
652
793
|
targetNode: BaseNodeModel
|
|
653
794
|
}) {
|
|
654
|
-
this.pointsList =
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
795
|
+
this.pointsList = this.orthogonalizePath(
|
|
796
|
+
getPolylinePoints(
|
|
797
|
+
{
|
|
798
|
+
x: startPoint.x,
|
|
799
|
+
y: startPoint.y,
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
x: endPoint.x,
|
|
803
|
+
y: endPoint.y,
|
|
804
|
+
},
|
|
805
|
+
sourceNode,
|
|
806
|
+
targetNode,
|
|
807
|
+
this.offset || 0,
|
|
808
|
+
),
|
|
666
809
|
)
|
|
667
810
|
|
|
668
811
|
this.initPoints()
|