Four features that turn a streaming Sankey diagram into a system monitoring tool: a generic details panel for click-to-inspect, proportional particle speed for flow rate visualization, threshold alerting for metric-based node highlighting, and topology diffingfor tracking infrastructure changes over time.
These features compose with the existingobservation hooks,serialization, andrealtime encodingsystems. The details panel is generic — it works with any chart type, not just network charts.
Details Panel
DetailsPanel is a selection-driven detail view that opens when a user clicks on a data point. It uses the observation system internally (useChartObserver withclick events), so it works insideLinkedCharts and composes with any chart that emits observations.
Place it inside a ChartContainer via thedetailsPanel prop. The panel receives the clicked datum through a render prop — you control what shows.
Microservice Architecture
JSX
import { ChartContainer, DetailsPanel, SankeyDiagram, LinkedCharts } from "semiotic" <LinkedCharts> <ChartContainer title="System Monitor" status="live" detailsPanel={ <DetailsPanel position="right" size={300} trigger="click"> {(datum, observation) => ( <div> <h3>{datum.id}</h3> <p>Throughput: {datum.value} req/s</p> {/* Embed sparklines, metrics, anything */} </div> )} </DetailsPanel> } > <SankeyDiagram edges={edges} onObservation={() => {}} chartId="system" /> </ChartContainer> </LinkedCharts>
Positions
| Position | Behavior |
|---|
"right" | Slides in from right edge (default). size controls width. |
"bottom" | Slides up from bottom edge. size controls height. |
"overlay" | Centered overlay with shadow. size controls max width. |
Props
| Prop | Type | Default | Description |
|---|
children | (datum, observation) => ReactNode | required | Render function for panel content |
position | "right" | "bottom" | "overlay" | "right" | Panel position |
size | number | 300 | Width (right) or height (bottom) |
trigger | "click" | "hover" | "click" | Observation type that triggers the panel |
chartId | string | all | Filter observations by chart ID |
dismissOnEmpty | boolean | true | Close panel when clicking empty space |
showClose | boolean | true | Show close button |
onToggle | (open: boolean) => void | — | Called when panel opens or closes |
JSX
// DetailsPanel works with any chart, not just network charts. // It consumes click observations via useChartObserver internally. import { DetailsPanel, ChartContainer, Scatterplot, LinkedCharts } from "semiotic" <LinkedCharts> <ChartContainer title="My Dashboard" detailsPanel={ <DetailsPanel position="right" // "right" | "bottom" | "overlay" size={300} // width (right) or height (bottom) trigger="click" // "click" | "hover" chartId="scatter" // filter to specific chart dismissOnEmpty // clicking empty space closes panel showClose // show close button (default true) onToggle={(open) => console.log("Panel", open ? "opened" : "closed")} > {(datum, observation) => ( <div> <h3>{datum.name}</h3> <p>Clicked at ({observation.x}, {observation.y})</p> </div> )} </DetailsPanel> } > <Scatterplot data={data} xAccessor="x" yAccessor="y" onObservation={() => {}} chartId="scatter" /> </ChartContainer> </LinkedCharts>
Edge Flow Rate
Set proportionalSpeed: true on particleStyleto make particles travel faster on high-throughput edges. Speed scales from 0.3× (lowest-value edge) to 2× (highest-value edge), giving an immediate visual sense of where traffic is flowing most.
JSX
<StreamNetworkFrame ref={chartRef} chartType="sankey" showParticles particleStyle={{ proportionalSpeed: true, // faster particles on high-throughput edges spawnRate: 0.08, radius: 2.5, }} // ... />
Threshold Alerting
The thresholds prop on StreamNetworkFramemonitors a metric function against warning and critical thresholds. Nodes that cross a threshold change color and pulse with a glow animation, making overloaded services immediately visible.
JSX
<StreamNetworkFrame ref={chartRef} chartType="sankey" thresholds={{ metric: (node) => node.value, // extract the metric to check warning: 100, // yellow glow at 100+ critical: 250, // red glow at 250+ warningColor: "#f59e0b", criticalColor: "#ef4444", pulse: true, // animate the glow (default) }} // ... />
| Option | Type | Default | Description |
|---|
metric | (node) => number | required | Extract metric value from a node |
warning | number | — | Warning threshold |
critical | number | — | Critical threshold |
warningColor | string | #f59e0b | Warning state fill color |
criticalColor | string | #ef4444 | Critical state fill color |
pulse | boolean | true | Animate glow on alerting nodes |
Topology Diffing
When new nodes or edges appear in a streaming topology, Semiotic automatically highlights them with a green pulse glow that fades over 2 seconds. This makes infrastructure changes immediately visible without any configuration.
Access diff data programmatically via the getTopologyDiff()ref handle method, or react to changes with onTopologyChange.
JSX
// Topology diffing is automatic for streaming sankey. // New nodes get a green pulse glow (2s fade) when they appear. // Access diff data via the ref handle: const diff = chartRef.current.getTopologyDiff() // → { addedNodes: ["Service-42"], removedNodes: [], addedEdges: [...], removedEdges: [] } // React to topology changes: <StreamNetworkFrame ref={chartRef} chartType="sankey" onTopologyChange={(nodes, edges) => { const diff = chartRef.current.getTopologyDiff() if (diff.addedNodes.length > 0) { console.log("New services:", diff.addedNodes) } }} />
Live Demo
This demo combines all four features: click any node for details, watch particle speed vary by edge throughput, see nodes glow when they cross thresholds, and notice the green flash when new services appear in the topology.
JSX
const chartRef = useRef() // Push streaming data setInterval(() => { chartRef.current?.push({ source: "API Gateway", target: "Orders", value: Math.floor(Math.random() * 15), }) }, 300) <StreamNetworkFrame ref={chartRef} chartType="sankey" showParticles particleStyle={{ proportionalSpeed: true, spawnRate: 0.08 }} thresholds={{ metric: (node) => node.value, warning: 100, critical: 250, }} tensionConfig={{ transitionDuration: 600 }} staleness={{ threshold: 3000, showBadge: true }} showLabels edgeOpacity={0.4} />