Skip to content

Commit 9281fcc

Browse files
committed
[Feature][Graph Render]Nodes and initial render implementation
1 parent f4731c1 commit 9281fcc

File tree

2 files changed

+94
-61
lines changed

2 files changed

+94
-61
lines changed

src/modules/universe/NeuroJsonGraph.tsx

Lines changed: 85 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import ForceGraph3D from "3d-force-graph";
2-
import { Colors } from "design/theme";
3-
import { useAppDispatch } from "hooks/useAppDispatch";
4-
import { useAppSelector } from "hooks/useAppSelector";
52
import React, { useEffect, useRef } from "react";
6-
import { fetchRegistry } from "redux/neurojson/neurojson.action";
7-
import { NeurojsonSelector } from "redux/neurojson/neurojson.selector";
83
import * as THREE from "three";
94
import {
105
CSS2DObject,
116
CSS2DRenderer,
127
} from "three/examples/jsm/renderers/CSS2DRenderer";
138
import { Database } from "types/responses/registry.interface";
149

10+
// Define the interface for NodeObject
1511
interface NodeObject {
1612
id: string;
1713
name: string;
@@ -25,76 +21,105 @@ interface NodeObject {
2521
const NeuroJsonGraph: React.FC<{ registry: Database[] }> = ({ registry }) => {
2622
const graphRef = useRef<HTMLDivElement>(null);
2723

28-
const { loading, error } = useAppSelector(NeurojsonSelector);
24+
// Debug log for registry data
25+
useEffect(() => {
26+
console.log("From NeuroJsonGraph, registry:", registry);
27+
}, [registry]);
2928

3029
useEffect(() => {
31-
if (graphRef.current && registry) {
32-
const graphData = {
33-
nodes: registry.map((db: Database) => ({
34-
id: db.id,
35-
name: db.fullname || db.name,
36-
dbname: db.name,
37-
color: "rgba(255,255,255,0.8)",
38-
datatype: db.datatype,
39-
support: db.support,
40-
url: db.url,
41-
})),
42-
links: [],
43-
};
44-
45-
const Graph = ForceGraph3D()(graphRef.current)
46-
.graphData(graphData)
47-
.nodeRelSize(2)
48-
.nodeColor(
49-
(node) => (node as NodeObject).color || "rgba(255,255,255,0.8)"
50-
)
51-
.linkWidth(1)
52-
.backgroundColor(Colors.primary.light)
53-
.nodeLabel("name")
54-
.nodeThreeObject((node) => {
55-
const nodeEl = document.createElement("span");
56-
const castNode = node as NodeObject;
57-
nodeEl.textContent = castNode.dbname || "Unnamed";
58-
nodeEl.className = "orglabel";
59-
return new CSS2DObject(nodeEl);
30+
// Ensure registry and graphRef are properly initialized
31+
if (!registry || registry.length === 0) {
32+
console.error("Registry is empty or undefined:", registry);
33+
return;
34+
}
35+
36+
if (!graphRef.current) {
37+
console.error("Graph ref is null");
38+
return;
39+
}
40+
41+
// Prepare graph data
42+
const graphData = {
43+
nodes: registry.map((db) => ({
44+
id: db.id,
45+
name: db.fullname || db.name,
46+
dbname: db.name,
47+
color: "rgba(255,255,255,1)", // White color for nodes
48+
datatype: db.datatype,
49+
support: db.support,
50+
url: db.url,
51+
})),
52+
links: [], // Add links if needed
53+
};
54+
55+
// Initialize 3D Force Graph
56+
const Graph = ForceGraph3D()(graphRef.current)
57+
.graphData(graphData)
58+
.nodeRelSize(2)
59+
.nodeColor((node) => (node as NodeObject).color || "rgba(255,255,255,1)") // White nodes
60+
.backgroundColor("rgba(0,0,0,0)") // Transparent background
61+
.nodeLabel("name")
62+
.nodeThreeObject((node) => {
63+
const castNode = node as NodeObject;
64+
65+
// Create a 3D sphere for the node
66+
const sphereGeometry = new THREE.SphereGeometry(5, 16, 16); // Radius 5
67+
const sphereMaterial = new THREE.MeshBasicMaterial({
68+
color: "white",
6069
});
70+
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
6171

62-
// Initialize CSS2DRenderer for 2D labels
63-
const labelRenderer = new CSS2DRenderer();
64-
labelRenderer.setSize(window.innerWidth, window.innerHeight);
65-
labelRenderer.domElement.style.position = "absolute";
66-
labelRenderer.domElement.style.top = "0px";
67-
graphRef.current?.appendChild(labelRenderer.domElement);
72+
// Add label as CSS2DObject
73+
const label = new CSS2DObject(document.createElement("div"));
74+
label.element.textContent = castNode.dbname || "Unnamed";
75+
label.element.style.color = "white";
76+
label.element.style.fontSize = "10px";
77+
label.element.style.pointerEvents = "none"; // Prevent interaction
78+
label.position.set(0, 10, 0); // Position label above the node
79+
sphere.add(label);
6880

69-
// Simple render without overriding WebGLRenderer behavior
70-
Graph.renderer().domElement.addEventListener("render", (e) => {
71-
labelRenderer.render(Graph.scene(), Graph.camera());
81+
return sphere;
7282
});
7383

74-
// Handle window resize
75-
const resizeGraph = () => {
76-
Graph.width(window.innerWidth).height(window.innerHeight);
77-
labelRenderer.setSize(window.innerWidth, window.innerHeight);
78-
};
79-
resizeGraph();
80-
window.addEventListener("resize", resizeGraph);
81-
82-
return () => {
83-
window.removeEventListener("resize", resizeGraph);
84-
};
85-
}
86-
}, [registry]);
84+
// Initialize CSS2DRenderer for 2D labels
85+
const labelRenderer = new CSS2DRenderer();
86+
labelRenderer.setSize(window.innerWidth, window.innerHeight);
87+
labelRenderer.domElement.style.position = "absolute";
88+
labelRenderer.domElement.style.top = "0px";
89+
labelRenderer.domElement.style.pointerEvents = "none"; // Prevent interaction
90+
graphRef.current?.appendChild(labelRenderer.domElement);
91+
92+
// Animate label rendering
93+
const animate = () => {
94+
requestAnimationFrame(animate);
95+
labelRenderer.render(Graph.scene(), Graph.camera());
96+
};
97+
animate();
8798

88-
if (loading) return <div>Loading...</div>;
89-
if (error) return <div>Error: {error}</div>;
99+
// Handle window resize
100+
const resizeGraph = () => {
101+
Graph.width(window.innerWidth).height(window.innerHeight);
102+
labelRenderer.setSize(window.innerWidth, window.innerHeight);
103+
};
104+
resizeGraph();
105+
window.addEventListener("resize", resizeGraph);
106+
107+
// Cleanup on component unmount
108+
return () => {
109+
window.removeEventListener("resize", resizeGraph);
110+
if (graphRef.current) {
111+
graphRef.current.removeChild(labelRenderer.domElement);
112+
}
113+
};
114+
}, [registry]);
90115

91116
return (
92117
<div
93118
ref={graphRef}
94119
style={{
95120
width: "100%",
96121
height: "100vh",
97-
backgroundColor: Colors.primary.dark,
122+
backgroundColor: "transparent",
98123
position: "relative",
99124
}}
100125
/>

src/pages/Home.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,17 @@ const Home: React.FC = () => {
1212

1313
useEffect(() => {
1414
dispatch(fetchRegistry());
15+
console.log(registry);
1516
}, [dispatch]);
17+
1618
return (
17-
<Container>{registry && <NeuroJsonGraph registry={registry} />}</Container>
19+
<Container style={{ width: "100%", height: "100vh", padding: 0 }}>
20+
{registry && registry.length > 0 ? (
21+
<NeuroJsonGraph registry={registry} />
22+
) : (
23+
<div>No data available to display</div>
24+
)}
25+
</Container>
1826
);
1927
};
2028

0 commit comments

Comments
 (0)