Spaces:
Sleeping
Sleeping
bigwolfe
commited on
Commit
·
044ec7f
1
Parent(s):
40fe67e
graph working
Browse files- frontend/package-lock.json +15 -0
- frontend/package.json +1 -0
- frontend/src/components/GraphView.tsx +32 -3
frontend/package-lock.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
| 21 |
"@radix-ui/react-tooltip": "^1.2.8",
|
| 22 |
"@tailwindcss/typography": "^0.5.19",
|
| 23 |
"cmdk": "^1.1.1",
|
|
|
|
| 24 |
"react": "^19.2.0",
|
| 25 |
"react-dom": "^19.2.0",
|
| 26 |
"react-force-graph-2d": "^1.29.0",
|
|
@@ -4629,6 +4630,20 @@
|
|
| 4629 |
"node": ">=12"
|
| 4630 |
}
|
| 4631 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4632 |
"node_modules/d3-force-3d": {
|
| 4633 |
"version": "3.0.6",
|
| 4634 |
"resolved": "https://registry.npmjs.org/d3-force-3d/-/d3-force-3d-3.0.6.tgz",
|
|
|
|
| 21 |
"@radix-ui/react-tooltip": "^1.2.8",
|
| 22 |
"@tailwindcss/typography": "^0.5.19",
|
| 23 |
"cmdk": "^1.1.1",
|
| 24 |
+
"d3-force": "^3.0.0",
|
| 25 |
"react": "^19.2.0",
|
| 26 |
"react-dom": "^19.2.0",
|
| 27 |
"react-force-graph-2d": "^1.29.0",
|
|
|
|
| 4630 |
"node": ">=12"
|
| 4631 |
}
|
| 4632 |
},
|
| 4633 |
+
"node_modules/d3-force": {
|
| 4634 |
+
"version": "3.0.0",
|
| 4635 |
+
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
|
| 4636 |
+
"integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
|
| 4637 |
+
"license": "ISC",
|
| 4638 |
+
"dependencies": {
|
| 4639 |
+
"d3-dispatch": "1 - 3",
|
| 4640 |
+
"d3-quadtree": "1 - 3",
|
| 4641 |
+
"d3-timer": "1 - 3"
|
| 4642 |
+
},
|
| 4643 |
+
"engines": {
|
| 4644 |
+
"node": ">=12"
|
| 4645 |
+
}
|
| 4646 |
+
},
|
| 4647 |
"node_modules/d3-force-3d": {
|
| 4648 |
"version": "3.0.6",
|
| 4649 |
"resolved": "https://registry.npmjs.org/d3-force-3d/-/d3-force-3d-3.0.6.tgz",
|
frontend/package.json
CHANGED
|
@@ -23,6 +23,7 @@
|
|
| 23 |
"@radix-ui/react-tooltip": "^1.2.8",
|
| 24 |
"@tailwindcss/typography": "^0.5.19",
|
| 25 |
"cmdk": "^1.1.1",
|
|
|
|
| 26 |
"react": "^19.2.0",
|
| 27 |
"react-dom": "^19.2.0",
|
| 28 |
"react-force-graph-2d": "^1.29.0",
|
|
|
|
| 23 |
"@radix-ui/react-tooltip": "^1.2.8",
|
| 24 |
"@tailwindcss/typography": "^0.5.19",
|
| 25 |
"cmdk": "^1.1.1",
|
| 26 |
+
"d3-force": "^3.0.0",
|
| 27 |
"react": "^19.2.0",
|
| 28 |
"react-dom": "^19.2.0",
|
| 29 |
"react-force-graph-2d": "^1.29.0",
|
frontend/src/components/GraphView.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
import { useEffect, useRef, useState, useMemo } from 'react';
|
| 2 |
import ForceGraph2D, { type ForceGraphMethods } from 'react-force-graph-2d';
|
|
|
|
| 3 |
import type { GraphData, GraphNode } from '@/types/graph';
|
| 4 |
import { getGraphData } from '@/services/api';
|
| 5 |
import { Loader2, AlertCircle } from 'lucide-react';
|
|
@@ -72,6 +73,33 @@ export function GraphView({ onSelectNote }: GraphViewProps) {
|
|
| 72 |
fetchData();
|
| 73 |
}, []);
|
| 74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
// Simple hash for categorical colors
|
| 76 |
const getGroupColor = (group: string) => {
|
| 77 |
let hash = 0;
|
|
@@ -124,15 +152,16 @@ export function GraphView({ onSelectNote }: GraphViewProps) {
|
|
| 124 |
nodeLabel="label"
|
| 125 |
nodeColor={(node: any) => node.group && node.group !== 'root' ? getGroupColor(node.group) : defaultNodeColor}
|
| 126 |
linkColor={() => linkColor}
|
|
|
|
| 127 |
backgroundColor={backgroundColor}
|
| 128 |
onNodeClick={handleNodeClick}
|
| 129 |
nodeRelSize={6}
|
| 130 |
linkDirectionalParticles={2}
|
| 131 |
-
|
|
|
|
| 132 |
width={window.innerWidth * 0.75} // Approximate width, needs resize observer for true responsiveness
|
|
|
|
| 133 |
height={window.innerHeight - 60} // Approximate height minus header
|
| 134 |
-
// Basic forces to keep structure
|
| 135 |
-
d3Force={('charge', -120)}
|
| 136 |
/>
|
| 137 |
</div>
|
| 138 |
);
|
|
|
|
| 1 |
import { useEffect, useRef, useState, useMemo } from 'react';
|
| 2 |
import ForceGraph2D, { type ForceGraphMethods } from 'react-force-graph-2d';
|
| 3 |
+
import { forceRadial } from 'd3-force';
|
| 4 |
import type { GraphData, GraphNode } from '@/types/graph';
|
| 5 |
import { getGraphData } from '@/services/api';
|
| 6 |
import { Loader2, AlertCircle } from 'lucide-react';
|
|
|
|
| 73 |
fetchData();
|
| 74 |
}, []);
|
| 75 |
|
| 76 |
+
// Configure forces when data is loaded
|
| 77 |
+
useEffect(() => {
|
| 78 |
+
if (!isLoading && graphRef.current) {
|
| 79 |
+
// Configure forces
|
| 80 |
+
// Increase repulsion to spread out clusters
|
| 81 |
+
graphRef.current.d3Force('charge')?.strength(-400);
|
| 82 |
+
// Adjust link distance
|
| 83 |
+
graphRef.current.d3Force('link')?.distance(60);
|
| 84 |
+
|
| 85 |
+
// Add "valence shell" for orphans (nodes with val=1)
|
| 86 |
+
// Pulls them to a ring at radius 300
|
| 87 |
+
graphRef.current.d3Force(
|
| 88 |
+
'valence',
|
| 89 |
+
forceRadial(300, 0, 0).strength((node: any) => node.val === 1 ? 0.1 : 0)
|
| 90 |
+
);
|
| 91 |
+
|
| 92 |
+
// Add collision detection to prevent overlap
|
| 93 |
+
// @ts-ignore - d3 types might not be fully exposed
|
| 94 |
+
if (!graphRef.current.d3Force('collide')) {
|
| 95 |
+
// dynamic import of d3 would be needed to create new forces if not default
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
// Warmup the engine
|
| 99 |
+
graphRef.current.d3ReheatSimulation();
|
| 100 |
+
}
|
| 101 |
+
}, [data, isLoading]);
|
| 102 |
+
|
| 103 |
// Simple hash for categorical colors
|
| 104 |
const getGroupColor = (group: string) => {
|
| 105 |
let hash = 0;
|
|
|
|
| 152 |
nodeLabel="label"
|
| 153 |
nodeColor={(node: any) => node.group && node.group !== 'root' ? getGroupColor(node.group) : defaultNodeColor}
|
| 154 |
linkColor={() => linkColor}
|
| 155 |
+
linkWidth={3} //width of links between nodes
|
| 156 |
backgroundColor={backgroundColor}
|
| 157 |
onNodeClick={handleNodeClick}
|
| 158 |
nodeRelSize={6}
|
| 159 |
linkDirectionalParticles={2}
|
| 160 |
+
linkDirectionalParticleWidth={7}
|
| 161 |
+
linkDirectionalParticleSpeed={0.0025}
|
| 162 |
width={window.innerWidth * 0.75} // Approximate width, needs resize observer for true responsiveness
|
| 163 |
+
|
| 164 |
height={window.innerHeight - 60} // Approximate height minus header
|
|
|
|
|
|
|
| 165 |
/>
|
| 166 |
</div>
|
| 167 |
);
|