@flowgram.ai/free-auto-layout-plugin 0.1.0-alpha.14 → 0.1.0-alpha.16
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/esm/index.js +138 -93
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +77 -42
- package/dist/index.d.ts +77 -42
- package/dist/index.js +142 -95
- package/dist/index.js.map +1 -1
- package/package.json +11 -13
package/dist/esm/index.js
CHANGED
|
@@ -2081,10 +2081,12 @@ import { definePluginCreator } from "@flowgram.ai/core";
|
|
|
2081
2081
|
|
|
2082
2082
|
// src/services.ts
|
|
2083
2083
|
import { inject, injectable } from "inversify";
|
|
2084
|
+
import { Rectangle } from "@flowgram.ai/utils";
|
|
2084
2085
|
import {
|
|
2085
2086
|
WorkflowDocument,
|
|
2086
|
-
WorkflowNodeLinesData
|
|
2087
|
+
WorkflowNodeLinesData
|
|
2087
2088
|
} from "@flowgram.ai/free-layout-core";
|
|
2089
|
+
import { Playground } from "@flowgram.ai/core";
|
|
2088
2090
|
|
|
2089
2091
|
// src/layout/constant.ts
|
|
2090
2092
|
var DefaultLayoutConfig = {
|
|
@@ -2100,14 +2102,13 @@ var DefaultLayoutConfig = {
|
|
|
2100
2102
|
};
|
|
2101
2103
|
var DefaultLayoutOptions = {
|
|
2102
2104
|
getFollowNode: void 0,
|
|
2103
|
-
|
|
2105
|
+
disableFitView: false,
|
|
2106
|
+
enableAnimation: false,
|
|
2107
|
+
animationDuration: 300
|
|
2104
2108
|
};
|
|
2105
2109
|
|
|
2106
2110
|
// src/layout/store.ts
|
|
2107
|
-
import {
|
|
2108
|
-
WorkflowNodeLinesData
|
|
2109
|
-
} from "@flowgram.ai/free-layout-core";
|
|
2110
|
-
import { FlowNodeBaseType, FlowNodeTransformData } from "@flowgram.ai/document";
|
|
2111
|
+
import { FlowNodeBaseType } from "@flowgram.ai/document";
|
|
2111
2112
|
var LayoutStore = class {
|
|
2112
2113
|
constructor(config) {
|
|
2113
2114
|
this.config = config;
|
|
@@ -2136,6 +2137,7 @@ var LayoutStore = class {
|
|
|
2136
2137
|
return Array.from(this.store.edges.values());
|
|
2137
2138
|
}
|
|
2138
2139
|
create(params, options) {
|
|
2140
|
+
this.container = params.container;
|
|
2139
2141
|
this.store = this.createStore(params);
|
|
2140
2142
|
this.indexMap = this.createIndexMap();
|
|
2141
2143
|
this.setOptions(options);
|
|
@@ -2143,10 +2145,7 @@ var LayoutStore = class {
|
|
|
2143
2145
|
}
|
|
2144
2146
|
/** 创建布局数据 */
|
|
2145
2147
|
createStore(params) {
|
|
2146
|
-
const {
|
|
2147
|
-
this.container = container;
|
|
2148
|
-
const layoutNodes = this.createLayoutNodes(nodes);
|
|
2149
|
-
const layoutEdges = this.createEdgesStore(edges);
|
|
2148
|
+
const { layoutNodes, layoutEdges } = params;
|
|
2150
2149
|
const virtualEdges = this.createVirtualEdges(params);
|
|
2151
2150
|
const store = {
|
|
2152
2151
|
nodes: /* @__PURE__ */ new Map(),
|
|
@@ -2156,53 +2155,11 @@ var LayoutStore = class {
|
|
|
2156
2155
|
layoutEdges.concat(virtualEdges).forEach((edge) => store.edges.set(edge.id, edge));
|
|
2157
2156
|
return store;
|
|
2158
2157
|
}
|
|
2159
|
-
/** 创建节点布局数据 */
|
|
2160
|
-
createLayoutNodes(nodes) {
|
|
2161
|
-
const layoutNodes = nodes.map((node, index) => {
|
|
2162
|
-
const { bounds } = node.getData(FlowNodeTransformData);
|
|
2163
|
-
const layoutNode = {
|
|
2164
|
-
id: node.id,
|
|
2165
|
-
entity: node,
|
|
2166
|
-
index: "",
|
|
2167
|
-
// 初始化时,index 未计算
|
|
2168
|
-
rank: -1,
|
|
2169
|
-
// 初始化时,节点还未布局,层级为-1
|
|
2170
|
-
order: -1,
|
|
2171
|
-
// 初始化时,节点还未布局,顺序为-1
|
|
2172
|
-
position: { x: bounds.center.x, y: bounds.center.y },
|
|
2173
|
-
offset: { x: 0, y: 0 },
|
|
2174
|
-
size: { width: bounds.width, height: bounds.height },
|
|
2175
|
-
hasChildren: node.collapsedChildren?.length > 0
|
|
2176
|
-
};
|
|
2177
|
-
return layoutNode;
|
|
2178
|
-
});
|
|
2179
|
-
return layoutNodes;
|
|
2180
|
-
}
|
|
2181
|
-
/** 创建线条布局数据 */
|
|
2182
|
-
createEdgesStore(edges) {
|
|
2183
|
-
const layoutEdges = edges.map((edge) => {
|
|
2184
|
-
const { from, to } = edge.info;
|
|
2185
|
-
if (!from || !to || edge.vertical) {
|
|
2186
|
-
return;
|
|
2187
|
-
}
|
|
2188
|
-
const layoutEdge = {
|
|
2189
|
-
id: edge.id,
|
|
2190
|
-
entity: edge,
|
|
2191
|
-
from,
|
|
2192
|
-
to,
|
|
2193
|
-
fromIndex: "",
|
|
2194
|
-
// 初始化时,index 未计算
|
|
2195
|
-
toIndex: "",
|
|
2196
|
-
// 初始化时,index 未计算
|
|
2197
|
-
name: edge.id
|
|
2198
|
-
};
|
|
2199
|
-
return layoutEdge;
|
|
2200
|
-
}).filter(Boolean);
|
|
2201
|
-
return layoutEdges;
|
|
2202
|
-
}
|
|
2203
2158
|
/** 创建虚拟线条数据 */
|
|
2204
2159
|
createVirtualEdges(params) {
|
|
2205
|
-
const {
|
|
2160
|
+
const { layoutNodes, layoutEdges } = params;
|
|
2161
|
+
const nodes = layoutNodes.map((layoutNode) => layoutNode.entity);
|
|
2162
|
+
const edges = layoutEdges.map((layoutEdge) => layoutEdge.entity);
|
|
2206
2163
|
const groupNodes = nodes.filter((n) => n.flowNodeType === FlowNodeBaseType.GROUP);
|
|
2207
2164
|
const virtualEdges = groupNodes.map((group) => {
|
|
2208
2165
|
const { id: groupId, blocks = [] } = group;
|
|
@@ -2289,7 +2246,7 @@ var LayoutStore = class {
|
|
|
2289
2246
|
});
|
|
2290
2247
|
const visited = /* @__PURE__ */ new Set();
|
|
2291
2248
|
const visit = (node) => {
|
|
2292
|
-
if (visited.has(node.id)) {
|
|
2249
|
+
if (!node || visited.has(node.id)) {
|
|
2293
2250
|
return;
|
|
2294
2251
|
}
|
|
2295
2252
|
visited.add(node.id);
|
|
@@ -2297,7 +2254,7 @@ var LayoutStore = class {
|
|
|
2297
2254
|
node.blocks.forEach((child) => {
|
|
2298
2255
|
visit(child);
|
|
2299
2256
|
});
|
|
2300
|
-
const { outputLines } = node.
|
|
2257
|
+
const { outputLines } = node.lines;
|
|
2301
2258
|
const sortedLines = outputLines.sort((a, b) => {
|
|
2302
2259
|
const aNode = this.getNode(a.to?.id);
|
|
2303
2260
|
const bNode = this.getNode(b.to?.id);
|
|
@@ -2319,7 +2276,7 @@ var LayoutStore = class {
|
|
|
2319
2276
|
visit(to);
|
|
2320
2277
|
});
|
|
2321
2278
|
};
|
|
2322
|
-
visit(this.container);
|
|
2279
|
+
visit(this.container.entity);
|
|
2323
2280
|
const uniqueNodeIds = nodeIdList.reduceRight((acc, nodeId) => {
|
|
2324
2281
|
if (!acc.includes(nodeId)) {
|
|
2325
2282
|
acc.unshift(nodeId);
|
|
@@ -2352,7 +2309,7 @@ var LayoutStore = class {
|
|
|
2352
2309
|
};
|
|
2353
2310
|
|
|
2354
2311
|
// src/layout/position.ts
|
|
2355
|
-
import { startTween
|
|
2312
|
+
import { startTween } from "@flowgram.ai/core";
|
|
2356
2313
|
var LayoutPosition = class {
|
|
2357
2314
|
constructor(store) {
|
|
2358
2315
|
this.store = store;
|
|
@@ -2373,7 +2330,7 @@ var LayoutPosition = class {
|
|
|
2373
2330
|
startTween({
|
|
2374
2331
|
from: { d: 0 },
|
|
2375
2332
|
to: { d: 100 },
|
|
2376
|
-
duration:
|
|
2333
|
+
duration: this.store.options.animationDuration ?? 0,
|
|
2377
2334
|
onUpdate: (v) => {
|
|
2378
2335
|
this.store.nodes.forEach((layoutNode) => {
|
|
2379
2336
|
this.updateNodePosition({ layoutNode, step: v.d });
|
|
@@ -2387,18 +2344,20 @@ var LayoutPosition = class {
|
|
|
2387
2344
|
}
|
|
2388
2345
|
updateNodePosition(params) {
|
|
2389
2346
|
const { layoutNode, step } = params;
|
|
2390
|
-
const transform = layoutNode.entity.
|
|
2391
|
-
const
|
|
2347
|
+
const { transform } = layoutNode.entity.transform;
|
|
2348
|
+
const layoutPosition = {
|
|
2392
2349
|
x: layoutNode.position.x + layoutNode.offset.x,
|
|
2393
|
-
|
|
2350
|
+
// layoutNode.position.y 是中心点,但画布节点原点在上边沿的中间,所以 y 坐标需要转化后一下
|
|
2351
|
+
y: layoutNode.position.y - layoutNode.size.height / 2 + layoutNode.offset.y
|
|
2352
|
+
};
|
|
2353
|
+
const deltaX = (layoutPosition.x - transform.position.x) * step / 100;
|
|
2354
|
+
const deltaY = (layoutPosition.y - transform.position.y) * step / 100;
|
|
2355
|
+
const position2 = {
|
|
2356
|
+
x: transform.position.x + deltaX,
|
|
2357
|
+
y: transform.position.y + deltaY
|
|
2394
2358
|
};
|
|
2395
|
-
const deltaX = (position2.x - transform.position.x) * step / 100;
|
|
2396
|
-
const deltaY = (position2.y - transform.bounds.height / 2 - transform.position.y) * step / 100;
|
|
2397
2359
|
transform.update({
|
|
2398
|
-
position:
|
|
2399
|
-
x: transform.position.x + deltaX,
|
|
2400
|
-
y: transform.position.y + deltaY
|
|
2401
|
-
}
|
|
2360
|
+
position: position2
|
|
2402
2361
|
});
|
|
2403
2362
|
const document = layoutNode.entity.document;
|
|
2404
2363
|
document.layout.updateAffectedTransform(layoutNode.entity);
|
|
@@ -2406,7 +2365,6 @@ var LayoutPosition = class {
|
|
|
2406
2365
|
};
|
|
2407
2366
|
|
|
2408
2367
|
// src/layout/dagre.ts
|
|
2409
|
-
import { FlowNodeTransformData as FlowNodeTransformData2 } from "@flowgram.ai/document";
|
|
2410
2368
|
import { Graph as DagreGraph } from "@dagrejs/graphlib";
|
|
2411
2369
|
var DagreLayout = class {
|
|
2412
2370
|
constructor(store) {
|
|
@@ -2460,13 +2418,7 @@ var DagreLayout = class {
|
|
|
2460
2418
|
return graph;
|
|
2461
2419
|
}
|
|
2462
2420
|
graphSetData() {
|
|
2463
|
-
const nodes =
|
|
2464
|
-
const edges = Array.from(this.store.edges.values()).sort((next, prev) => {
|
|
2465
|
-
if (next.fromIndex === prev.fromIndex) {
|
|
2466
|
-
return next.toIndex < prev.toIndex ? -1 : 1;
|
|
2467
|
-
}
|
|
2468
|
-
return next.fromIndex < prev.fromIndex ? -1 : 1;
|
|
2469
|
-
});
|
|
2421
|
+
const { nodes, edges } = this.store;
|
|
2470
2422
|
nodes.forEach((layoutNode) => {
|
|
2471
2423
|
this.graph.setNode(layoutNode.index, {
|
|
2472
2424
|
originID: layoutNode.id,
|
|
@@ -2474,7 +2426,12 @@ var DagreLayout = class {
|
|
|
2474
2426
|
height: layoutNode.size.height
|
|
2475
2427
|
});
|
|
2476
2428
|
});
|
|
2477
|
-
edges.
|
|
2429
|
+
edges.sort((next, prev) => {
|
|
2430
|
+
if (next.fromIndex === prev.fromIndex) {
|
|
2431
|
+
return next.toIndex < prev.toIndex ? -1 : 1;
|
|
2432
|
+
}
|
|
2433
|
+
return next.fromIndex < prev.fromIndex ? -1 : 1;
|
|
2434
|
+
}).forEach((layoutEdge) => {
|
|
2478
2435
|
this.graph.setEdge({
|
|
2479
2436
|
v: layoutEdge.fromIndex,
|
|
2480
2437
|
w: layoutEdge.toIndex,
|
|
@@ -2505,12 +2462,11 @@ var DagreLayout = class {
|
|
|
2505
2462
|
return Number.isNaN(number) ? 0 : number;
|
|
2506
2463
|
}
|
|
2507
2464
|
getOffsetX(layoutNode) {
|
|
2508
|
-
if (
|
|
2465
|
+
if (layoutNode.layoutNodes.length === 0) {
|
|
2509
2466
|
return 0;
|
|
2510
2467
|
}
|
|
2511
|
-
const
|
|
2512
|
-
const
|
|
2513
|
-
const leftOffset = -bounds.width / 2 + padding.left;
|
|
2468
|
+
const { padding } = layoutNode;
|
|
2469
|
+
const leftOffset = -layoutNode.size.width / 2 + padding.left;
|
|
2514
2470
|
return leftOffset;
|
|
2515
2471
|
}
|
|
2516
2472
|
setOrderAndRank(g) {
|
|
@@ -2612,33 +2568,122 @@ var AutoLayoutService = class {
|
|
|
2612
2568
|
};
|
|
2613
2569
|
}
|
|
2614
2570
|
async layout(options = {}) {
|
|
2615
|
-
|
|
2571
|
+
const layoutOptions = {
|
|
2616
2572
|
...DefaultLayoutOptions,
|
|
2617
2573
|
...options
|
|
2618
|
-
}
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
const
|
|
2622
|
-
|
|
2574
|
+
};
|
|
2575
|
+
const containerNode = layoutOptions.containerNode ?? this.document.root;
|
|
2576
|
+
const container = this.createLayoutNode(containerNode, options);
|
|
2577
|
+
const layouts = await this.layoutNode(container, layoutOptions);
|
|
2578
|
+
const rect = this.getLayoutNodeRect(container);
|
|
2579
|
+
const positionPromise = layouts.map((layout2) => layout2.position());
|
|
2580
|
+
const fitViewPromise = this.fitView(layoutOptions, rect);
|
|
2581
|
+
await Promise.all([...positionPromise, fitViewPromise]);
|
|
2582
|
+
}
|
|
2583
|
+
async fitView(options, rect) {
|
|
2584
|
+
if (options.disableFitView === true) {
|
|
2623
2585
|
return;
|
|
2624
2586
|
}
|
|
2625
|
-
|
|
2626
|
-
|
|
2587
|
+
return this.playground.config.fitView(rect, options.enableAnimation, 30);
|
|
2588
|
+
}
|
|
2589
|
+
async layoutNode(container, options) {
|
|
2590
|
+
const { layoutNodes, layoutEdges } = container;
|
|
2591
|
+
if (layoutNodes.length === 0) {
|
|
2592
|
+
return [];
|
|
2593
|
+
}
|
|
2594
|
+
const childrenLayouts = (await Promise.all(layoutNodes.map((n) => this.layoutNode(n, options)))).flat();
|
|
2627
2595
|
const layout2 = new Layout(this.layoutConfig);
|
|
2628
|
-
layout2.init({
|
|
2596
|
+
layout2.init({ container, layoutNodes, layoutEdges }, options);
|
|
2629
2597
|
layout2.layout();
|
|
2630
|
-
|
|
2598
|
+
const rect = this.getLayoutNodeRect(container);
|
|
2599
|
+
container.size = {
|
|
2600
|
+
width: rect.width,
|
|
2601
|
+
height: rect.height
|
|
2602
|
+
};
|
|
2603
|
+
return [...childrenLayouts, layout2];
|
|
2604
|
+
}
|
|
2605
|
+
createLayoutNodes(nodes, options) {
|
|
2606
|
+
return nodes.map((node) => this.createLayoutNode(node, options));
|
|
2607
|
+
}
|
|
2608
|
+
/** 创建节点布局数据 */
|
|
2609
|
+
createLayoutNode(node, options) {
|
|
2610
|
+
const { blocks } = node;
|
|
2611
|
+
const edges = this.getNodesAllLines(blocks);
|
|
2612
|
+
const layoutNodes = this.createLayoutNodes(blocks, options);
|
|
2613
|
+
const layoutEdges = this.createLayoutEdges(edges);
|
|
2614
|
+
const { bounds, padding } = node.transform;
|
|
2615
|
+
const { width: width2, height, center } = bounds;
|
|
2616
|
+
const { x, y } = center;
|
|
2617
|
+
const layoutNode = {
|
|
2618
|
+
id: node.id,
|
|
2619
|
+
entity: node,
|
|
2620
|
+
index: "",
|
|
2621
|
+
// 初始化时,index 未计算
|
|
2622
|
+
rank: -1,
|
|
2623
|
+
// 初始化时,节点还未布局,层级为-1
|
|
2624
|
+
order: -1,
|
|
2625
|
+
// 初始化时,节点还未布局,顺序为-1
|
|
2626
|
+
position: { x, y },
|
|
2627
|
+
offset: { x: 0, y: 0 },
|
|
2628
|
+
padding,
|
|
2629
|
+
size: { width: width2, height },
|
|
2630
|
+
layoutNodes,
|
|
2631
|
+
layoutEdges
|
|
2632
|
+
};
|
|
2633
|
+
return layoutNode;
|
|
2634
|
+
}
|
|
2635
|
+
createLayoutEdges(edges) {
|
|
2636
|
+
const layoutEdges = edges.map((edge) => this.createLayoutEdge(edge)).filter(Boolean);
|
|
2637
|
+
return layoutEdges;
|
|
2638
|
+
}
|
|
2639
|
+
/** 创建线条布局数据 */
|
|
2640
|
+
createLayoutEdge(edge) {
|
|
2641
|
+
const { from, to } = edge.info;
|
|
2642
|
+
if (!from || !to || edge.vertical) {
|
|
2643
|
+
return;
|
|
2644
|
+
}
|
|
2645
|
+
const layoutEdge = {
|
|
2646
|
+
id: edge.id,
|
|
2647
|
+
entity: edge,
|
|
2648
|
+
from,
|
|
2649
|
+
to,
|
|
2650
|
+
fromIndex: "",
|
|
2651
|
+
// 初始化时,index 未计算
|
|
2652
|
+
toIndex: "",
|
|
2653
|
+
// 初始化时,index 未计算
|
|
2654
|
+
name: edge.id
|
|
2655
|
+
};
|
|
2656
|
+
return layoutEdge;
|
|
2631
2657
|
}
|
|
2632
2658
|
getNodesAllLines(nodes) {
|
|
2633
2659
|
const lines = nodes.map((node) => {
|
|
2634
|
-
const linesData = node.getData(
|
|
2660
|
+
const linesData = node.getData(WorkflowNodeLinesData);
|
|
2635
2661
|
const outputLines = linesData.outputLines.filter(Boolean);
|
|
2636
2662
|
const inputLines = linesData.inputLines.filter(Boolean);
|
|
2637
2663
|
return [...outputLines, ...inputLines];
|
|
2638
2664
|
}).flat();
|
|
2639
2665
|
return lines;
|
|
2640
2666
|
}
|
|
2667
|
+
getLayoutNodeRect(layoutNode) {
|
|
2668
|
+
const rects = layoutNode.layoutNodes.map((node) => this.layoutNodeRect(node));
|
|
2669
|
+
const rect = Rectangle.enlarge(rects);
|
|
2670
|
+
const { padding } = layoutNode;
|
|
2671
|
+
const width2 = rect.width + padding.left + padding.right;
|
|
2672
|
+
const height = rect.height + padding.top + padding.bottom;
|
|
2673
|
+
const x = rect.x - padding.left;
|
|
2674
|
+
const y = rect.y - padding.top;
|
|
2675
|
+
return new Rectangle(x, y, width2, height);
|
|
2676
|
+
}
|
|
2677
|
+
layoutNodeRect(layoutNode) {
|
|
2678
|
+
const { width: width2, height } = layoutNode.size;
|
|
2679
|
+
const x = layoutNode.position.x - width2 / 2;
|
|
2680
|
+
const y = layoutNode.position.y - height / 2;
|
|
2681
|
+
return new Rectangle(x, y, width2, height);
|
|
2682
|
+
}
|
|
2641
2683
|
};
|
|
2684
|
+
__decorateClass([
|
|
2685
|
+
inject(Playground)
|
|
2686
|
+
], AutoLayoutService.prototype, "playground", 2);
|
|
2642
2687
|
__decorateClass([
|
|
2643
2688
|
inject(WorkflowDocument)
|
|
2644
2689
|
], AutoLayoutService.prototype, "document", 2);
|