1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
| import { useCallback } from 'react'
| import ELK from 'elkjs/lib/elk.bundled.js'
| import {
| useReactFlow,
| useStoreApi,
| } from 'reactflow'
| import { cloneDeep } from 'lodash-es'
| import type {
| Edge,
| Node,
| } from '../types'
| import { useWorkflowStore } from '../store'
| import { AUTO_LAYOUT_OFFSET } from '../constants'
| import { useNodesSyncDraft } from './use-nodes-sync-draft'
|
| const layoutOptions = {
| 'elk.algorithm': 'layered',
| 'elk.direction': 'RIGHT',
| 'elk.layered.spacing.nodeNodeBetweenLayers': '60',
| 'elk.spacing.nodeNode': '40',
| 'elk.layered.nodePlacement.strategy': 'SIMPLE',
| }
|
| const elk = new ELK()
|
| export const getLayoutedNodes = async (nodes: Node[], edges: Edge[]) => {
| const graph = {
| id: 'root',
| layoutOptions,
| children: nodes.map((n) => {
| return {
| ...n,
| width: n.width ?? 150,
| height: n.height ?? 50,
| targetPosition: 'left',
| sourcePosition: 'right',
| }
| }),
| edges: cloneDeep(edges),
| }
|
| const layoutedGraph = await elk.layout(graph as any)
| const layoutedNodes = nodes.map((node) => {
| const layoutedNode = layoutedGraph.children?.find(
| lgNode => lgNode.id === node.id,
| )
|
| return {
| ...node,
| position: {
| x: (layoutedNode?.x ?? 0) + AUTO_LAYOUT_OFFSET.x,
| y: (layoutedNode?.y ?? 0) + AUTO_LAYOUT_OFFSET.y,
| },
| }
| })
|
| return {
| layoutedNodes,
| }
| }
|
| export const useNodesLayout = () => {
| const store = useStoreApi()
| const reactflow = useReactFlow()
| const workflowStore = useWorkflowStore()
| const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
| const handleNodesLayout = useCallback(async () => {
| workflowStore.setState({ nodeAnimation: true })
| const {
| getNodes,
| edges,
| setNodes,
| } = store.getState()
| const { setViewport } = reactflow
| const nodes = getNodes()
| const {
| layoutedNodes,
| } = await getLayoutedNodes(nodes, edges)
|
| setNodes(layoutedNodes)
| const zoom = 0.7
| setViewport({
| x: 0,
| y: 0,
| zoom,
| })
| setTimeout(() => {
| handleSyncWorkflowDraft()
| })
| }, [store, reactflow, handleSyncWorkflowDraft, workflowStore])
|
| return {
| handleNodesLayout,
| }
| }
|
|