Angular component for rendering hierarchical JSON data as interactive SVG tree diagrams with zoom/pan controls.
import { JsonVisualizerComponent } from './json-visualizer.component'
import { createDefaultConfig } from './providers/preset-configs'
@Component({
template: `
<app-json-visualizer
[data]="data"
[config]="config"
[width]="800"
[height]="600">
</app-json-visualizer>
`
})
export class ExampleComponent {
data = { root: { items: [{ name: 'item1', value: 123 }] } }
config = createDefaultConfig()
}
data: any
- JSON data to visualizeconfig: VisualizerConfig
- Configuration objectwidth: number = 800
- Component widthheight: number = 600
- Component height
interface VisualizerConfig {
nodeRenderers: NodeRenderer[]
dataTransformer: DataTransformer
layoutProvider: LayoutProvider
enableZooming?: boolean
theme?: ThemeConfig
layout?: LayoutConfig
onNodeClick?: (node: VisualizerNode, event: MouseEvent) => void
}
interface VisualizerNode {
id: string
name: string
value?: string | number
children?: VisualizerNode[]
type: 'root' | 'object' | 'array' | 'leaf'
level: number
x?: number
y?: number
originalData?: any
}
import {
API_VISUALIZER_CONFIG,
createDefaultConfig,
createDeviceConfig,
TENANT_DEVICE_CONFIG
} from './providers/preset-configs'
// Basic JSON visualization
const config = createDefaultConfig()
// IoT device hierarchies
const deviceConfig = createDeviceConfig()
// API endpoint trees
const apiConfig = API_VISUALIZER_CONFIG
// Multi-tenant device management
const tenantConfig = TENANT_DEVICE_CONFIG
class CustomNodeRenderer implements NodeRenderer {
canHandle = (node: VisualizerNode): boolean => {
return node.originalData?.type === 'custom'
}
renderContent = (node: VisualizerNode, container: SVGGElement): void => {
// Custom SVG rendering logic
}
getNodeStyle = (node: VisualizerNode): NodeStyle => ({
fill: '#ffffff',
stroke: '#000000',
width: 160,
height: 40
})
}
const config: VisualizerConfig = {
nodeRenderers: [new CustomNodeRenderer(), new DefaultNodeRenderer()],
// ... other config
}
const config = {
layout: {
nodeSpacing: { x: 220, y: 80 },
padding: { top: 20, right: 20, bottom: 20, left: 20 }
},
enableZooming: true,
maxDepth: 10
}
import { DARK_THEME, LIGHT_THEME } from './providers/preset-configs'
const config = {
theme: DARK_THEME,
// or custom theme
theme: {
node: { fill: '#ffffff', stroke: '#000000' },
link: { stroke: '#cccccc', strokeWidth: 1 }
}
}
const config = {
onNodeClick: (node, event) => {
console.log('Clicked:', node.name)
},
onNodeHover: (node, event) => {
// Show tooltip
}
}
Nodes can be individually dragged to reposition them within the canvas:
- Click and drag any node to move it freely
- Visual feedback with shadows and opacity changes during drag
- Automatic collision detection prevents overlapping
- Hitboxes: Each node has a collision boundary that prevents overlap
- Visual Feedback: Conflicting nodes are highlighted with red borders during drag
- Smart Positioning: Automatically finds the closest valid position when collision occurs
- Snap to Grid: Positions are snapped to a 10px grid for clean alignment
- Pan and Zoom: Canvas-level pan and zoom (mouse wheel)
- Individual Node Dragging: Move nodes independently without affecting canvas
- Minimum Spacing: Configurable margin between nodes (default: 15px)
@Component({
template: `
<app-json-visualizer
[data]="complexData"
[config]="enhancedConfig"
[width]="1000"
[height]="800">
</app-json-visualizer>
`
})
export class InteractiveExampleComponent {
complexData = {
root: {
devices: [
{ id: 'device1', name: 'Sensor A', type: 'temperature', value: 25.3 },
{ id: 'device2', name: 'Sensor B', type: 'humidity', value: 65.8 }
]
}
}
enhancedConfig = createDefaultConfig()
// Dragging and collision detection are enabled by default
}
- Chrome 80+, Firefox 75+, Safari 13+, Edge 80+
- SVG support required