@x025me/link-analysis
v1.0.5
Published
A powerful React component for visualizing link analysis graphs with Neo4j-style styling
Downloads
16
Maintainers
Readme
@x025me/link-analysis
A beautiful, interactive React component for visualizing network graphs and relationships. Perfect for displaying connections between people, organizations, phone numbers, or any linked data.
🚀 Quick Start
Step 1: Install
npm install @x025me/link-analysis react react-domStep 2: Add Styles
In your main entry file (usually main.tsx or index.tsx):
import 'antd/dist/reset.css'Step 3: Use the Component
import { GraphVisualization } from '@x025me/link-analysis'
function App() {
const graphData = {
nodes: [
{ id: '1', label: 'Alice', type: 'person' },
{ id: '2', label: 'Bob', type: 'person' },
{ id: '3', label: 'Company Inc', type: 'organization' },
],
edges: [
{ id: 'e1', source: '1', target: '2', label: 'knows' },
{ id: 'e2', source: '1', target: '3', label: 'works at' },
],
}
return (
<div style={{ width: '100%', height: '600px' }}>
<GraphVisualization data={graphData} />
</div>
)
}That's it! You now have an interactive graph visualization.
📖 Common Use Cases
1. Displaying Social Networks
Show relationships between people:
import { GraphVisualization } from '@x025me/link-analysis'
const socialNetwork = {
nodes: [
{ id: 'alice', label: 'Alice', type: 'person' },
{ id: 'bob', label: 'Bob', type: 'person' },
{ id: 'charlie', label: 'Charlie', type: 'person' },
],
edges: [
{ id: 'e1', source: 'alice', target: 'bob', label: 'friends' },
{ id: 'e2', source: 'bob', target: 'charlie', label: 'friends' },
],
}
function SocialNetwork() {
return (
<div style={{ width: '100%', height: '500px' }}>
<GraphVisualization data={socialNetwork} />
</div>
)
}2. Phone Call Analysis
Visualize phone call records with phone numbers as nodes:
const callData = {
nodes: [
{
id: 'phone-1234567890',
label: '+1 (234) 567-8900',
type: 'phone',
metadata: { primaryPhone: '1234567890' }
},
{
id: 'phone-0987654321',
label: '+1 (987) 654-3210',
type: 'phone',
metadata: { primaryPhone: '0987654321' }
},
],
edges: [
{
id: 'call1',
source: 'phone-1234567890',
target: 'phone-0987654321',
label: 'Called (5 times)',
source_detail: '1234567890',
target_detail: '0987654321'
},
],
}3. Organizational Charts
Show company hierarchy:
const orgChart = {
nodes: [
{ id: 'ceo', label: 'CEO', type: 'person' },
{ id: 'cto', label: 'CTO', type: 'person' },
{ id: 'cfo', label: 'CFO', type: 'person' },
{ id: 'eng', label: 'Engineering', type: 'organization' },
{ id: 'finance', label: 'Finance', type: 'organization' },
],
edges: [
{ id: 'e1', source: 'ceo', target: 'cto', label: 'manages' },
{ id: 'e2', source: 'ceo', target: 'cfo', label: 'manages' },
{ id: 'e3', source: 'cto', target: 'eng', label: 'leads' },
{ id: 'e4', source: 'cfo', target: 'finance', label: 'leads' },
],
}
function OrgChart() {
return (
<GraphVisualization
data={orgChart}
layout={{ name: 'breadthfirst', directed: true }}
/>
)
}4. Interactive Graph with Click Handlers
Respond to user interactions:
import { useState } from 'react'
import { GraphVisualization, GraphData } from '@x025me/link-analysis'
function InteractiveGraph() {
const [selectedNode, setSelectedNode] = useState<string | null>(null)
const [graphData, setGraphData] = useState<GraphData>({
nodes: [
{ id: '1', label: 'Node 1' },
{ id: '2', label: 'Node 2' },
],
edges: [
{ id: 'e1', source: '1', target: '2' },
],
})
return (
<div>
{selectedNode && (
<div>Selected: {selectedNode}</div>
)}
<div style={{ width: '100%', height: '600px' }}>
<GraphVisualization
data={graphData}
onNodeClick={(nodeId) => {
setSelectedNode(nodeId)
console.log('Node clicked:', nodeId)
}}
onEdgeClick={(edgeId) => {
console.log('Edge clicked:', edgeId)
}}
/>
</div>
</div>
)
}🎨 Customizing the Layout
Choose from different layout algorithms:
Force-Directed (Default)
Best for showing natural clusters and relationships:
<GraphVisualization
data={data}
layout={{
name: 'cose',
animate: true,
padding: 50,
nodeSpacing: 100,
edgeLength: 200,
}}
/>Circular Layout
Organizes nodes in a circle:
<GraphVisualization
data={data}
layout={{
name: 'circle',
animate: true,
padding: 50,
}}
/>Grid Layout
Arranges nodes in a grid:
<GraphVisualization
data={data}
layout={{
name: 'grid',
animate: true,
padding: 50,
}}
/>Hierarchical Layout
Shows top-to-bottom hierarchy:
<GraphVisualization
data={data}
layout={{
name: 'breadthfirst',
animate: true,
padding: 50,
directed: true,
}}
/>Neo4j-Style Layout
Physics-heavy layout similar to Neo4j Bloom:
<GraphVisualization
data={data}
layout={{
name: 'cose-bilkent',
animate: 'end',
idealEdgeLength: 120,
nodeRepulsion: 4500,
gravity: 0.25,
}}
/>🔍 Filtering Nodes
Include Specific Nodes
Show only certain nodes:
const [includeFilters, setIncludeFilters] = useState<string[]>(['1234567890', '0987654321'])
<GraphVisualization
data={data}
includeFilters={includeFilters}
onIncludeFiltersChange={setIncludeFilters}
/>Exclude Specific Nodes
Hide certain nodes:
const [excludeFilters, setExcludeFilters] = useState<string[]>(['unwanted-node-id'])
<GraphVisualization
data={data}
excludeFilters={excludeFilters}
onExcludeFiltersChange={setExcludeFilters}
/>🎯 Using the Command Center
The component includes a built-in command center with two tabs:
- Basic Tab: Search, zoom, and navigation controls
- Advanced Tab: Filters, layout selection, and data management
Users can interact with the graph using:
- Click: Select a node
- Ctrl/Cmd + Click: Multi-select nodes
- Drag: Pan the graph
- Scroll: Zoom in/out
- Hover: See node/edge details in tooltips
📊 Data Format
Basic Node Structure
{
id: 'unique-id', // Required: Unique identifier
label: 'Display Name', // Required: Text shown on node
type: 'person', // Optional: Node type (affects color/shape)
image: '/path/to/image', // Optional: Node image
metadata: { // Optional: Additional data
category: 'Research',
description: 'A person',
tags: ['important'],
primaryPhone: '1234567890',
},
data: { // Optional: Raw data
// Any additional fields
},
}Basic Edge Structure
{
id: 'unique-edge-id', // Required: Unique identifier
source: 'node-id-1', // Required: Source node ID
target: 'node-id-2', // Required: Target node ID
label: 'connects to', // Optional: Edge label
weight: 5, // Optional: Edge weight
source_detail: '1234567890', // Optional: Phone number or detail
target_detail: '0987654321', // Optional: Phone number or detail
}Complete Example
const completeData = {
nodes: [
{
id: 'person-1',
label: 'John Doe',
type: 'person',
image: '/images/john.jpg',
metadata: {
category: 'Employee',
description: 'Software Engineer',
tags: ['developer', 'senior'],
primaryPhone: '+1234567890',
},
},
{
id: 'org-1',
label: 'Tech Corp',
type: 'organization',
metadata: {
category: 'Company',
description: 'Technology company',
},
},
],
edges: [
{
id: 'edge-1',
source: 'person-1',
target: 'org-1',
label: 'works at',
weight: 1,
},
],
}🌓 Theming
Wrap your app with ThemeProvider for dark/light theme support:
import { ThemeProvider, GraphVisualization } from '@x025me/link-analysis'
function App() {
return (
<ThemeProvider>
<GraphVisualization data={data} />
</ThemeProvider>
)
}The component automatically adapts to light and dark themes.
🛠️ Working with Raw Data
If you have data in a different format, use the normalizeToGraphData utility:
import { normalizeToGraphData } from '@x025me/link-analysis'
// Your raw data (can be in various formats)
const rawData = {
people: [
{ id: 1, name: 'Alice', phone: '123-456-7890' },
{ id: 2, name: 'Bob', phone: '098-765-4321' },
],
connections: [
{ from: 1, to: 2, type: 'knows' },
],
}
// Normalize it
const graphData = normalizeToGraphData(rawData)
// Use it
<GraphVisualization data={graphData} />💡 Tips & Best Practices
1. Container Size
Always set a specific height for the container:
// ✅ Good
<div style={{ width: '100%', height: '600px' }}>
<GraphVisualization data={data} />
</div>
// ❌ Bad - no height specified
<div>
<GraphVisualization data={data} />
</div>2. Large Datasets
For graphs with many nodes (1000+), consider:
- Using simpler layouts (grid, circle)
- Filtering data before passing to component
- Using
includeFiltersto show only relevant nodes
3. Phone Number Formatting
The component automatically handles phone numbers. You can use:
+1234567890123-456-7890(123) 456-78901234567890
All formats are normalized automatically.
4. Node Types
Common node types with built-in styling:
person- Blue circleorganization- Green rounded rectanglephone- Hexagon shapewebsite- Golden diamondlocation- Coral octagon
❓ Troubleshooting
Graph not showing?
- Check container height: Make sure the parent div has a height set
- Check data format: Ensure
nodesandedgesarrays exist - Check node IDs: Source and target IDs in edges must match node IDs
Styles not working?
- Import Ant Design styles: Add
import 'antd/dist/reset.css' - Check CSS imports: Ensure styles are imported before the component
Nodes not connecting?
- Verify edge source/target: Must exactly match node IDs
- Check for typos: IDs are case-sensitive
- Use
normalizeToGraphData: If your data format is different
Performance issues?
- Reduce node count: Filter data before rendering
- Use simpler layouts: Grid or circle for large datasets
- Disable animations: Set
animate: falsein layout config
📚 API Reference
GraphVisualization Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| data | GraphData | required | Graph data with nodes and edges |
| layout | GraphLayoutOptions | cose | Layout configuration |
| style | CSSProperties | - | Custom container styles |
| onNodeClick | (id: string) => void | - | Called when node is clicked |
| onEdgeClick | (id: string) => void | - | Called when edge is clicked |
| includeFilters | string[] | [] | Show only these nodes |
| excludeFilters | string[] | [] | Hide these nodes |
| onIncludeFiltersChange | (values: string[]) => void | - | Update include filters |
| onExcludeFiltersChange | (values: string[]) => void | - | Update exclude filters |
GraphData Type
interface GraphData {
nodes: Node[]
edges: Edge[]
}Node Type
interface Node {
id: string
label: string
type?: string
image?: string
metadata?: NodeMetadata
data?: Record<string, any>
}Edge Type
interface Edge {
id: string
source: string
target: string
label?: string
weight?: number
source_detail?: string
target_detail?: string
data?: Record<string, any>
}🎓 Examples
Check out these common patterns:
Loading Data from API
import { useState, useEffect } from 'react'
import { GraphVisualization, GraphData, normalizeToGraphData } from '@x025me/link-analysis'
function ApiGraph() {
const [data, setData] = useState<GraphData>({ nodes: [], edges: [] })
const [loading, setLoading] = useState(true)
useEffect(() => {
fetch('/api/graph-data')
.then(res => res.json())
.then(raw => {
const normalized = normalizeToGraphData(raw)
setData(normalized)
setLoading(false)
})
}, [])
if (loading) return <div>Loading...</div>
return (
<div style={{ width: '100%', height: '600px' }}>
<GraphVisualization data={data} />
</div>
)
}Dynamic Updates
function DynamicGraph() {
const [data, setData] = useState<GraphData>({
nodes: [{ id: '1', label: 'Node 1' }],
edges: [],
})
const addNode = () => {
const newNode = {
id: `node-${Date.now()}`,
label: `Node ${data.nodes.length + 1}`,
}
setData(prev => ({
...prev,
nodes: [...prev.nodes, newNode],
}))
}
return (
<div>
<button onClick={addNode}>Add Node</button>
<div style={{ width: '100%', height: '600px' }}>
<GraphVisualization data={data} />
</div>
</div>
)
}📝 License
MIT
🤝 Support
Found a bug or have a question? Open an issue on GitHub.
Happy visualizing! 🎉
