A modern, interactive SVG graph visualization library with advanced theming, physics simulation, and mobile-first design. Create beautiful, customizable network diagrams with dynamic styling and responsive controls.
This project was an exercise in "vibe coding" while implementing best practices. For production applications, we strongly recommend using these mature, battle-tested alternatives:
This library serves as an educational example of clean TypeScript architecture, comprehensive testing, and modern development practices. Feel free to explore the code for learning purposes!
npm install svg-graph-network
import GraphNetwork from 'svg-graph-network';
const graph = new GraphNetwork('container-id', {
data: {
nodes: [
{ id: "1", name: "Alice", type: "person", shape: "circle", size: 25 },
{ id: "2", name: "Bob", type: "person", shape: "rectangle", size: 30 },
{ id: "3", name: "Carol", type: "organization", shape: "square", size: 20 }
],
links: [
{ source: "1", target: "2", label: "friends", weight: 2, line_type: "solid" },
{ source: "2", target: "3", label: "works at", weight: 3, line_type: "dashed" }
]
},
config: {
theme: 'dark',
showControls: true,
showLegend: true,
showGrid: true
}
});
interface GraphNetworkOptions {
data: {
nodes: NodeData[];
links: LinkData[];
};
config?: {
// Physics Configuration
damping?: number; // Velocity damping (0.35-1.0, default: 0.95)
repulsionStrength?: number; // Node repulsion force (default: 6500)
attractionStrength?: number; // Link attraction force (default: 0.001)
groupingStrength?: number; // Type-based grouping force (default: 0.001)
// Interaction Configuration
zoomSensitivity?: number; // Mouse wheel sensitivity (default: 1.01)
filterDepth?: number; // Connection depth for filtering (default: 1)
// UI Configuration
showControls?: boolean; // Show zoom/control buttons (default: true)
showLegend?: boolean; // Show node type legend (default: true)
showTitle?: boolean; // Show graph title (default: true)
showBreadcrumbs?: boolean; // Show navigation breadcrumbs (default: true)
// Theming Configuration
theme?: 'dark' | 'light'; // Visual theme (default: 'dark')
title?: string; // Graph title text
showGrid?: boolean; // Show background grid (default: true)
};
}
interface NodeData {
id: string; // Unique identifier
name: string; // Display name
type?: string; // Type for styling/grouping (fully configurable)
shape?: 'circle' | 'rectangle' | 'square' | 'triangle';
size?: number; // Size in pixels
[key: string]: any; // Custom properties
}
interface LinkData {
source: string; // Source node ID
target: string; // Target node ID
label?: string; // Display label
weight?: number; // Visual weight/thickness
line_type?: 'solid' | 'dashed' | 'dotted';
color?: string; // Custom color
[key: string]: any; // Custom properties
}
// Data Management
graph.setData(graphData); // Replace all data
graph.addNode(nodeData); // Add single node
graph.removeNode(nodeId); // Remove node and connected links
graph.addEdge(linkData); // Add single link
graph.removeEdge(linkId); // Remove specific link
// View Control
graph.resetViewAndLayout(); // Reset zoom and restart physics
graph.fitToView(); // Fit graph to container bounds
graph.zoomIn(); // Programmatic zoom in
graph.zoomOut(); // Programmatic zoom out
// Filtering
graph.filterByNode(nodeId, depth); // Show only connected nodes
graph.resetFilter(); // Show all nodes
// Theming
graph.setTheme('light' | 'dark'); // Change theme
graph.toggleTheme(); // Switch between themes
graph.configureGrid(gridConfig); // Customize background grid
// Cleanup
graph.destroy(); // Clean up resources
// Configure custom themes
graph.setTheme({
name: 'custom',
colors: {
background: '#1a1a2e',
foreground: '#e94560',
primary: '#0f3460',
secondary: '#16213e'
},
nodeStyles: {
// Dynamic node type styling - no hardcoded types!
'user': { fill: '#4CAF50', stroke: '#2E7D32' },
'admin': { fill: '#FF9800', stroke: '#F57C00' },
'system': { fill: '#2196F3', stroke: '#1976D2' }
},
canvas: {
showGrid: true,
gridColor: 'rgba(233, 69, 96, 0.1)',
gridSize: 40
}
});
// Listen for events
graph.on('nodeDoubleClick', (data) => {
console.log('Node double-clicked:', data.node);
});
graph.on('themeChanged', (data) => {
console.log('Theme changed to:', data.theme);
});
graph.on('filtered', (data) => {
console.log(`Showing ${data.visibleNodes.length} nodes`);
});
// Available events
'nodeMouseDown' | 'nodeDoubleClick' | 'filtered' | 'filterReset' |
'themeChanged' | 'zoom' | 'resize' | 'reset' | 'nodeAdded' |
'nodeRemoved' | 'fitted' | 'destroyed'
Full touch gesture support with mobile-optimized UI:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=2.0, user-scalable=yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
The library uses CSS custom properties for comprehensive theming:
:root {
/* Colors */
--graph-bg-primary: #1a1a1a;
--graph-text-primary: #f0f0f0;
--graph-border-color: rgba(255, 255, 255, 0.1);
/* Grid */
--graph-grid-color: rgba(255, 165, 0, 0.1);
--graph-grid-size: 30px;
/* Controls */
--graph-control-bg: rgba(42, 42, 42, 0.9);
--graph-control-border: 1px solid #444;
}
[data-theme="light"] {
--graph-bg-primary: #fafafa;
--graph-text-primary: #1a1a1a;
--graph-grid-color: rgba(0, 100, 200, 0.1);
}
Built with a clean, modular architecture featuring focused components:
See Architecture Documentation for detailed technical information.
npm install # Install dependencies
npm run dev # Start development server (localhost:8080)
npm run build # Build for production
npm run test # Run test suite
npm run lint # Check code quality
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)MIT © Contributors
An educational example of clean TypeScript architecture and modern development practices.