File size: 2,643 Bytes
3382f47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import React, { useEffect, useRef, useState } from "react";
import { Network } from "vis-network";
import { DataSet } from "vis-data";

import tw from "tailwind-styled-components";

import { GraphNode, TaskData } from "../../lib/types";

interface GraphEdge {
  id: string;
  from: string;
  to: string;
  arrows: string;
}

interface GraphProps {
  graphData: {
    nodes: GraphNode[];
    edges: GraphEdge[];
  };
  setSelectedTask: React.Dispatch<React.SetStateAction<TaskData | null>>;
  setIsTaskInfoExpanded: React.Dispatch<React.SetStateAction<boolean>>;
}

const Graph: React.FC<GraphProps> = ({
  graphData,
  setSelectedTask,
  setIsTaskInfoExpanded,
}) => {
  const graphRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!graphRef.current) {
      return;
    }
    const nodes = new DataSet<GraphNode>(graphData.nodes);
    const edges = new DataSet<GraphEdge>(graphData.edges);

    const data = {
      nodes: nodes,
      edges: edges,
    };

    const options = {
      nodes: {
        font: {
          size: 20, // Increased font size for labels
          color: "black", // Set a readable font color
        },
        shapeProperties: {
          useBorderWithImage: true,
        },
      },
      edges: {
        length: 250, // Increased edge length
      },
      layout: {
        hierarchical: {
          enabled: true,
          levelSeparation: 300,
          nodeSpacing: 250,
          treeSpacing: 250,
          blockShifting: true,
          edgeMinimization: true,
          parentCentralization: true,
          direction: "UD",
          sortMethod: "directed",
        },
      },
      physics: {
        stabilization: {
          enabled: true,
          iterations: 1000,
        },
        hierarchicalRepulsion: {
          centralGravity: 0.0,
          springLength: 200,
          springConstant: 0.01,
          nodeDistance: 300,
          damping: 0.09,
        },
        timestep: 0.5,
      },
    };

    const network = new Network(graphRef.current, data, options);

    // Add an event listener for node clicks
    network.on("click", (params) => {
      if (params.nodes.length) {
        const nodeId = params.nodes[0];
        const clickedNodeArray = nodes.get(nodeId);
        if (clickedNodeArray) {
          setSelectedTask((clickedNodeArray as any).data as TaskData);
          setIsTaskInfoExpanded(true);
        }
      } else {
        setSelectedTask(null);
        setIsTaskInfoExpanded(false);
      }
    });
  }, [graphData]);

  return <GraphContainer ref={graphRef} />;
};

export default Graph;

const GraphContainer = tw.div`
  w-full
  h-full
`;