11import ForceGraph3D from "3d-force-graph" ;
2- import { Colors } from "design/theme" ;
3- import { useAppDispatch } from "hooks/useAppDispatch" ;
4- import { useAppSelector } from "hooks/useAppSelector" ;
52import React , { useEffect , useRef } from "react" ;
6- import { fetchRegistry } from "redux/neurojson/neurojson.action" ;
7- import { NeurojsonSelector } from "redux/neurojson/neurojson.selector" ;
83import * as THREE from "three" ;
94import {
105 CSS2DObject ,
116 CSS2DRenderer ,
127} from "three/examples/jsm/renderers/CSS2DRenderer" ;
138import { Database } from "types/responses/registry.interface" ;
149
10+ // Define the interface for NodeObject
1511interface NodeObject {
1612 id : string ;
1713 name : string ;
@@ -25,76 +21,105 @@ interface NodeObject {
2521const 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 />
0 commit comments