Node Graph
scificn/node-graphFreeComponent
SVG node-edge graph with responsive width, directed arrowheads, animated marching-ants edges, and per-node status colors.
Live preview
live · rendered by the registry
Rendered by scificn on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://www.scificn.dev/r/node-graph.jsonSource
1'use client'23import * as React from 'react'4import { cn } from '@/lib/utils'56export type NodeGraphVariant = 'DEFAULT' | 'ACTIVE' | 'WARNING' | 'CRITICAL'7export type NodeStatus = 'ACTIVE' | 'OFFLINE' | 'WARNING' | 'CRITICAL' | 'NEUTRAL'89export interface NodeGraphNode {10 id: string11 label: string12 x: number // 0–100 coordinate space13 y: number14 status?: NodeStatus15 sublabel?: string16}1718export interface NodeGraphEdge {19 from: string20 to: string21 label?: string22 animated?: boolean23}2425export interface NodeGraphProps extends React.HTMLAttributes<HTMLDivElement> {26 nodes: NodeGraphNode[]27 edges: NodeGraphEdge[]28 variant?: NodeGraphVariant29 title?: string30 height?: number31 directed?: boolean32}3334const VARIANT_COLORS: Record<NodeGraphVariant, string> = {35 DEFAULT: 'var(--text-secondary)',36 ACTIVE: 'var(--color-green)',37 WARNING: 'var(--color-amber)',38 CRITICAL: 'var(--color-red)',39}4041const STATUS_COLOR: Record<NodeStatus, string> = {42 ACTIVE: 'var(--color-green)',43 OFFLINE: 'var(--border)',44 WARNING: 'var(--color-amber)',45 CRITICAL: 'var(--color-red)',46 NEUTRAL: 'var(--text-muted)',47}4849const NODE_W = 10050const NODE_H = 365152const NodeGraph = React.forwardRef<HTMLDivElement, NodeGraphProps>(53 (54 {55 className,56 nodes,57 edges,58 variant = 'ACTIVE',59 title,60 height = 320,61 directed = false,62 style,63 ...props64 },65 ref66 ) => {67 const containerRef = React.useRef<HTMLDivElement>(null)68 const [svgW, setSvgW] = React.useState(600)69 const [hovered, setHovered] = React.useState<string | null>(null)7071 React.useEffect(() => {72 if (!containerRef.current) return73 const ro = new ResizeObserver(entries => {74 setSvgW(entries[0].contentRect.width)75 })76 ro.observe(containerRef.current)77 return () => ro.disconnect()78 }, [])7980 const color = VARIANT_COLORS[variant]81 const markerId = `arrow-${variant}`8283 function nodePx(node: NodeGraphNode) {84 return (node.x / 100) * svgW85 }8687 function nodePy(node: NodeGraphNode) {88 return (node.y / 100) * height89 }9091 function edgeEndpoints(fromNode: NodeGraphNode, toNode: NodeGraphNode) {92 const fx = nodePx(fromNode)93 const fy = nodePy(fromNode)94 const tx = nodePx(toNode)95 const ty = nodePy(toNode)96 const dx = tx - fx97 const dy = ty - fy98 const dist = Math.sqrt(dx * dx + dy * dy)99 if (dist < 1) return { x1: fx, y1: fy, x2: tx, y2: ty }100101// … truncated
More from scificn
All 33 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Alertalert | scificn | Components | Free | 1 dep | |
| Badgebadge | scificn | Components | Free | 1 dep | |
| Bar Chartbar-chart | scificn | Components | Free | no deps | |
| Breadcrumbbreadcrumb | scificn | Components | Free | no deps | |
| Buttonbutton | scificn | Components | Free | 2 deps | |
| Cardcard | scificn | Components | Free | no deps | |
| Checkboxcheckbox | scificn | Components | Free | 1 dep | |
| Dialogdialog | scificn | Components | Free | 1 dep |
