Skip to content

Commit f2dfa09

Browse files
committed
Add Graph utils to start handling basic traversals.
* Breadth First Search * Depth First Search * Generate Random Graph * Populate Graph from Nodes
1 parent 7c21920 commit f2dfa09

File tree

8 files changed

+194
-9
lines changed

8 files changed

+194
-9
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Node } from '../utils/GraphUtils';
2+
3+
export default function BreadthFirstSearch(nodeMap: Node[], setNodes: (nodes: any) => void, selectedId: string) {
4+
let queue: Node[] = [];
5+
let visited: Node[] = [];
6+
7+
for (let i = 0; i < nodeMap.length; i++) {
8+
if (nodeMap[i].id === selectedId) {
9+
queue.push(nodeMap[i]);
10+
visited.push(nodeMap[i]);
11+
}
12+
}
13+
14+
function processQueue() {
15+
if (queue.length > 0) {
16+
let currentNode: Node = queue.shift()!;
17+
currentNode.fill = 'darkseagreen';
18+
for (let i = 0; i < currentNode.children.length; i++) {
19+
if (!visited.includes(currentNode.children[i])) {
20+
queue.push(currentNode.children[i]);
21+
visited.push(currentNode.children[i]);
22+
}
23+
}
24+
setNodes([...nodeMap]);
25+
setTimeout(processQueue, 1000); // 1 second delay
26+
}
27+
}
28+
29+
setTimeout(processQueue, 1000); // 1 second delay
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Node } from '../utils/GraphUtils';
2+
3+
export default function DepthFirstSearch(nodeMap: Node[], setNodes: (nodes: any) => void, selectedId: string) {
4+
let queue: Node[] = [];
5+
let visited: Node[] = [];
6+
7+
for (let i = 0; i < nodeMap.length; i++) {
8+
if (nodeMap[i].id === selectedId) {
9+
queue.push(nodeMap[i]);
10+
visited.push(nodeMap[i]);
11+
}
12+
}
13+
14+
function processQueue() {
15+
if (queue.length > 0) {
16+
let currentNode: Node = queue.pop()!;
17+
currentNode.fill = 'darkseagreen';
18+
for (let i = 0; i < currentNode.children.length; i++) {
19+
if (!visited.includes(currentNode.children[i])) {
20+
queue.push(currentNode.children[i]);
21+
visited.push(currentNode.children[i]);
22+
}
23+
}
24+
setNodes([...nodeMap]);
25+
setTimeout(processQueue, 1000); // 1 second delay
26+
}
27+
}
28+
29+
setTimeout(processQueue, 1000); // 1 second delay
30+
}

src/algorithms/graphs/GenerateRandomGraph.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ export default function GenerateRandomGraph(numNodes: number, setNodes: (nodes:
33
for (let i = 0; i < numNodes; i++) {
44
nodeTemp.push({
55
id: i.toString(),
6-
fill: 'slateblue',
6+
fill: 'purple',
77
});
88
}
99
setNodes(nodeTemp);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
import { Node } from '../utils/GraphUtils';
3+
4+
export default function PopulateGraphMap(nodeMap: Node[], setNodes: (nodes: any) => void, setEdges: (edges: any) => void) {
5+
const nodes = [];
6+
const edges = [];
7+
for (let i = 0; i < nodeMap.length; i++) {
8+
nodes.push({
9+
id: nodeMap[i].id,
10+
label: nodeMap[i].label,
11+
});
12+
for (let j = 0; j < nodeMap[i].children.length; j++) {
13+
edges.push({
14+
id: nodeMap[i].id + '-' + nodeMap[i].children[j].id,
15+
source: nodeMap[i].id,
16+
target: nodeMap[i].children[j].id,
17+
label: nodeMap[i].id + '-' + nodeMap[i].children[j].id,
18+
});
19+
}
20+
for (let j = 0; j < nodeMap[i].parents.length; j++) {
21+
edges.push({
22+
id: nodeMap[i].parents[j].id + '-' + nodeMap[i].id,
23+
source: nodeMap[i].parents[j].id,
24+
target: nodeMap[i].id,
25+
label: nodeMap[i].parents[j].id + '-' + nodeMap[i].id,
26+
});
27+
}
28+
}
29+
setNodes(nodes);
30+
setEdges(edges);
31+
}

src/algorithms/utils/GraphUtils.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Define a class to represent a cell in the maze
2+
export class Node {
3+
id: string;
4+
label: string;
5+
fill: string;
6+
children: Node[];
7+
parents: Node[];
8+
9+
constructor(id: string, label: string, fill: string) {
10+
this.id = id;
11+
this.label = label;
12+
this.fill = fill;
13+
this.children = [];
14+
this.parents = [];
15+
}
16+
}

src/pages/GraphVisualiser.tsx

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,63 @@
11
import React, {useState, useEffect} from 'react';
22
import { GraphCanvas } from 'reagraph';
33
import GenerateRandomGraph from '../algorithms/graphs/GenerateRandomGraph';
4+
import BreadthFirstSearch from '../algorithms/graphs/BreadthFirstSearch';
5+
import DepthFirstSearch from '../algorithms/graphs/DepthFirstSearch';
6+
import { Node } from '../algorithms/utils/GraphUtils';
7+
import PopulateGraphMap from '../algorithms/graphs/PopulateGraphMap';
48
import '../styles/graph.css';
9+
import { GraphAlgorithm } from '../utils/GraphEnum';
510

611
const GraphVisualiser: React.FC = () => {
7-
const [edges, _] = useState([]);
12+
const [edges, setEdges] = useState([]);
813
const [nodes, setNodes] = useState<{ id: string }[]>([]); // Specify the type of the nodes state variable
14+
const [algorithm, setAlgorithm] = useState(GraphAlgorithm.BFS);
15+
16+
const nodeMap: Node[] = [
17+
new Node('0', '0', 'slateblue'),
18+
new Node('1', '1', 'slateblue'),
19+
new Node('2', '2', 'slateblue'),
20+
new Node('3', '3', 'slateblue'),
21+
new Node('4', '4', 'slateblue'),
22+
new Node('5', '5', 'slateblue'),
23+
new Node('6', '6', 'slateblue'),
24+
new Node('7', '7', 'slateblue'),
25+
new Node('8', '8', 'slateblue'),
26+
new Node('9', '9', 'slateblue'),
27+
];
28+
29+
nodeMap[0].children.push(nodeMap[1]);
30+
nodeMap[1].children.push(nodeMap[2]);
31+
nodeMap[2].children.push(nodeMap[3]);
32+
nodeMap[3].children.push(nodeMap[4]);
33+
nodeMap[3].children.push(nodeMap[7]);
34+
nodeMap[4].children.push(nodeMap[8]);
35+
nodeMap[4].children.push(nodeMap[5]);
36+
nodeMap[4].children.push(nodeMap[6]);
37+
nodeMap[1].children.push(nodeMap[0]);
38+
nodeMap[5].children.push(nodeMap[9]);
939

1040
useEffect(() => {
11-
GenerateRandomGraph(10, setNodes);
41+
PopulateGraphMap(nodeMap, setNodes, setEdges);
1242
}, []);
1343

44+
1445
return (
1546
<div className="graph-canvas">
16-
<GraphCanvas
17-
nodes={nodes}
18-
edges={edges}
19-
/>
47+
<div className="graph-canvas-control-panel">
48+
<h4>Double Click Node to run algorithm.</h4>
49+
<select className="graph-canvas-control" onChange={(event) => {setAlgorithm(event.target.value as GraphAlgorithm)}}>
50+
<option value={GraphAlgorithm.DFS}>Depth First Search</option>
51+
<option value={GraphAlgorithm.BFS}>Breadth First Search</option>
52+
</select>
53+
</div>
54+
<div className="graph-canvas-art">
55+
<GraphCanvas
56+
nodes={nodes}
57+
edges={edges}
58+
onNodeDoubleClick={node => DepthFirstSearch(nodeMap, setNodes, node.id)}
59+
/>
60+
</div>
2061
</div>
2162
);
2263
};

src/styles/graph.css

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,44 @@
11
.graph-canvas {
22
width: 100%;
33
height: 100svh;
4+
display:flex;
5+
flex-direction: column;
46
}
57

6-
7-
.graph-canvas > div {
8+
.graph-canvas > .graph-canvas-art {
89
position: relative;
910
width:100%;
1011
height: 100%;
12+
}
13+
14+
.graph-canvas-control-panel{
15+
display: flex;
16+
flex-direction: row;
17+
position: relative;
18+
height: 64px;
19+
background-color: #6A0DAD;
20+
opacity: 80%;
21+
transition: .5s;
22+
}
23+
24+
.graph-canvas-control-panel > h4 {
25+
margin: auto;
26+
}
27+
28+
.graph-canvas-control {
29+
z-index: 100;
30+
position: relative;
31+
top: 0;
32+
height: 24px;
33+
width: 200px;
34+
margin: auto;
35+
display: flex;
36+
justify-content: center; /** X-axis align **/
37+
color: black;
38+
background-color: white;
39+
}
40+
41+
.graph-outer{
42+
height: 100svh;
43+
width: 100%;
1144
}

src/utils/GraphEnum.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export enum GraphAlgorithm {
2+
BFS = 'bfs',
3+
DFS = 'dfs',
4+
}

0 commit comments

Comments
 (0)