File size: 1,537 Bytes
d9494a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import Dagre from '@dagrejs/dagre';

import { WORKFLOW_LAYOUT_DEFAULT_OPTIONS } from '@/workflow/layout/constants/WorkflowLayoutDefaultOptions';

export type WorkflowLayoutNode = {
  id: string;
  width: number;
  height: number;
};

export type WorkflowLayoutEdge = {
  source: string;
  target: string;
};

export type WorkflowLayoutPosition = {
  id: string;
  position: { x: number; y: number };
};

export type WorkflowLayoutOptions = {
  ranksep: number;
  nodesep: number;
  rankdir: string;
};

export const computeWorkflowLayout = ({
  nodes,
  edges,
  options = WORKFLOW_LAYOUT_DEFAULT_OPTIONS,
}: {
  nodes: WorkflowLayoutNode[];
  edges: WorkflowLayoutEdge[];
  options?: WorkflowLayoutOptions;
}): WorkflowLayoutPosition[] => {
  const graph = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));

  graph.setGraph({
    ranksep: options.ranksep,
    nodesep: options.nodesep,
    rankdir: options.rankdir,
  });

  const nodeIds = new Set(nodes.map((node) => node.id));

  nodes.forEach((node) =>
    graph.setNode(node.id, {
      width: node.width,
      height: node.height,
    }),
  );

  edges.forEach((edge) => {
    if (nodeIds.has(edge.source) && nodeIds.has(edge.target)) {
      graph.setEdge(edge.source, edge.target);
    }
  });

  Dagre.layout(graph);

  return nodes.map((node) => {
    const layoutedNode = graph.node(node.id);

    const x = layoutedNode.x - layoutedNode.width / 2;
    const y = layoutedNode.y - layoutedNode.height / 2;

    return { id: node.id, position: { x, y } };
  });
};