Skip to main content

Graph Renderer Component Creation

· 5 min read

Execution Plan

Establish a modular Graph Renderer component system by refactoring from a single 3200+ line file into a well-organized architecture with focused components, hooks, and utilities.

Planned Work

  1. Component structure and hierarchy design
  2. Hook architecture implementation
  3. Utility architecture implementation
  4. Data flow design
  5. File structure organization

Execution Results / Attempts

✅ Component Created (2025-11-08 to 2025-11-17)

Work Period: November 8, 2025 to November 17, 2025

Commits: 10 commits related to graph component creation and refactoring

The Graph component system has been successfully created and refactored from a single 3200+ line file into a modular architecture with focused components, hooks, and utilities.

Key Commits:

  • a64d629e (2025-11-08): Updating authors and adding graph component plus stats structures and algos
  • 7333d884 (2025-11-08): Making graph component reactive
  • d2e8bf6d (2025-11-08): Adding menu bar to graph component
  • 92e82a04 (2025-11-08): Added ability to have anchor links to specific nodes in specific graphs
  • f57ee652 (2025-11-10): Adding integ and e2e tests for graph component
  • b5c58a8a (2025-11-10): Checkpointing graph renderer
  • cca8ae25 (2025-11-12): Big blog structure overhaul + finalization of graph component
  • e657ebde (2025-11-12): Revamp to readmes plus fix for graph
  • 7634d68b (2025-11-16): Revamping graph component, modularizing it, etc. Also added storybook tab to document components
  • 6ec4aaac (2025-11-17): Revamp component setup, story book stories, graph render on mobile, etc

Component Structure

┌─────────────────────────────────────────────────────────┐
│ GraphRenderer │
│ (BrowserOnly wrapper - handles SSR prevention) │
└──────────────────┬──────────────────────────────────────┘


┌──────────────────────┐
│ GraphRendererImpl │
│ (Main Component) │
└──────────┬───────────┘

┌──────────┴──────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ GraphCanvas │ │GraphInfoPanel│
│ (ForceGraph) │ │ (Side Bar) │
└──────────────┘ └──────────────┘


┌──────────────┐
│ GraphMenuBar │
│ (Controls) │
└──────────────┘

Component Details

GraphRenderer

  • Purpose: Browser-only wrapper to prevent SSR issues
  • Location: GraphRenderer.tsx
  • Responsibilities:
    • Dynamic import of browser-only dependencies
    • Loading state management
    • Error handling

GraphRendererImpl

  • Purpose: Main component that composes all sub-components
  • Location: GraphRenderer.tsx (to be refactored)
  • Responsibilities:
    • Component composition
    • State coordination
    • Event handling orchestration

GraphCanvas

  • Purpose: ForceGraph2D wrapper
  • Location: GraphCanvas.tsx
  • Props: All ForceGraph2D configuration
  • Responsibilities:
    • Canvas rendering setup
    • Graph visualization
    • Event propagation

GraphInfoPanel

  • Purpose: Side panel for node/edge information
  • Location: GraphInfoPanel.tsx
  • Size: ~400 lines (extracted from main file)
  • Responsibilities:
    • Display node information
    • Display edge information
    • Show connections (ingress/egress)
    • External links
    • Documentation links

GraphMenuBar

  • Purpose: Control buttons
  • Location: GraphMenuBar.tsx
  • Size: ~100 lines
  • Responsibilities:
    • Center graph
    • Expand/collapse all
    • Toggle panel visibility

Hook Architecture

useGraphState

  • Purpose: Centralized state management
  • Location: useGraphState.ts
  • Returns: { state, actions }
  • State Properties:
    • expandedNodes: Set<string>
    • selectedNode: any
    • selectedEdge: any
    • highlightedNodeId: string | null
    • highlightedEdgeId: string | null
    • paneVisible: boolean
    • contextMenu: {...} | null
    • rightClickMenu: {...} | null
    • nodePositions: Map<string, {...}>
    • isDarkMode: boolean

useGraphData

  • Purpose: Data transformation
  • Location: useGraphData.ts
  • Returns: { graphData, flattenNodes }
  • Features:
    • Hierarchical node flattening
    • Expansion-based filtering
    • Link generation

useGraphInteractions

  • Purpose: Event handler management
  • Location: useGraphInteractions.ts
  • Returns: Object with all handlers
  • Handlers:
    • Node interactions (click, right-click, drag)
    • Edge interactions (click, right-click)
    • Zoom handling
    • Clipboard operations

Utility Architecture

GraphDataUtils.ts

Purpose: Tree traversal and data operations

  • findPathToNode - Find path to node in tree
  • findNodeById - Find node by ID
  • getAllNodesWithChildren - Get all parent nodes
  • cleanNodeForSelection - Clean node object
  • cleanEdgeForSelection - Clean edge object

GraphNodeUtils.ts

Purpose: Node properties and styling

  • getNodeRadius - Calculate radius (12 for parents, 8 for leaves)
  • getNodeColor - Get color with fallback
  • getNodeLabel - Extract label (title > name > id)
  • isValidNodeCoordinates - Validate coordinates
  • getNodeStatusIndicator - Get status symbol (▶/▼/🌿)

GraphRenderingUtils.ts

Purpose: Rendering calculations

  • getEdgeCoordinates - Calculate edge start/end points
  • calculateAvailableTextWidth - Text width in circular node
  • calculateEmojiAreaCenterY - Emoji area position
  • calculateLinePositions - Text line Y positions
  • calculateOptimalTitleFontSize - Title font sizing
  • calculateIndicatorFontSize - Indicator font sizing

GraphTextUtils.ts

Purpose: Text processing

  • breakLongWord - Break words at natural boundaries
  • wrapTextIntoLines - Wrap text into 3 lines
  • truncateLine - Truncate with ellipsis
  • calculateOptimalFontSize - Optimal font size calculation
  • applyZoomScaling - Zoom-based font scaling

Data Flow

User Interaction


useGraphInteractions (handlers)


useGraphState (state updates)


useGraphData (data transformation)


GraphCanvas (rendering)

├──► GraphInfoPanel (display info)
└──► GraphMenuBar (controls)

Storybook Documentation

All components are documented in Storybook with:

  • Interactive examples
  • Prop documentation
  • Usage examples
  • Architecture overview

Running Storybook

npm run storybook
# or
yarn storybook

Available Stories

  1. Graph/GraphMenuBar

    • Default (light mode)
    • Dark mode
    • Pane hidden
    • Custom height
  2. Graph/GraphInfoPanel

    • Empty state
    • Node selected
    • Edge selected
    • Dark mode
    • Differentiating edge
  3. Graph/Architecture

    • Architecture overview
    • Component examples
    • Usage patterns

File Size Reduction

Before Refactoring

  • GraphRenderer.tsx: ~3,219 lines

After Refactoring

  • GraphRenderer.tsx: ~800-1000 lines (estimated after full refactor)
  • GraphMenuBar.tsx: ~100 lines
  • GraphInfoPanel.tsx: ~400 lines
  • GraphCanvas.tsx: ~150 lines
  • useGraphState.ts: ~120 lines
  • useGraphData.ts: ~100 lines
  • useGraphInteractions.ts: ~150 lines
  • Utility files: ~1,200 lines (split across 4 files)

Total: Similar line count, but much better organized

Benefits

  1. Maintainability: Smaller files are easier to understand
  2. Testability: Components can be tested independently
  3. Reusability: Components can be used in different contexts
  4. Documentation: Storybook provides interactive docs
  5. Performance: Better code splitting opportunities
  6. Collaboration: Multiple developers can work on different components

Migration Path

  1. ✅ Created utility files (GraphDataUtils, GraphNodeUtils, etc.)
  2. ✅ Created hooks (useGraphState, useGraphData, useGraphInteractions)
  3. ✅ Created components (GraphMenuBar, GraphInfoPanel, GraphCanvas)
  4. ⏳ Refactor GraphRendererImpl to use new components
  5. ✅ Set up Storybook
  6. ✅ Create Storybook stories

Next Steps

  1. Complete GraphRendererImpl refactoring
  2. Add unit tests for components
  3. Add integration tests
  4. Performance profiling
  5. Additional Storybook stories for edge cases