Skip to content

Commit 42d6098

Browse files
committed
Starting point for force-directed graph
1 parent f61a596 commit 42d6098

File tree

3 files changed

+115
-2
lines changed

3 files changed

+115
-2
lines changed

packages/feedback-components/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414
"@macrostrat/color-utils": "workspace:^1.0.0",
1515
"@macrostrat/hyper": "^3.0.0",
1616
"@macrostrat/ui-components": "workspace:*",
17+
"@xyflow/react": "^12.3.6",
18+
"d3-force": "^3.0.0",
1719
"react": "^17.0.2||^18",
1820
"react-arborist": "^3.4.0",
19-
"react-flow": "^1.0.3",
2021
"react-text-annotate-blend": "^1.2.0"
2122
},
2223
"exports": {
@@ -33,5 +34,8 @@
3334
"type": "git",
3435
"url": "https://github.com/UW-Macrostrat/web-components.git",
3536
"directory": "packages/feedback-components"
37+
},
38+
"devDependencies": {
39+
"@types/d3-force": "^3"
3640
}
3741
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { TreeData } from "./types";
2+
import { treeToGraph } from "./edit-state";
3+
import h from "@macrostrat/hyper";
4+
5+
import {
6+
forceSimulation,
7+
SimulationNodeDatum,
8+
SimulationLinkDatum,
9+
forceCenter,
10+
forceLink,
11+
forceManyBody,
12+
forceCollide,
13+
} from "d3-force";
14+
import { useEffect, useState } from "react";
15+
import { Spinner } from "@blueprintjs/core";
16+
17+
export function GraphView(props: {
18+
tree: TreeData[];
19+
width: number;
20+
height: number;
21+
}) {
22+
// A graph view with react-flow
23+
// Get positions of nodes using force simulation
24+
const { tree, width, height } = props;
25+
26+
const [nodes, setNodes] = useState<SimulationNodeDatum[]>(null);
27+
const [links, setLinks] = useState<SimulationLinkDatum[]>(null);
28+
29+
useEffect(() => {
30+
const { nodes, edges } = treeToGraph(tree);
31+
32+
const nodesMap = new Map<number, SimulationNodeDatum>(
33+
nodes.map((d) => [d.id, d])
34+
);
35+
36+
const links = edges.map((d) => {
37+
return {
38+
source: nodesMap.get(d.source),
39+
target: nodesMap.get(d.dest),
40+
strength: 1,
41+
};
42+
});
43+
44+
const simulation = forceSimulation(nodes)
45+
.force("link", forceLink(links))
46+
.force("charge", forceManyBody().strength(-50))
47+
.force("center", forceCenter(width / 2, height / 2))
48+
.force("collide", forceCollide().radius(20))
49+
.on("tick", () => {
50+
// Update the positions of the nodes
51+
// setNodes(nodes);
52+
console.log("Simulation tick");
53+
})
54+
.on("end", () => {
55+
// Update the positions of the nodes
56+
setNodes(nodes);
57+
setLinks(links);
58+
});
59+
60+
return () => {
61+
simulation.stop();
62+
};
63+
}, [tree, width, height]);
64+
65+
if (nodes == null || links == null) {
66+
return h(Spinner);
67+
}
68+
69+
console.log("Graph", nodes, links);
70+
71+
return h("div.graph-view", { style: { width, height } }, [
72+
h("svg", { width, height }, [
73+
h(
74+
"g.nodes",
75+
nodes.map((d) => {
76+
return h("circle", {
77+
cx: d.x,
78+
cy: d.y,
79+
r: 5,
80+
fill: "blue",
81+
});
82+
})
83+
),
84+
h(
85+
"g.links",
86+
links.map((d) => {
87+
return h("line", {
88+
x1: d.source.x,
89+
y1: d.source.y,
90+
x2: d.target.x,
91+
y2: d.target.y,
92+
stroke: "black",
93+
});
94+
})
95+
),
96+
]),
97+
]);
98+
}

packages/feedback-components/src/feedback/index.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ import { FeedbackText } from "./text-visualizer";
77
import type { InternalEntity, TreeData } from "./types";
88
import type { Entity } from "../extractions";
99
import { ModelInfo } from "../extractions";
10-
import { TreeDispatchContext, useUpdatableTree, ViewMode } from "./edit-state";
10+
import {
11+
TreeDispatchContext,
12+
treeToGraph,
13+
useUpdatableTree,
14+
ViewMode,
15+
} from "./edit-state";
1116
import { useCallback, useEffect, useRef } from "react";
1217
import { ButtonGroup, Card, SegmentedControl } from "@blueprintjs/core";
1318
import { OmniboxSelector } from "./type-selector";
@@ -19,6 +24,7 @@ import {
1924
SaveButton,
2025
} from "@macrostrat/ui-components";
2126
import useElementDimensions from "use-element-dimensions";
27+
import { GraphView } from "./graph";
2228

2329
export type { GraphData } from "./edit-state";
2430
export { treeToGraph } from "./edit-state";
@@ -137,6 +143,11 @@ export function FeedbackComponent({
137143
height,
138144
matchComponent,
139145
}),
146+
h.if(state.viewMode == "graph")(GraphView, {
147+
tree,
148+
width,
149+
height,
150+
}),
140151
]
141152
),
142153
]);

0 commit comments

Comments
 (0)