@vanduo-oss/vd3-flowchart 1.5.0 → 1.5.1
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/CHANGELOG.md +18 -0
- package/README.md +7 -2
- package/dist/index.cjs +283 -35
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +283 -35
- package/dist/index.js.map +3 -3
- package/dist/meta.json +10 -10
- package/dist/vd3-flowchart.css +50 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,6 +8,8 @@ var DIRECTIONS = {
|
|
|
8
8
|
down: { main: "y", sign: 1 },
|
|
9
9
|
up: { main: "y", sign: -1 }
|
|
10
10
|
};
|
|
11
|
+
var DEFAULT_LEVEL_EDGE_GAP = 88;
|
|
12
|
+
var DEFAULT_SIBLING_EDGE_GAP = 64;
|
|
11
13
|
function num(value, fallback) {
|
|
12
14
|
const next = Number(value);
|
|
13
15
|
return Number.isFinite(next) ? next : fallback;
|
|
@@ -32,60 +34,182 @@ function pickRoots(nodes, indegree, optRoot) {
|
|
|
32
34
|
}
|
|
33
35
|
function spanningForest(allIds, roots, children) {
|
|
34
36
|
const visited = /* @__PURE__ */ new Set();
|
|
35
|
-
const
|
|
36
|
-
const tree = /* @__PURE__ */ new Map();
|
|
37
|
+
const active = /* @__PURE__ */ new Set();
|
|
37
38
|
const forestRoots = [];
|
|
38
|
-
const
|
|
39
|
+
const forwardParents = new Map(allIds.map((id) => [id, []]));
|
|
40
|
+
const dfs = (id) => {
|
|
39
41
|
visited.add(id);
|
|
40
|
-
|
|
41
|
-
const kids = [];
|
|
42
|
+
active.add(id);
|
|
42
43
|
(children.get(id) || []).forEach((child) => {
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
if (active.has(child)) return;
|
|
45
|
+
const list = forwardParents.get(child);
|
|
46
|
+
if (list && !list.includes(id)) list.push(id);
|
|
47
|
+
if (!visited.has(child)) dfs(child);
|
|
47
48
|
});
|
|
48
|
-
|
|
49
|
+
active.delete(id);
|
|
49
50
|
};
|
|
50
51
|
roots.forEach((root) => {
|
|
51
52
|
if (!visited.has(root)) {
|
|
52
53
|
forestRoots.push(root);
|
|
53
|
-
|
|
54
|
+
dfs(root);
|
|
54
55
|
}
|
|
55
56
|
});
|
|
56
57
|
allIds.forEach((id) => {
|
|
57
58
|
if (!visited.has(id)) {
|
|
58
59
|
forestRoots.push(id);
|
|
59
|
-
|
|
60
|
+
dfs(id);
|
|
60
61
|
}
|
|
61
62
|
});
|
|
63
|
+
const depth = new Map(allIds.map((id) => [id, 0]));
|
|
64
|
+
const limit = Math.max(1, allIds.length);
|
|
65
|
+
for (let pass = 0; pass < limit; pass += 1) {
|
|
66
|
+
let changed = false;
|
|
67
|
+
for (const id of allIds) {
|
|
68
|
+
const parents = forwardParents.get(id) || [];
|
|
69
|
+
for (const parent of parents) {
|
|
70
|
+
const nextDepth = Math.min(limit, (depth.get(parent) || 0) + 1);
|
|
71
|
+
if (nextDepth > (depth.get(id) || 0)) {
|
|
72
|
+
depth.set(id, nextDepth);
|
|
73
|
+
changed = true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!changed) break;
|
|
78
|
+
}
|
|
79
|
+
const tree = new Map(allIds.map((id) => [id, []]));
|
|
80
|
+
const rootSet = new Set(forestRoots);
|
|
81
|
+
const chosenParent = /* @__PURE__ */ new Map();
|
|
82
|
+
for (const id of allIds) {
|
|
83
|
+
if (rootSet.has(id)) continue;
|
|
84
|
+
const parents = forwardParents.get(id) || [];
|
|
85
|
+
if (!parents.length) continue;
|
|
86
|
+
let bestParent = parents[0];
|
|
87
|
+
let bestDepth = depth.get(bestParent) ?? -1;
|
|
88
|
+
for (let index = 1; index < parents.length; index += 1) {
|
|
89
|
+
const candidate = parents[index];
|
|
90
|
+
const candidateDepth = depth.get(candidate) ?? -1;
|
|
91
|
+
if (candidateDepth > bestDepth) {
|
|
92
|
+
bestDepth = candidateDepth;
|
|
93
|
+
bestParent = candidate;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
chosenParent.set(id, bestParent);
|
|
97
|
+
}
|
|
98
|
+
const placedChild = /* @__PURE__ */ new Set();
|
|
99
|
+
for (const parentId of allIds) {
|
|
100
|
+
const out = tree.get(parentId);
|
|
101
|
+
for (const childId of children.get(parentId) || []) {
|
|
102
|
+
if (chosenParent.get(childId) === parentId && !placedChild.has(childId)) {
|
|
103
|
+
placedChild.add(childId);
|
|
104
|
+
out.push(childId);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
62
108
|
return { depth, tree, forestRoots };
|
|
63
109
|
}
|
|
64
110
|
function treeCenters(forestRoots, tree, depth, sizeOf, options) {
|
|
65
111
|
const dir = DIRECTIONS[options.direction] || DIRECTIONS.right;
|
|
66
|
-
const
|
|
67
|
-
const
|
|
112
|
+
const hasExplicitLevel = Number.isFinite(Number(options.levelGap));
|
|
113
|
+
const hasExplicitSibling = Number.isFinite(Number(options.siblingGap));
|
|
114
|
+
const explicitLevelGap = num(options.levelGap, 220);
|
|
115
|
+
const explicitSiblingGap = num(options.siblingGap, 140);
|
|
116
|
+
const edgeSiblingGap = hasExplicitSibling ? Math.max(16, explicitSiblingGap - 96) : DEFAULT_SIBLING_EDGE_GAP;
|
|
117
|
+
const crossSpan = (id) => {
|
|
118
|
+
const size = sizeOf(id);
|
|
119
|
+
return dir.main === "x" ? size.height : size.width;
|
|
120
|
+
};
|
|
121
|
+
const mainSpan = (id) => {
|
|
122
|
+
const size = sizeOf(id);
|
|
123
|
+
return dir.main === "x" ? size.width : size.height;
|
|
124
|
+
};
|
|
125
|
+
const subtreeSpan = /* @__PURE__ */ new Map();
|
|
126
|
+
const subtreeCount = /* @__PURE__ */ new Map();
|
|
127
|
+
const measure = (id) => {
|
|
128
|
+
const selfSpan = crossSpan(id);
|
|
129
|
+
const kids = tree.get(id) || [];
|
|
130
|
+
if (!kids.length) {
|
|
131
|
+
subtreeSpan.set(id, selfSpan);
|
|
132
|
+
subtreeCount.set(id, 1);
|
|
133
|
+
return selfSpan;
|
|
134
|
+
}
|
|
135
|
+
let childTotal = 0;
|
|
136
|
+
let totalCount = 1;
|
|
137
|
+
kids.forEach((kid, index) => {
|
|
138
|
+
if (index > 0) childTotal += edgeSiblingGap;
|
|
139
|
+
childTotal += measure(kid);
|
|
140
|
+
totalCount += subtreeCount.get(kid) || 1;
|
|
141
|
+
});
|
|
142
|
+
const span = Math.max(selfSpan, childTotal);
|
|
143
|
+
subtreeSpan.set(id, span);
|
|
144
|
+
subtreeCount.set(id, totalCount);
|
|
145
|
+
return span;
|
|
146
|
+
};
|
|
147
|
+
forestRoots.forEach(measure);
|
|
68
148
|
const crossOf = /* @__PURE__ */ new Map();
|
|
69
|
-
|
|
70
|
-
|
|
149
|
+
const place = (id, startCross) => {
|
|
150
|
+
const span = subtreeSpan.get(id) || crossSpan(id);
|
|
71
151
|
const kids = tree.get(id) || [];
|
|
72
152
|
if (!kids.length) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return
|
|
153
|
+
const center2 = startCross + span / 2;
|
|
154
|
+
crossOf.set(id, center2);
|
|
155
|
+
return center2;
|
|
156
|
+
}
|
|
157
|
+
let childTotal = 0;
|
|
158
|
+
const kidSpans = kids.map((kid, index) => {
|
|
159
|
+
const kidSpan = subtreeSpan.get(kid) || crossSpan(kid);
|
|
160
|
+
if (index > 0) childTotal += edgeSiblingGap;
|
|
161
|
+
childTotal += kidSpan;
|
|
162
|
+
return kidSpan;
|
|
163
|
+
});
|
|
164
|
+
let cursor = startCross + (span - childTotal) / 2;
|
|
165
|
+
const childCenters = kids.map((kid, index) => {
|
|
166
|
+
const kidSpan = kidSpans[index];
|
|
167
|
+
const center2 = place(kid, cursor);
|
|
168
|
+
cursor += kidSpan + edgeSiblingGap;
|
|
169
|
+
return center2;
|
|
170
|
+
});
|
|
171
|
+
if (kids.length >= 2) {
|
|
172
|
+
const counts = kids.map((kid) => subtreeCount.get(kid) || 1);
|
|
173
|
+
const maxCount = Math.max(...counts);
|
|
174
|
+
const minCount = Math.min(...counts);
|
|
175
|
+
if (maxCount > minCount) {
|
|
176
|
+
const primaryIndex = counts.indexOf(maxCount);
|
|
177
|
+
const center2 = childCenters[primaryIndex];
|
|
178
|
+
crossOf.set(id, center2);
|
|
179
|
+
return center2;
|
|
180
|
+
}
|
|
76
181
|
}
|
|
77
|
-
const childCenters = kids.map(place);
|
|
78
182
|
const center = (childCenters[0] + childCenters[childCenters.length - 1]) / 2;
|
|
79
183
|
crossOf.set(id, center);
|
|
80
184
|
return center;
|
|
81
185
|
};
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
186
|
+
let rootCursor = 0;
|
|
187
|
+
forestRoots.forEach((root, index) => {
|
|
188
|
+
if (index > 0) rootCursor += edgeSiblingGap;
|
|
189
|
+
const span = subtreeSpan.get(root) || crossSpan(root);
|
|
190
|
+
place(root, rootCursor);
|
|
191
|
+
rootCursor += span;
|
|
85
192
|
});
|
|
193
|
+
let maxDepth = 0;
|
|
194
|
+
const maxMainAtDepth = /* @__PURE__ */ new Map();
|
|
195
|
+
crossOf.forEach((_cross, id) => {
|
|
196
|
+
const d = depth.get(id) || 0;
|
|
197
|
+
if (d > maxDepth) maxDepth = d;
|
|
198
|
+
const current = maxMainAtDepth.get(d) || 0;
|
|
199
|
+
const span = mainSpan(id);
|
|
200
|
+
if (span > current) maxMainAtDepth.set(d, span);
|
|
201
|
+
});
|
|
202
|
+
const mainCenterAtDepth = /* @__PURE__ */ new Map([[0, 0]]);
|
|
203
|
+
for (let d = 1; d <= maxDepth; d += 1) {
|
|
204
|
+
const prevCenter = mainCenterAtDepth.get(d - 1) || 0;
|
|
205
|
+
const prevSpan = maxMainAtDepth.get(d - 1) || 160;
|
|
206
|
+
const currSpan = maxMainAtDepth.get(d) || 160;
|
|
207
|
+
const step = hasExplicitLevel ? Math.max(explicitLevelGap, (prevSpan + currSpan) / 2 + 24) : (prevSpan + currSpan) / 2 + DEFAULT_LEVEL_EDGE_GAP;
|
|
208
|
+
mainCenterAtDepth.set(d, prevCenter + step * dir.sign);
|
|
209
|
+
}
|
|
86
210
|
const centers = /* @__PURE__ */ new Map();
|
|
87
211
|
crossOf.forEach((cross, id) => {
|
|
88
|
-
const main = (depth.get(id) || 0)
|
|
212
|
+
const main = mainCenterAtDepth.get(depth.get(id) || 0) || 0;
|
|
89
213
|
centers.set(
|
|
90
214
|
id,
|
|
91
215
|
dir.main === "x" ? { centerX: main, centerY: cross } : { centerX: cross, centerY: main }
|
|
@@ -399,7 +523,7 @@ var EDGE_STROKE_PRESETS = [
|
|
|
399
523
|
{ id: "medium", label: "Medium", width: DEFAULT_EDGE_STROKE_WIDTH },
|
|
400
524
|
{ id: "bold", label: "Bold", width: 3.5 }
|
|
401
525
|
];
|
|
402
|
-
var VD_FLOWCHART_VERSION = "1.5.
|
|
526
|
+
var VD_FLOWCHART_VERSION = "1.5.1";
|
|
403
527
|
var FLOWCHART_DOCUMENT_VERSION = "1.3.0";
|
|
404
528
|
var FLOWCHART_NODE_TYPES = [
|
|
405
529
|
"rounded-rect",
|
|
@@ -1106,10 +1230,37 @@ function getOrthogonalMidpoints(fromStub, toStub, fromPort, toPort) {
|
|
|
1106
1230
|
function getOrthogonalPoints(fromPoint, toPoint, fromPort, toPort, fromRect, toRect, metrics = routeMetrics(1)) {
|
|
1107
1231
|
const fromNormal = getPortNormal(fromPort);
|
|
1108
1232
|
const toNormal = getPortNormal(toPort);
|
|
1109
|
-
const fromStub = offsetPoint(fromPoint, fromNormal, metrics.stub);
|
|
1110
|
-
const toStub = offsetPoint(toPoint, toNormal, metrics.stub);
|
|
1111
1233
|
const sourceHorizontal = isHorizontalPort(fromPort);
|
|
1112
1234
|
const targetHorizontal = isHorizontalPort(toPort);
|
|
1235
|
+
const minStub = 4 * (metrics.scale || 1);
|
|
1236
|
+
let fromStubLen = metrics.stub;
|
|
1237
|
+
let toStubLen = metrics.stub;
|
|
1238
|
+
if (sourceHorizontal && targetHorizontal && fromNormal.x === -toNormal.x) {
|
|
1239
|
+
const span = (toPoint.x - fromPoint.x) * fromNormal.x;
|
|
1240
|
+
if (span > 0) {
|
|
1241
|
+
const fitted = Math.min(metrics.stub, span * 0.45, span / 2);
|
|
1242
|
+
fromStubLen = fitted;
|
|
1243
|
+
toStubLen = fitted;
|
|
1244
|
+
}
|
|
1245
|
+
} else if (!sourceHorizontal && !targetHorizontal && fromNormal.y === -toNormal.y) {
|
|
1246
|
+
const span = (toPoint.y - fromPoint.y) * fromNormal.y;
|
|
1247
|
+
if (span > 0) {
|
|
1248
|
+
const fitted = Math.min(metrics.stub, span * 0.45, span / 2);
|
|
1249
|
+
fromStubLen = fitted;
|
|
1250
|
+
toStubLen = fitted;
|
|
1251
|
+
}
|
|
1252
|
+
} else if (sourceHorizontal !== targetHorizontal) {
|
|
1253
|
+
const spanFrom = sourceHorizontal ? (toPoint.x - fromPoint.x) * fromNormal.x : (toPoint.y - fromPoint.y) * fromNormal.y;
|
|
1254
|
+
const spanTo = targetHorizontal ? (fromPoint.x - toPoint.x) * toNormal.x : (fromPoint.y - toPoint.y) * toNormal.y;
|
|
1255
|
+
if (spanFrom > 0 && spanFrom < metrics.stub) {
|
|
1256
|
+
fromStubLen = Math.min(spanFrom / 2, Math.max(minStub, spanFrom * 0.5));
|
|
1257
|
+
}
|
|
1258
|
+
if (spanTo > 0 && spanTo < metrics.stub) {
|
|
1259
|
+
toStubLen = Math.min(spanTo / 2, Math.max(minStub, spanTo * 0.5));
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
const fromStub = offsetPoint(fromPoint, fromNormal, fromStubLen);
|
|
1263
|
+
const toStub = offsetPoint(toPoint, toNormal, toStubLen);
|
|
1113
1264
|
const mids = [];
|
|
1114
1265
|
if (sourceHorizontal && targetHorizontal) {
|
|
1115
1266
|
const facing = fromNormal.x === -toNormal.x;
|
|
@@ -1532,6 +1683,7 @@ var VdFlowchart = class {
|
|
|
1532
1683
|
this.handleClick = this.handleClick.bind(this);
|
|
1533
1684
|
this.handleDoubleClick = this.handleDoubleClick.bind(this);
|
|
1534
1685
|
this.handleWheel = this.handleWheel.bind(this);
|
|
1686
|
+
this.handleCanvasBlur = this.handleCanvasBlur.bind(this);
|
|
1535
1687
|
this.handleKeyDown = this.handleKeyDown.bind(this);
|
|
1536
1688
|
this.handleSelectionFieldInput = this.handleSelectionFieldInput.bind(this);
|
|
1537
1689
|
this.handleSelectionFieldChange = this.handleSelectionFieldChange.bind(this);
|
|
@@ -1944,6 +2096,7 @@ var VdFlowchart = class {
|
|
|
1944
2096
|
this.canvasEl.addEventListener("click", this.handleClick);
|
|
1945
2097
|
this.canvasEl.addEventListener("dblclick", this.handleDoubleClick);
|
|
1946
2098
|
this.canvasEl.addEventListener("wheel", this.handleWheel, { passive: false });
|
|
2099
|
+
this.canvasEl.addEventListener("blur", this.handleCanvasBlur);
|
|
1947
2100
|
this.root.addEventListener("keydown", this.handleKeyDown, true);
|
|
1948
2101
|
window.addEventListener("pointerup", this.handlePointerUp);
|
|
1949
2102
|
window.addEventListener("resize", this.handleResize);
|
|
@@ -1962,6 +2115,7 @@ var VdFlowchart = class {
|
|
|
1962
2115
|
this.canvasEl.removeEventListener("click", this.handleClick);
|
|
1963
2116
|
this.canvasEl.removeEventListener("dblclick", this.handleDoubleClick);
|
|
1964
2117
|
this.canvasEl.removeEventListener("wheel", this.handleWheel);
|
|
2118
|
+
this.canvasEl.removeEventListener("blur", this.handleCanvasBlur);
|
|
1965
2119
|
this.root.removeEventListener("keydown", this.handleKeyDown, true);
|
|
1966
2120
|
window.removeEventListener("pointerup", this.handlePointerUp);
|
|
1967
2121
|
window.removeEventListener("resize", this.handleResize);
|
|
@@ -1970,6 +2124,19 @@ var VdFlowchart = class {
|
|
|
1970
2124
|
if (this.destroyed) return;
|
|
1971
2125
|
this.render({ inspector: false, json: false });
|
|
1972
2126
|
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Focus the diagram canvas. Quiet focus returns from an inline editor without
|
|
2129
|
+
* painting the full-canvas `:focus-visible` ring (see `.is-quiet-focus`).
|
|
2130
|
+
*/
|
|
2131
|
+
focusCanvas(options = {}) {
|
|
2132
|
+
if (!this.canvasEl || this.destroyed) return;
|
|
2133
|
+
const quiet = options.quiet === true;
|
|
2134
|
+
this.canvasEl.classList.toggle("is-quiet-focus", quiet);
|
|
2135
|
+
this.canvasEl.focus({ preventScroll: true });
|
|
2136
|
+
}
|
|
2137
|
+
handleCanvasBlur() {
|
|
2138
|
+
this.canvasEl?.classList.remove("is-quiet-focus");
|
|
2139
|
+
}
|
|
1973
2140
|
updatePaletteState() {
|
|
1974
2141
|
const arrowArmed = this.activeTool === "arrow";
|
|
1975
2142
|
this.paletteGrid.querySelectorAll(".vd-flowchart-palette-btn").forEach((button) => {
|
|
@@ -3425,7 +3592,7 @@ var VdFlowchart = class {
|
|
|
3425
3592
|
if (event.key === "Escape" || event.key === "Enter") {
|
|
3426
3593
|
event.preventDefault();
|
|
3427
3594
|
this.stopTextEdit({ commit: event.key === "Enter" });
|
|
3428
|
-
this.
|
|
3595
|
+
this.focusCanvas({ quiet: true });
|
|
3429
3596
|
}
|
|
3430
3597
|
});
|
|
3431
3598
|
textarea.addEventListener("blur", () => {
|
|
@@ -3452,7 +3619,7 @@ var VdFlowchart = class {
|
|
|
3452
3619
|
if (event.key === "Escape") {
|
|
3453
3620
|
event.preventDefault();
|
|
3454
3621
|
this.stopTextEdit({ commit: false });
|
|
3455
|
-
this.
|
|
3622
|
+
this.focusCanvas({ quiet: true });
|
|
3456
3623
|
return;
|
|
3457
3624
|
}
|
|
3458
3625
|
if (event.key === "Enter") {
|
|
@@ -3461,13 +3628,12 @@ var VdFlowchart = class {
|
|
|
3461
3628
|
if (!commits) return;
|
|
3462
3629
|
event.preventDefault();
|
|
3463
3630
|
this.stopTextEdit({ commit: true });
|
|
3464
|
-
this.
|
|
3631
|
+
this.focusCanvas({ quiet: true });
|
|
3465
3632
|
return;
|
|
3466
3633
|
}
|
|
3467
3634
|
if (event.key === "Tab" && mindmap && !event.shiftKey && !event.altKey && !event.ctrlKey) {
|
|
3468
3635
|
event.preventDefault();
|
|
3469
3636
|
this.stopTextEdit({ commit: true });
|
|
3470
|
-
this.canvasEl.focus();
|
|
3471
3637
|
this.insertBranchNode(node.id, { edit: true });
|
|
3472
3638
|
}
|
|
3473
3639
|
}
|
|
@@ -4775,7 +4941,7 @@ var VdFlowchart = class {
|
|
|
4775
4941
|
changed = true;
|
|
4776
4942
|
}
|
|
4777
4943
|
});
|
|
4778
|
-
const rerouted = options.reroutePorts === false ? false : this.rerouteEdgePorts();
|
|
4944
|
+
const rerouted = options.reroutePorts === false ? false : this.rerouteEdgePorts(resolvedMode === "tree" ? options.direction || "right" : null);
|
|
4779
4945
|
if (!changed && !rerouted) return this;
|
|
4780
4946
|
this.render();
|
|
4781
4947
|
this.emitChange("layout", { mode: resolvedMode });
|
|
@@ -4788,8 +4954,16 @@ var VdFlowchart = class {
|
|
|
4788
4954
|
// Re-pick each edge's from/to port from the nodes' current centers, so a
|
|
4789
4955
|
// freshly laid-out graph attaches connectors on sensible sides. Returns
|
|
4790
4956
|
// whether any port actually changed.
|
|
4791
|
-
rerouteEdgePorts() {
|
|
4957
|
+
rerouteEdgePorts(flowDirection = null) {
|
|
4792
4958
|
let changed = false;
|
|
4959
|
+
const flow = flowDirection === "down" || flowDirection === "up" || flowDirection === "left" || flowDirection === "right" ? flowDirection : null;
|
|
4960
|
+
const outDegree = /* @__PURE__ */ new Map();
|
|
4961
|
+
if (flow) {
|
|
4962
|
+
this.documentData.edges.forEach((edge) => {
|
|
4963
|
+
const fromId = edge?.from?.nodeId;
|
|
4964
|
+
if (fromId) outDegree.set(fromId, (outDegree.get(fromId) || 0) + 1);
|
|
4965
|
+
});
|
|
4966
|
+
}
|
|
4793
4967
|
this.documentData.edges.forEach((edge) => {
|
|
4794
4968
|
const fromNode = this.findNode(edge.from.nodeId);
|
|
4795
4969
|
const toNode = this.findNode(edge.to.nodeId);
|
|
@@ -4799,8 +4973,82 @@ var VdFlowchart = class {
|
|
|
4799
4973
|
y: fromNode.y + fromNode.height / 2
|
|
4800
4974
|
};
|
|
4801
4975
|
const toCenter = { x: toNode.x + toNode.width / 2, y: toNode.y + toNode.height / 2 };
|
|
4802
|
-
|
|
4803
|
-
|
|
4976
|
+
let nextFrom;
|
|
4977
|
+
let nextTo;
|
|
4978
|
+
if (flow) {
|
|
4979
|
+
const dx = toCenter.x - fromCenter.x;
|
|
4980
|
+
const dy = toCenter.y - fromCenter.y;
|
|
4981
|
+
const vertical = flow === "down" || flow === "up";
|
|
4982
|
+
const sign = flow === "up" || flow === "left" ? -1 : 1;
|
|
4983
|
+
const mainDelta = (vertical ? dy : dx) * sign;
|
|
4984
|
+
const crossDelta = vertical ? dx : dy;
|
|
4985
|
+
const isDiamondBranch = fromNode.type === "diamond" && (outDegree.get(fromNode.id) || 0) >= 2;
|
|
4986
|
+
if (mainDelta < -8) {
|
|
4987
|
+
const allNodes = this.documentData.nodes;
|
|
4988
|
+
if (vertical) {
|
|
4989
|
+
const minX = Math.min(fromNode.x, toNode.x);
|
|
4990
|
+
const maxRight = Math.max(fromNode.x + fromNode.width, toNode.x + toNode.width);
|
|
4991
|
+
const minY = Math.min(fromCenter.y, toCenter.y) - 8;
|
|
4992
|
+
const maxY = Math.max(fromCenter.y, toCenter.y) + 8;
|
|
4993
|
+
let rightCount = 0;
|
|
4994
|
+
let leftCount = 0;
|
|
4995
|
+
allNodes.forEach((n) => {
|
|
4996
|
+
if (!n || n.id === fromNode.id || n.id === toNode.id) return;
|
|
4997
|
+
const ny = n.y + n.height / 2;
|
|
4998
|
+
if (ny < minY || ny > maxY) return;
|
|
4999
|
+
const nx = n.x + n.width / 2;
|
|
5000
|
+
if (nx >= maxRight - 20) rightCount += 1;
|
|
5001
|
+
if (nx <= minX + 20) leftCount += 1;
|
|
5002
|
+
});
|
|
5003
|
+
const side = leftCount < rightCount ? "left" : rightCount < leftCount ? "right" : crossDelta < -8 ? "left" : "right";
|
|
5004
|
+
nextFrom = side;
|
|
5005
|
+
nextTo = side;
|
|
5006
|
+
} else {
|
|
5007
|
+
const minY = Math.min(fromNode.y, toNode.y);
|
|
5008
|
+
const maxBottom = Math.max(fromNode.y + fromNode.height, toNode.y + toNode.height);
|
|
5009
|
+
const minX = Math.min(fromCenter.x, toCenter.x) - 8;
|
|
5010
|
+
const maxX = Math.max(fromCenter.x, toCenter.x) + 8;
|
|
5011
|
+
let bottomCount = 0;
|
|
5012
|
+
let topCount = 0;
|
|
5013
|
+
allNodes.forEach((n) => {
|
|
5014
|
+
if (!n || n.id === fromNode.id || n.id === toNode.id) return;
|
|
5015
|
+
const nx = n.x + n.width / 2;
|
|
5016
|
+
if (nx < minX || nx > maxX) return;
|
|
5017
|
+
const ny = n.y + n.height / 2;
|
|
5018
|
+
if (ny >= maxBottom - 20) bottomCount += 1;
|
|
5019
|
+
if (ny <= minY + 20) topCount += 1;
|
|
5020
|
+
});
|
|
5021
|
+
const side = topCount < bottomCount ? "top" : bottomCount < topCount ? "bottom" : crossDelta < -8 ? "top" : "bottom";
|
|
5022
|
+
nextFrom = side;
|
|
5023
|
+
nextTo = side;
|
|
5024
|
+
}
|
|
5025
|
+
} else if (mainDelta >= 12) {
|
|
5026
|
+
if (vertical) {
|
|
5027
|
+
nextTo = sign > 0 ? "top" : "bottom";
|
|
5028
|
+
if (isDiamondBranch && Math.abs(crossDelta) >= fromNode.width * 0.45) {
|
|
5029
|
+
nextFrom = crossDelta > 0 ? "right" : "left";
|
|
5030
|
+
} else {
|
|
5031
|
+
nextFrom = sign > 0 ? "bottom" : "top";
|
|
5032
|
+
}
|
|
5033
|
+
} else {
|
|
5034
|
+
nextTo = sign > 0 ? "left" : "right";
|
|
5035
|
+
if (isDiamondBranch && Math.abs(crossDelta) >= fromNode.height * 0.45) {
|
|
5036
|
+
nextFrom = crossDelta > 0 ? "bottom" : "top";
|
|
5037
|
+
} else {
|
|
5038
|
+
nextFrom = sign > 0 ? "right" : "left";
|
|
5039
|
+
}
|
|
5040
|
+
}
|
|
5041
|
+
} else if (vertical) {
|
|
5042
|
+
nextFrom = dx >= 0 ? "right" : "left";
|
|
5043
|
+
nextTo = dx >= 0 ? "left" : "right";
|
|
5044
|
+
} else {
|
|
5045
|
+
nextFrom = dy >= 0 ? "bottom" : "top";
|
|
5046
|
+
nextTo = dy >= 0 ? "top" : "bottom";
|
|
5047
|
+
}
|
|
5048
|
+
} else {
|
|
5049
|
+
nextFrom = getPortByDirection(fromNode, toCenter).port;
|
|
5050
|
+
nextTo = getPortByDirection(toNode, fromCenter).port;
|
|
5051
|
+
}
|
|
4804
5052
|
if (nextFrom !== edge.from.port || nextTo !== edge.to.port) {
|
|
4805
5053
|
edge.from.port = nextFrom;
|
|
4806
5054
|
edge.to.port = nextTo;
|