@yh-ui/flow 1.0.53 → 1.0.54
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/dist/Flow.vue +9 -6
- package/dist/plugins/plugins/layout.cjs +30 -7
- package/dist/plugins/plugins/layout.mjs +50 -12
- package/dist/renderer/EdgeRenderer.vue +32 -3
- package/dist/renderer/NodeRenderer.vue +25 -1
- package/dist/utils/edge.cjs +82 -1
- package/dist/utils/edge.d.ts +7 -0
- package/dist/utils/edge.mjs +105 -1
- package/dist/utils/validation.cjs +1 -8
- package/dist/utils/validation.mjs +1 -4
- package/package.json +8 -4
package/dist/Flow.vue
CHANGED
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
</template>
|
|
121
121
|
|
|
122
122
|
<script setup>
|
|
123
|
-
import { ref, computed, watch, onMounted, onBeforeUnmount, shallowRef, useId } from "vue";
|
|
123
|
+
import { ref, computed, watch, onMounted, onBeforeUnmount, shallowRef, useId, toRaw } from "vue";
|
|
124
124
|
if (typeof window !== "undefined") window.__YH_FLOW_VERSION__ = "1.0.1";
|
|
125
125
|
import EdgeRenderer from "./renderer/EdgeRenderer.vue";
|
|
126
126
|
import EdgeHandlesRenderer from "./renderer/EdgeHandlesRenderer.vue";
|
|
@@ -860,16 +860,19 @@ pluginManager.init(flowInstance);
|
|
|
860
860
|
defineExpose(flowInstance);
|
|
861
861
|
watch(
|
|
862
862
|
() => props.nodes,
|
|
863
|
-
(
|
|
864
|
-
if (
|
|
865
|
-
|
|
863
|
+
(nodes) => {
|
|
864
|
+
if (toRaw(nodesRef.value) !== toRaw(nodes)) {
|
|
865
|
+
nodesRef.value = nodes;
|
|
866
|
+
}
|
|
866
867
|
},
|
|
867
868
|
{ deep: true }
|
|
868
869
|
);
|
|
869
870
|
watch(
|
|
870
871
|
() => props.edges,
|
|
871
|
-
(
|
|
872
|
-
edgesRef.value
|
|
872
|
+
(edges) => {
|
|
873
|
+
if (toRaw(edgesRef.value) !== toRaw(edges)) {
|
|
874
|
+
edgesRef.value = edges;
|
|
875
|
+
}
|
|
873
876
|
},
|
|
874
877
|
{ deep: true }
|
|
875
878
|
);
|
|
@@ -20,7 +20,15 @@ const defaultOptions = {
|
|
|
20
20
|
workerUrl: ""
|
|
21
21
|
};
|
|
22
22
|
async function applyDagreLayout(nodes, edges, options) {
|
|
23
|
-
|
|
23
|
+
let dagreLib;
|
|
24
|
+
try {
|
|
25
|
+
dagreLib = await Promise.resolve().then(() => require("dagre"));
|
|
26
|
+
} catch {
|
|
27
|
+
throw new Error('[YH-UI Flow] Layout engine "dagre" is not installed. Please install "dagre" to use the dagre layout algorithm.');
|
|
28
|
+
}
|
|
29
|
+
if (!dagreLib) {
|
|
30
|
+
throw new Error('[YH-UI Flow] Layout engine "dagre" is not installed. Please install "dagre" to use the dagre layout algorithm.');
|
|
31
|
+
}
|
|
24
32
|
const dagre = dagreLib.default || dagreLib;
|
|
25
33
|
const graphlib = dagreLib.graphlib || dagre.graphlib;
|
|
26
34
|
const g = new graphlib.Graph();
|
|
@@ -63,11 +71,18 @@ async function applyElkLayout(nodes, edges, options) {
|
|
|
63
71
|
const elkPath = "elkjs";
|
|
64
72
|
let elkLib;
|
|
65
73
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
try {
|
|
75
|
+
elkLib = await Promise.resolve(`${/* @vite-ignore */
|
|
76
|
+
bundledPath}`).then(s => require(s));
|
|
77
|
+
} catch {
|
|
78
|
+
elkLib = await Promise.resolve(`${/* @vite-ignore */
|
|
79
|
+
elkPath}`).then(s => require(s));
|
|
80
|
+
}
|
|
68
81
|
} catch {
|
|
69
|
-
|
|
70
|
-
|
|
82
|
+
throw new Error('[YH-UI Flow] Layout engine "elkjs" is not installed. Please install "elkjs" to use the elk layout algorithm.');
|
|
83
|
+
}
|
|
84
|
+
if (!elkLib) {
|
|
85
|
+
throw new Error('[YH-UI Flow] Layout engine "elkjs" is not installed. Please install "elkjs" to use the elk layout algorithm.');
|
|
71
86
|
}
|
|
72
87
|
const ELK = elkLib.default || elkLib;
|
|
73
88
|
const elk = new ELK();
|
|
@@ -116,8 +131,16 @@ async function applyElkLayout(nodes, edges, options) {
|
|
|
116
131
|
}
|
|
117
132
|
async function applyForceLayout(nodes, edges, options, flowInstance) {
|
|
118
133
|
const d3ForcePath = "d3-force";
|
|
119
|
-
|
|
120
|
-
|
|
134
|
+
let d3ForceLib;
|
|
135
|
+
try {
|
|
136
|
+
d3ForceLib = await Promise.resolve(`${/* @vite-ignore */
|
|
137
|
+
d3ForcePath}`).then(s => require(s));
|
|
138
|
+
} catch {
|
|
139
|
+
throw new Error('[YH-UI Flow] Layout engine "d3-force" is not installed. Please install "d3-force" to use the force layout algorithm.');
|
|
140
|
+
}
|
|
141
|
+
if (!d3ForceLib) {
|
|
142
|
+
throw new Error('[YH-UI Flow] Layout engine "d3-force" is not installed. Please install "d3-force" to use the force layout algorithm.');
|
|
143
|
+
}
|
|
121
144
|
const d3Force = d3ForceLib.default || d3ForceLib;
|
|
122
145
|
const forceNodes = nodes.map(node => ({
|
|
123
146
|
id: node.id,
|
|
@@ -12,7 +12,22 @@ const defaultOptions = {
|
|
|
12
12
|
workerUrl: ""
|
|
13
13
|
};
|
|
14
14
|
async function applyDagreLayout(nodes, edges, options) {
|
|
15
|
-
|
|
15
|
+
let dagreLib;
|
|
16
|
+
try {
|
|
17
|
+
dagreLib = await import(
|
|
18
|
+
/* @vite-ignore */
|
|
19
|
+
"dagre"
|
|
20
|
+
);
|
|
21
|
+
} catch {
|
|
22
|
+
throw new Error(
|
|
23
|
+
'[YH-UI Flow] Layout engine "dagre" is not installed. Please install "dagre" to use the dagre layout algorithm.'
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
if (!dagreLib) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
'[YH-UI Flow] Layout engine "dagre" is not installed. Please install "dagre" to use the dagre layout algorithm.'
|
|
29
|
+
);
|
|
30
|
+
}
|
|
16
31
|
const dagre = dagreLib.default || dagreLib;
|
|
17
32
|
const graphlib = dagreLib.graphlib || dagre.graphlib;
|
|
18
33
|
const g = new graphlib.Graph();
|
|
@@ -52,14 +67,25 @@ async function applyElkLayout(nodes, edges, options) {
|
|
|
52
67
|
const elkPath = "elkjs";
|
|
53
68
|
let elkLib;
|
|
54
69
|
try {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
70
|
+
try {
|
|
71
|
+
elkLib = await import(
|
|
72
|
+
/* @vite-ignore */
|
|
73
|
+
bundledPath
|
|
74
|
+
);
|
|
75
|
+
} catch {
|
|
76
|
+
elkLib = await import(
|
|
77
|
+
/* @vite-ignore */
|
|
78
|
+
elkPath
|
|
79
|
+
);
|
|
80
|
+
}
|
|
59
81
|
} catch {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
82
|
+
throw new Error(
|
|
83
|
+
'[YH-UI Flow] Layout engine "elkjs" is not installed. Please install "elkjs" to use the elk layout algorithm.'
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (!elkLib) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
'[YH-UI Flow] Layout engine "elkjs" is not installed. Please install "elkjs" to use the elk layout algorithm.'
|
|
63
89
|
);
|
|
64
90
|
}
|
|
65
91
|
const ELK = elkLib.default || elkLib;
|
|
@@ -106,10 +132,22 @@ async function applyElkLayout(nodes, edges, options) {
|
|
|
106
132
|
}
|
|
107
133
|
async function applyForceLayout(nodes, edges, options, flowInstance) {
|
|
108
134
|
const d3ForcePath = "d3-force";
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
135
|
+
let d3ForceLib;
|
|
136
|
+
try {
|
|
137
|
+
d3ForceLib = await import(
|
|
138
|
+
/* @vite-ignore */
|
|
139
|
+
d3ForcePath
|
|
140
|
+
);
|
|
141
|
+
} catch {
|
|
142
|
+
throw new Error(
|
|
143
|
+
'[YH-UI Flow] Layout engine "d3-force" is not installed. Please install "d3-force" to use the force layout algorithm.'
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
if (!d3ForceLib) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
'[YH-UI Flow] Layout engine "d3-force" is not installed. Please install "d3-force" to use the force layout algorithm.'
|
|
149
|
+
);
|
|
150
|
+
}
|
|
113
151
|
const d3Force = d3ForceLib.default || d3ForceLib;
|
|
114
152
|
const forceNodes = nodes.map((node) => ({
|
|
115
153
|
id: node.id,
|
|
@@ -14,7 +14,11 @@
|
|
|
14
14
|
>
|
|
15
15
|
<defs>
|
|
16
16
|
<!-- Dynamic masks to create a true gap in the line behind the label -->
|
|
17
|
-
<mask
|
|
17
|
+
<mask
|
|
18
|
+
v-for="ed in edgeData.filter(e => e.edge.label)"
|
|
19
|
+
:key="`mask-${ed.edge.id}`"
|
|
20
|
+
:id="getMaskId(ed.edge.id)"
|
|
21
|
+
>
|
|
18
22
|
<rect x="-5000" y="-5000" width="10000" height="10000" fill="white" />
|
|
19
23
|
<rect
|
|
20
24
|
:x="ed.labelX - ed.labelWidth / 2 - 4"
|
|
@@ -61,8 +65,28 @@
|
|
|
61
65
|
style="cursor: pointer; pointer-events: all"
|
|
62
66
|
/>
|
|
63
67
|
|
|
64
|
-
<!-- Visible Path -->
|
|
68
|
+
<!-- Visible Path with Mask (when label exists) -->
|
|
65
69
|
<path
|
|
70
|
+
v-if="ed.edge.label"
|
|
71
|
+
:d="ed.path"
|
|
72
|
+
:stroke="ed.stroke"
|
|
73
|
+
:stroke-width="ed.strokeWidth"
|
|
74
|
+
fill="none"
|
|
75
|
+
:class="{
|
|
76
|
+
'yh-flow-edge-path': true,
|
|
77
|
+
'is-animated': ed.edge.animated
|
|
78
|
+
}"
|
|
79
|
+
:mask="`url(#${getMaskId(ed.edge.id)})`"
|
|
80
|
+
:style="{
|
|
81
|
+
pointerEvents: 'none',
|
|
82
|
+
transition: 'stroke 0.2s, stroke-width 0.2s',
|
|
83
|
+
stroke: ed.stroke
|
|
84
|
+
}"
|
|
85
|
+
/>
|
|
86
|
+
|
|
87
|
+
<!-- Visible Path without Mask (when no label exists) -->
|
|
88
|
+
<path
|
|
89
|
+
v-else
|
|
66
90
|
:d="ed.path"
|
|
67
91
|
:stroke="ed.stroke"
|
|
68
92
|
:stroke-width="ed.strokeWidth"
|
|
@@ -71,7 +95,6 @@
|
|
|
71
95
|
'yh-flow-edge-path': true,
|
|
72
96
|
'is-animated': ed.edge.animated
|
|
73
97
|
}"
|
|
74
|
-
:mask="ed.edge.label ? `url(#${getMaskId(ed.edge.id)})` : void 0"
|
|
75
98
|
:style="{
|
|
76
99
|
pointerEvents: 'none',
|
|
77
100
|
transition: 'stroke 0.2s, stroke-width 0.2s',
|
|
@@ -151,6 +174,12 @@ const getLabelStyle = (edge) => {
|
|
|
151
174
|
return styles;
|
|
152
175
|
};
|
|
153
176
|
const edgeData = computed(() => {
|
|
177
|
+
console.log(
|
|
178
|
+
"EdgeRenderer computed edgeData running. Nodes count:",
|
|
179
|
+
props.nodes.length,
|
|
180
|
+
"Node 1 pos:",
|
|
181
|
+
props.nodes.find((n) => n.id === "1")?.position
|
|
182
|
+
);
|
|
154
183
|
const result = [];
|
|
155
184
|
for (const edge of props.edges) {
|
|
156
185
|
if (!edge || edge.hidden) continue;
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
</template>
|
|
65
65
|
|
|
66
66
|
<script setup>
|
|
67
|
-
import { computed, ref, onMounted, onBeforeUnmount } from "vue";
|
|
67
|
+
import { computed, ref, onMounted, onBeforeUnmount, watch } from "vue";
|
|
68
68
|
import {
|
|
69
69
|
getCustomNodeTemplate,
|
|
70
70
|
getCustomNode,
|
|
@@ -373,6 +373,30 @@ onBeforeUnmount(() => {
|
|
|
373
373
|
}
|
|
374
374
|
nodeElements.clear();
|
|
375
375
|
});
|
|
376
|
+
watch(
|
|
377
|
+
() => props.nodes,
|
|
378
|
+
(newNodes) => {
|
|
379
|
+
let hasChanges = false;
|
|
380
|
+
newNodes.forEach((node) => {
|
|
381
|
+
if (!node.measured) {
|
|
382
|
+
const el = nodeElements.get(node.id);
|
|
383
|
+
if (el) {
|
|
384
|
+
const rect = el.getBoundingClientRect();
|
|
385
|
+
const width = Math.round(rect.width);
|
|
386
|
+
const height = Math.round(rect.height);
|
|
387
|
+
if (width > 0 && height > 0) {
|
|
388
|
+
node.measured = { width, height };
|
|
389
|
+
hasChanges = true;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
if (hasChanges) {
|
|
395
|
+
emit("nodes-measured");
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
{ flush: "post" }
|
|
399
|
+
);
|
|
376
400
|
const setNodeRef = (el, nodeId) => {
|
|
377
401
|
if (el) {
|
|
378
402
|
nodeElements.set(nodeId, el);
|
package/dist/utils/edge.cjs
CHANGED
|
@@ -8,6 +8,7 @@ exports.getEdgeCenter = getEdgeCenter;
|
|
|
8
8
|
exports.getEdgePath = getEdgePath;
|
|
9
9
|
exports.getEdgePosition = getEdgePosition;
|
|
10
10
|
exports.getHandlePosition = getHandlePosition;
|
|
11
|
+
exports.getSelfLoopPath = getSelfLoopPath;
|
|
11
12
|
exports.getSmoothStepPath = getSmoothStepPath;
|
|
12
13
|
exports.getStepPath = getStepPath;
|
|
13
14
|
exports.getStraightPath = getStraightPath;
|
|
@@ -208,7 +209,37 @@ function getSmoothStepPath(params) {
|
|
|
208
209
|
return [`M${sourceX},${sourceY}`, `L${sourceX},${midY - sign1Y * r}`, `Q${sourceX},${midY} ${sourceX + sign2X * r},${midY}`, `L${targetX - sign2X * r},${midY}`, `Q${targetX},${midY} ${targetX},${midY + sign1Y * r}`, `L${targetX},${targetY}`].join(" ");
|
|
209
210
|
}
|
|
210
211
|
}
|
|
212
|
+
function getSelfLoopPath(sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, nodeWidth, nodeHeight) {
|
|
213
|
+
const w = nodeWidth ?? 150;
|
|
214
|
+
const h = nodeHeight ?? 50;
|
|
215
|
+
const dx = targetX - sourceX;
|
|
216
|
+
const dy = targetY - sourceY;
|
|
217
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
218
|
+
if (dist < 5) {
|
|
219
|
+
const loopSize = 40;
|
|
220
|
+
if (sourcePosition === "right") {
|
|
221
|
+
return `M${sourceX},${sourceY} C${sourceX + loopSize},${sourceY - loopSize} ${sourceX + loopSize},${sourceY + loopSize} ${sourceX},${sourceY}`;
|
|
222
|
+
} else if (sourcePosition === "left") {
|
|
223
|
+
return `M${sourceX},${sourceY} C${sourceX - loopSize},${sourceY - loopSize} ${sourceX - loopSize},${sourceY + loopSize} ${sourceX},${sourceY}`;
|
|
224
|
+
} else if (sourcePosition === "top") {
|
|
225
|
+
return `M${sourceX},${sourceY} C${sourceX - loopSize},${sourceY - loopSize} ${sourceX + loopSize},${sourceY - loopSize} ${sourceX},${sourceY}`;
|
|
226
|
+
} else {
|
|
227
|
+
return `M${sourceX},${sourceY} C${sourceX - loopSize},${sourceY + loopSize} ${sourceX + loopSize},${sourceY + loopSize} ${sourceX},${sourceY}`;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const offset = Math.max(w, h, 60) * 0.5;
|
|
231
|
+
let c1x = sourceX;
|
|
232
|
+
let c1y = sourceY;
|
|
233
|
+
if (sourcePosition === "right") c1x += offset;else if (sourcePosition === "left") c1x -= offset;else if (sourcePosition === "top") c1y -= offset;else if (sourcePosition === "bottom") c1y += offset;
|
|
234
|
+
let c2x = targetX;
|
|
235
|
+
let c2y = targetY;
|
|
236
|
+
if (targetPosition === "right") c2x += offset;else if (targetPosition === "left") c2x -= offset;else if (targetPosition === "top") c2y -= offset;else if (targetPosition === "bottom") c2y += offset;
|
|
237
|
+
return `M${sourceX},${sourceY} C${c1x},${c1y} ${c2x},${c2y} ${targetX},${targetY}`;
|
|
238
|
+
}
|
|
211
239
|
function getEdgePath(type, params) {
|
|
240
|
+
if (params.isSelfLoop) {
|
|
241
|
+
return getSelfLoopPath(params.sourceX, params.sourceY, params.targetX, params.targetY, params.sourcePosition, params.targetPosition, params.nodeWidth, params.nodeHeight);
|
|
242
|
+
}
|
|
212
243
|
switch (type) {
|
|
213
244
|
case "bezier":
|
|
214
245
|
case "default":
|
|
@@ -229,8 +260,58 @@ function getEdgeCenter(params) {
|
|
|
229
260
|
sourceY,
|
|
230
261
|
targetX,
|
|
231
262
|
targetY,
|
|
232
|
-
type = "bezier"
|
|
263
|
+
type = "bezier",
|
|
264
|
+
isSelfLoop,
|
|
265
|
+
nodeWidth,
|
|
266
|
+
nodeHeight,
|
|
267
|
+
sourcePosition,
|
|
268
|
+
targetPosition
|
|
233
269
|
} = params;
|
|
270
|
+
if (isSelfLoop) {
|
|
271
|
+
const w = nodeWidth ?? 150;
|
|
272
|
+
const h = nodeHeight ?? 50;
|
|
273
|
+
const dx = targetX - sourceX;
|
|
274
|
+
const dy = targetY - sourceY;
|
|
275
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
276
|
+
let c1x = sourceX,
|
|
277
|
+
c1y = sourceY,
|
|
278
|
+
c2x = targetX,
|
|
279
|
+
c2y = targetY;
|
|
280
|
+
if (dist < 5) {
|
|
281
|
+
const loopSize = 40;
|
|
282
|
+
if (sourcePosition === "right") {
|
|
283
|
+
c1x = sourceX + loopSize;
|
|
284
|
+
c1y = sourceY - loopSize;
|
|
285
|
+
c2x = sourceX + loopSize;
|
|
286
|
+
c2y = sourceY + loopSize;
|
|
287
|
+
} else if (sourcePosition === "left") {
|
|
288
|
+
c1x = sourceX - loopSize;
|
|
289
|
+
c1y = sourceY - loopSize;
|
|
290
|
+
c2x = sourceX - loopSize;
|
|
291
|
+
c2y = sourceY + loopSize;
|
|
292
|
+
} else if (sourcePosition === "top") {
|
|
293
|
+
c1x = sourceX - loopSize;
|
|
294
|
+
c1y = sourceY - loopSize;
|
|
295
|
+
c2x = sourceX + loopSize;
|
|
296
|
+
c2y = sourceY - loopSize;
|
|
297
|
+
} else {
|
|
298
|
+
c1x = sourceX - loopSize;
|
|
299
|
+
c1y = sourceY + loopSize;
|
|
300
|
+
c2x = sourceX + loopSize;
|
|
301
|
+
c2y = sourceY + loopSize;
|
|
302
|
+
}
|
|
303
|
+
} else {
|
|
304
|
+
const offset = Math.max(w, h, 60) * 0.5;
|
|
305
|
+
if (sourcePosition === "right") c1x += offset;else if (sourcePosition === "left") c1x -= offset;else if (sourcePosition === "top") c1y -= offset;else if (sourcePosition === "bottom") c1y += offset;
|
|
306
|
+
if (targetPosition === "right") c2x += offset;else if (targetPosition === "left") c2x -= offset;else if (targetPosition === "top") c2y -= offset;else if (targetPosition === "bottom") c2y += offset;
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
x: 0.125 * sourceX + 0.375 * c1x + 0.375 * c2x + 0.125 * targetX,
|
|
310
|
+
y: 0.125 * sourceY + 0.375 * c1y + 0.375 * c2y + 0.125 * targetY,
|
|
311
|
+
ox: 0,
|
|
312
|
+
oy: 0
|
|
313
|
+
};
|
|
314
|
+
}
|
|
234
315
|
if (type === "bezier" || type === "default") {
|
|
235
316
|
const curvature = params.curvature ?? 0.25;
|
|
236
317
|
const srcDir = getDir(params.sourcePosition);
|
package/dist/utils/edge.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ export interface EdgePathParams {
|
|
|
8
8
|
targetPosition: Position;
|
|
9
9
|
/** 控制曲率,0~1,默认 0.25 */
|
|
10
10
|
curvature?: number;
|
|
11
|
+
isSelfLoop?: boolean;
|
|
12
|
+
nodeWidth?: number;
|
|
13
|
+
nodeHeight?: number;
|
|
11
14
|
}
|
|
12
15
|
/**
|
|
13
16
|
* 获取连接点的位置坐标
|
|
@@ -60,6 +63,10 @@ export declare function getStepPath(params: EdgePathParams): string;
|
|
|
60
63
|
* 生成平滑阶梯线路径(带圆角转折的 step)
|
|
61
64
|
*/
|
|
62
65
|
export declare function getSmoothStepPath(params: EdgePathParams): string;
|
|
66
|
+
/**
|
|
67
|
+
* 生成自环曲线路径
|
|
68
|
+
*/
|
|
69
|
+
export declare function getSelfLoopPath(sourceX: number, sourceY: number, targetX: number, targetY: number, sourcePosition: Position, targetPosition: Position, nodeWidth?: number, nodeHeight?: number): string;
|
|
63
70
|
/**
|
|
64
71
|
* 根据类型获取连线路径
|
|
65
72
|
*/
|
package/dist/utils/edge.mjs
CHANGED
|
@@ -148,7 +148,52 @@ export function getSmoothStepPath(params) {
|
|
|
148
148
|
].join(" ");
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
|
+
export function getSelfLoopPath(sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, nodeWidth, nodeHeight) {
|
|
152
|
+
const w = nodeWidth ?? 150;
|
|
153
|
+
const h = nodeHeight ?? 50;
|
|
154
|
+
const dx = targetX - sourceX;
|
|
155
|
+
const dy = targetY - sourceY;
|
|
156
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
157
|
+
if (dist < 5) {
|
|
158
|
+
const loopSize = 40;
|
|
159
|
+
if (sourcePosition === "right") {
|
|
160
|
+
return `M${sourceX},${sourceY} C${sourceX + loopSize},${sourceY - loopSize} ${sourceX + loopSize},${sourceY + loopSize} ${sourceX},${sourceY}`;
|
|
161
|
+
} else if (sourcePosition === "left") {
|
|
162
|
+
return `M${sourceX},${sourceY} C${sourceX - loopSize},${sourceY - loopSize} ${sourceX - loopSize},${sourceY + loopSize} ${sourceX},${sourceY}`;
|
|
163
|
+
} else if (sourcePosition === "top") {
|
|
164
|
+
return `M${sourceX},${sourceY} C${sourceX - loopSize},${sourceY - loopSize} ${sourceX + loopSize},${sourceY - loopSize} ${sourceX},${sourceY}`;
|
|
165
|
+
} else {
|
|
166
|
+
return `M${sourceX},${sourceY} C${sourceX - loopSize},${sourceY + loopSize} ${sourceX + loopSize},${sourceY + loopSize} ${sourceX},${sourceY}`;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const offset = Math.max(w, h, 60) * 0.5;
|
|
170
|
+
let c1x = sourceX;
|
|
171
|
+
let c1y = sourceY;
|
|
172
|
+
if (sourcePosition === "right") c1x += offset;
|
|
173
|
+
else if (sourcePosition === "left") c1x -= offset;
|
|
174
|
+
else if (sourcePosition === "top") c1y -= offset;
|
|
175
|
+
else if (sourcePosition === "bottom") c1y += offset;
|
|
176
|
+
let c2x = targetX;
|
|
177
|
+
let c2y = targetY;
|
|
178
|
+
if (targetPosition === "right") c2x += offset;
|
|
179
|
+
else if (targetPosition === "left") c2x -= offset;
|
|
180
|
+
else if (targetPosition === "top") c2y -= offset;
|
|
181
|
+
else if (targetPosition === "bottom") c2y += offset;
|
|
182
|
+
return `M${sourceX},${sourceY} C${c1x},${c1y} ${c2x},${c2y} ${targetX},${targetY}`;
|
|
183
|
+
}
|
|
151
184
|
export function getEdgePath(type, params) {
|
|
185
|
+
if (params.isSelfLoop) {
|
|
186
|
+
return getSelfLoopPath(
|
|
187
|
+
params.sourceX,
|
|
188
|
+
params.sourceY,
|
|
189
|
+
params.targetX,
|
|
190
|
+
params.targetY,
|
|
191
|
+
params.sourcePosition,
|
|
192
|
+
params.targetPosition,
|
|
193
|
+
params.nodeWidth,
|
|
194
|
+
params.nodeHeight
|
|
195
|
+
);
|
|
196
|
+
}
|
|
152
197
|
switch (type) {
|
|
153
198
|
case "bezier":
|
|
154
199
|
case "default":
|
|
@@ -164,7 +209,66 @@ export function getEdgePath(type, params) {
|
|
|
164
209
|
}
|
|
165
210
|
}
|
|
166
211
|
export function getEdgeCenter(params) {
|
|
167
|
-
const {
|
|
212
|
+
const {
|
|
213
|
+
sourceX,
|
|
214
|
+
sourceY,
|
|
215
|
+
targetX,
|
|
216
|
+
targetY,
|
|
217
|
+
type = "bezier",
|
|
218
|
+
isSelfLoop,
|
|
219
|
+
nodeWidth,
|
|
220
|
+
nodeHeight,
|
|
221
|
+
sourcePosition,
|
|
222
|
+
targetPosition
|
|
223
|
+
} = params;
|
|
224
|
+
if (isSelfLoop) {
|
|
225
|
+
const w = nodeWidth ?? 150;
|
|
226
|
+
const h = nodeHeight ?? 50;
|
|
227
|
+
const dx = targetX - sourceX;
|
|
228
|
+
const dy = targetY - sourceY;
|
|
229
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
230
|
+
let c1x = sourceX, c1y = sourceY, c2x = targetX, c2y = targetY;
|
|
231
|
+
if (dist < 5) {
|
|
232
|
+
const loopSize = 40;
|
|
233
|
+
if (sourcePosition === "right") {
|
|
234
|
+
c1x = sourceX + loopSize;
|
|
235
|
+
c1y = sourceY - loopSize;
|
|
236
|
+
c2x = sourceX + loopSize;
|
|
237
|
+
c2y = sourceY + loopSize;
|
|
238
|
+
} else if (sourcePosition === "left") {
|
|
239
|
+
c1x = sourceX - loopSize;
|
|
240
|
+
c1y = sourceY - loopSize;
|
|
241
|
+
c2x = sourceX - loopSize;
|
|
242
|
+
c2y = sourceY + loopSize;
|
|
243
|
+
} else if (sourcePosition === "top") {
|
|
244
|
+
c1x = sourceX - loopSize;
|
|
245
|
+
c1y = sourceY - loopSize;
|
|
246
|
+
c2x = sourceX + loopSize;
|
|
247
|
+
c2y = sourceY - loopSize;
|
|
248
|
+
} else {
|
|
249
|
+
c1x = sourceX - loopSize;
|
|
250
|
+
c1y = sourceY + loopSize;
|
|
251
|
+
c2x = sourceX + loopSize;
|
|
252
|
+
c2y = sourceY + loopSize;
|
|
253
|
+
}
|
|
254
|
+
} else {
|
|
255
|
+
const offset = Math.max(w, h, 60) * 0.5;
|
|
256
|
+
if (sourcePosition === "right") c1x += offset;
|
|
257
|
+
else if (sourcePosition === "left") c1x -= offset;
|
|
258
|
+
else if (sourcePosition === "top") c1y -= offset;
|
|
259
|
+
else if (sourcePosition === "bottom") c1y += offset;
|
|
260
|
+
if (targetPosition === "right") c2x += offset;
|
|
261
|
+
else if (targetPosition === "left") c2x -= offset;
|
|
262
|
+
else if (targetPosition === "top") c2y -= offset;
|
|
263
|
+
else if (targetPosition === "bottom") c2y += offset;
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
x: 0.125 * sourceX + 0.375 * c1x + 0.375 * c2x + 0.125 * targetX,
|
|
267
|
+
y: 0.125 * sourceY + 0.375 * c1y + 0.375 * c2y + 0.125 * targetY,
|
|
268
|
+
ox: 0,
|
|
269
|
+
oy: 0
|
|
270
|
+
};
|
|
271
|
+
}
|
|
168
272
|
if (type === "bezier" || type === "default") {
|
|
169
273
|
const curvature = params.curvature ?? 0.25;
|
|
170
274
|
const srcDir = getDir(params.sourcePosition);
|
|
@@ -56,14 +56,7 @@ function isValidConnection(sourceNode, targetNode, connection) {
|
|
|
56
56
|
}
|
|
57
57
|
if (connection.source === connection.target) {
|
|
58
58
|
return {
|
|
59
|
-
isValid:
|
|
60
|
-
message: "Cannot connect to the same node"
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
if (connection.target === connection.source) {
|
|
64
|
-
return {
|
|
65
|
-
isValid: false,
|
|
66
|
-
message: "Cannot create self-loop"
|
|
59
|
+
isValid: true
|
|
67
60
|
};
|
|
68
61
|
}
|
|
69
62
|
return {
|
|
@@ -41,10 +41,7 @@ export function isValidConnection(sourceNode, targetNode, connection) {
|
|
|
41
41
|
return { isValid: false, message: "Target node not found" };
|
|
42
42
|
}
|
|
43
43
|
if (connection.source === connection.target) {
|
|
44
|
-
return { isValid:
|
|
45
|
-
}
|
|
46
|
-
if (connection.target === connection.source) {
|
|
47
|
-
return { isValid: false, message: "Cannot create self-loop" };
|
|
44
|
+
return { isValid: true };
|
|
48
45
|
}
|
|
49
46
|
return { isValid: true };
|
|
50
47
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yh-ui/flow",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.54",
|
|
4
4
|
"description": "YH-UI High-performance Flow Chart Component",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"lint": "eslint ."
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@yh-ui/utils": "^1.0.
|
|
36
|
-
"@yh-ui/hooks": "^1.0.
|
|
35
|
+
"@yh-ui/utils": "^1.0.54",
|
|
36
|
+
"@yh-ui/hooks": "^1.0.54"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"vue": "^3.5.35",
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"vue": "^3.5.35",
|
|
45
45
|
"dagre": ">=0.8.5",
|
|
46
46
|
"elkjs": ">=0.9.0",
|
|
47
|
-
"d3-force": ">=3.0.0"
|
|
47
|
+
"d3-force": ">=3.0.0",
|
|
48
|
+
"html-to-image": ">=1.11.0"
|
|
48
49
|
},
|
|
49
50
|
"peerDependenciesMeta": {
|
|
50
51
|
"dagre": {
|
|
@@ -55,6 +56,9 @@
|
|
|
55
56
|
},
|
|
56
57
|
"d3-force": {
|
|
57
58
|
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"html-to-image": {
|
|
61
|
+
"optional": true
|
|
58
62
|
}
|
|
59
63
|
},
|
|
60
64
|
"publishConfig": {
|