The D3 force-directed graph visualization was experiencing severe performance issues with large changesets:
- Nodes spreading infinitely far apart and moving off-screen
- Extremely slow rendering and interaction
- High CPU usage
- Poor user experience with 100+ function changes
- Unbounded simulation - No constraints on node positions
- O(n²) link creation - Creating all-to-all links within file groups
- Fixed force parameters - Same settings for all graph sizes
- No alpha decay optimization - Simulation running indefinitely
- Detect large graphs (>50 nodes)
- Reduce charge strength from -300 to -100 for large graphs
- Reduce link distance from 100 to 50 for large graphs
- Reduce collision radius from 30 to 20 for large graphs
- Small groups (≤10 nodes): Full mesh connectivity (O(n²))
- Large groups (>10 nodes): Chain connectivity (O(n))
- Result: 98% reduction in links for 100-node files
- Constrain nodes to viewport with 50px padding
- Prevents nodes from drifting off-screen
- Maintains visibility of all nodes
- Added weak X/Y centering forces (strength: 0.05)
- Prevents excessive spreading
- Keeps graph compact and viewable
- Faster alpha decay for large graphs (0.05 vs 0.0228)
- Distance limiting for charge forces (200px for large graphs)
- Increased velocity decay (0.4)
- Stronger collision detection (0.7)
- 50 nodes: Slow, nodes spread out
- 100 nodes: Very slow, nodes off-screen
- 200+ nodes: Unusable
- 50 nodes: Fast, compact layout
- 100 nodes: Good performance, stays on-screen
- 200+ nodes: Usable, settles quickly
- Before: 4,950 links
- After: 99 links
- Improvement: 98% reduction
nextjs-frontend/src/components/graph/FunctionGraphViewer.tsxnextjs-frontend/src/components/graph/FunctionGraph.tsxstatic/app.js
To test the improvements:
- Load a comparison with 50+ function changes
- Verify nodes stay within viewport
- Check that simulation settles within 3-5 seconds
- Confirm smooth interaction (zoom, pan, drag)
- Monitor CPU usage (should drop after settling)
The large graph threshold can be adjusted:
const isLargeGraph = nodeCount > 50; // Change this value as neededFor even larger datasets (500+ nodes), consider:
- Progressive rendering
- WebGL-based rendering
- Automatic clustering
- Level-of-detail rendering
See docs/graph-performance-optimizations.md for detailed technical documentation.