Skip to content

Commit 881dd0d

Browse files
committed
Revise the circle nodes layout to a constellation-style graph
1 parent f9fc708 commit 881dd0d

File tree

1 file changed

+119
-25
lines changed

1 file changed

+119
-25
lines changed

src/modules/universe/NeuroJsonGraph.tsx

Lines changed: 119 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,27 @@ const NeuroJsonGraph: React.FC<{
7777
// if (size > 3) return { color: Colors.primary.main, size: 7 };
7878
// return { color: Colors.primary.light, size: 5 };
7979
// };
80+
// Custom random number generator (same as `mulberry32`)
81+
const mulberry32 = (a: number) => {
82+
return function () {
83+
let t = (a += 0x6d2b79f5);
84+
t = Math.imul(t ^ (t >>> 15), t | 1);
85+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
86+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
87+
};
88+
};
89+
90+
const rngfun = mulberry32(0x123456789); // Seeded random function
91+
92+
// // Shuffle nodes
93+
// const nodenum = registry.length;
94+
// const randnode = [...Array(nodenum).keys()];
95+
96+
// Fisher-Yates Shuffle
97+
// for (let i = 0; i < nodenum; i++) {
98+
// const j = Math.floor(rngfun() * (i + 1));
99+
// [randnode[i], randnode[j]] = [randnode[j], randnode[i]];
100+
// }
80101

81102
useEffect(() => {
82103
// Ensure registry and graphRef are properly initialized
@@ -90,6 +111,33 @@ const NeuroJsonGraph: React.FC<{
90111
return;
91112
}
92113

114+
let colorlist: { brightness: number; index: number }[] = registry.map(
115+
(db, index) => {
116+
const colorStr = blendColors(db.datatype); // Get color in "rgb(R,G,B)" format
117+
118+
// **Extract RGB values from the string**
119+
const match = colorStr.match(/\d+/g); // Get numbers from "rgb(R,G,B)"
120+
if (!match) return { brightness: 255, index }; // Default to white if extraction fails
121+
122+
const [r, g, b] = match.map(Number); // Convert to numbers
123+
const brightness = 0.2126 * r + 0.7152 * g + 0.0722 * b; // Compute brightness
124+
125+
return { brightness, index };
126+
}
127+
);
128+
129+
// **2️⃣ Sort nodes by brightness (dark → bright)**
130+
colorlist.sort((a, b) => a.brightness - b.brightness);
131+
132+
// // **3️⃣ Create shuffled node list using Fisher-Yates algorithm**
133+
// const nodenum = registry.length;
134+
// const randnode = colorlist.map((item) => item.index); // Get sorted indices
135+
136+
// for (let i = 0; i < nodenum; i++) {
137+
// const j = Math.floor(rngfun() * (i + 1));
138+
// [randnode[i], randnode[j]] = [randnode[j], randnode[i]];
139+
// }
140+
93141
// Prepare graph data
94142
const graphData = {
95143
nodes: registry.map((db) => {
@@ -107,35 +155,81 @@ const NeuroJsonGraph: React.FC<{
107155
url: db.url,
108156
datasets: db.datasets,
109157
size: size,
110-
standard: db.standard || [], // add standard property
158+
standard: db.standard || [],
111159
};
112160
}),
113-
links: registry.flatMap((db, index) => {
114-
const connections = [];
115-
const nextIndex = (index + 1) % registry.length;
116-
// const { color } = size2colorAndSize(db.datasets);
117-
const color = blendColors(db.datatype);
118-
connections.push({
119-
source: db.id,
120-
target: registry[nextIndex].id,
121-
color: color,
122-
visible: true,
123-
});
124-
return connections;
125161

126-
// non-circle rendering
127-
// const similarNodes = registry.filter(
128-
// (otherDb) =>
129-
// db.datatype.some((type) => otherDb.datatype.includes(type)) &&
130-
// db.id !== otherDb.id
131-
// );
162+
links: registry.flatMap((db, index) => {
163+
// const color = blendColors(db.datatype);
164+
// return registry
165+
// .filter(
166+
// (otherDb) =>
167+
// db.id !== otherDb.id &&
168+
// db.datatype.some((type) => otherDb.datatype.includes(type))
169+
// )
170+
// .map((otherDB) => ({
171+
// source: db.id,
172+
// target: otherDB.id,
173+
// color: Colors.lightGray,
174+
// visible: true,
175+
// }));
132176

133-
// return similarNodes.map((otherDb) => ({
177+
// const connections = [];
178+
// const nextIndex = (index + 1) % registry.length;
179+
// // const { color } = size2colorAndSize(db.datasets);
180+
// const color = blendColors(db.datatype);
181+
// connections.push({
134182
// source: db.id,
135-
// target: otherDb.id,
136-
// color: blendColors(db.datatype), // Link color based on datatype
183+
// target: registry[nextIndex].id,
184+
// color: color,
137185
// visible: true,
138-
// }));
186+
// });
187+
// return connections;
188+
189+
// use original website logic
190+
const coloridx = index;
191+
const i = colorlist[coloridx].index; // Get shuffled node index
192+
const node = registry[i]; // Get actual node
193+
194+
// Determine number of connections (proportional to dataset size)
195+
const conn = 1 + Math.round(rngfun() * Math.max(1, node.datasets / 20));
196+
// const numConnections = 4;
197+
const connections: {
198+
source: string;
199+
target: string;
200+
color: string;
201+
visible: boolean;
202+
}[] = [];
203+
204+
// for (let j = -conn; j <= conn; j++) {
205+
// if (j === 0) continue; // Skip linking to itself
206+
// if (coloridx + j >= nodenum) break; // Prevent out-of-bounds errors
207+
208+
// const targetNode = registry[randnode[Math.max(0, coloridx + j)]]; // Pick a nearby node from shuffled list
209+
210+
// connections.push({
211+
// source: node.id,
212+
// target: targetNode.id,
213+
// color: blendColors(node.datatype), // Match node's color
214+
// visible: true, // Make links visible
215+
// });
216+
// }
217+
218+
for (let j = 1; j <= conn; j++) {
219+
if (index + j >= registry.length) break; // Prevent out-of-bounds errors
220+
221+
const targetIdx = colorlist[index + j].index; // Get next closest in brightness
222+
const targetNode = registry[targetIdx];
223+
224+
connections.push({
225+
source: node.id,
226+
target: targetNode.id,
227+
color: blendColors(node.datatype), // Keep consistent coloring
228+
visible: true, // Make links visible
229+
});
230+
}
231+
232+
return connections;
139233
}),
140234
};
141235

@@ -144,7 +238,7 @@ const NeuroJsonGraph: React.FC<{
144238
.graphData(graphData)
145239
.nodeRelSize(2)
146240
.nodeColor((node) => (node as NodeObject).color)
147-
.linkWidth(2)
241+
.linkWidth(0.5)
148242
.backgroundColor("rgba(0,0,0,0)")
149243
.nodeLabel("name")
150244
.onNodeHover((node) => {
@@ -201,7 +295,7 @@ const NeuroJsonGraph: React.FC<{
201295
// Add label as CSS2DObject
202296
const label = new CSS2DObject(document.createElement("div"));
203297
label.element.textContent = castNode.dbname || "Unnamed";
204-
label.element.style.color = Colors.primary.main;
298+
label.element.style.color = Colors.white;
205299
label.element.style.fontSize = "12px";
206300
label.element.style.pointerEvents = "none";
207301
label.position.set(0, 10, 0);

0 commit comments

Comments
 (0)