An interactive dependency graph visualizer built for VS Code webviews. It renders a force-directed node-link diagram from a typed Graph object, with filtering, selection, relationship inspection, and smooth pan/zoom.
Features
- Force-directed layout — nodes settle into position automatically using D3's simulation, with collision avoidance and soft boundary forces to keep everything on screen
- Directional arrows — arrowheads are clipped to rect boundaries so they always appear visibly between nodes, never hidden underneath them
- Type-based filtering — sidebar lets you isolate nodes by type (Component, Handler, Analytics, Data, Types, Util)
- Node inspection — click any node to open a detail panel showing its parents, siblings, and children with colour-coded chips
- Chip navigation — click any relationship chip to jump directly to that node
- Pan & zoom — scroll to zoom, drag canvas to pan, drag individual nodes to reposition
- Fit / reset toolbar — ⊡ fits all visible nodes in view, ↺ resets zoom to 1:1
- Dimming — when a node is selected, unrelated nodes fade out so the local neighbourhood is clear
Usage
import { getWebviewContent } from './graphWebview';
const graph: Graph = {
nodes: [
{ id: 'app', label: 'App', type: 'component' },
{ id: 'router', label: 'Router', type: 'component' },
{ id: 'auth', label: 'Auth', type: 'handler' },
],
links: [
{ source: 'app', target: 'router' },
{ source: 'router', target: 'auth' },
],
};
panel.webview.html = getWebviewContent(graph);
Pass the return value directly to panel.webview.html in your VS Code extension. The function serialises the graph as inline JSON — no separate data fetch is needed.
API
getWebviewContent(graph: Graph): string
Returns a self-contained HTML string ready to set as webview content.
Graph
| Field | Type | Description |
|---|---|---|
nodes |
GraphNode[] |
List of nodes to render |
links |
GraphLink[] |
List of directed edges |
GraphNode
| Field | Type | Description |
|---|---|---|
id |
string |
Unique identifier — used to match link sources/targets |
label |
string |
Display text shown inside the node rect |
type |
string |
Controls colour and sidebar filter category (see below) |
GraphLink
| Field | Type | Description |
|---|---|---|
source |
string |
id of the source (importing) node |
target |
string |
id of the target (imported) node |
Links whose source or target don't match any node id are silently ignored.
Node Types & Colours
| Type | Colour |
|---|---|
component |
Blue |
handler |
Purple |
analytics |
Green |
datalayer |
Amber |
type |
Red |
util |
Sky |
| (anything else) | Grey |
Any string is accepted as a type — unknown values fall back to grey and won't appear in the sidebar filter list.
Relationship Colours
When a node is selected, connected nodes are highlighted by relationship:
| Relationship | Colour | Meaning |
|---|---|---|
| Parent | Purple | Nodes that import the selection |
| Sibling | Amber | Nodes that share a parent |
| Child | Green | Nodes the selection imports |
Content Security Policy
The webview uses this CSP:
default-src 'none';
script-src 'unsafe-inline' https://cdnjs.cloudflare.com;
style-src 'unsafe-inline';
D3 v7 is loaded from cdnjs.cloudflare.com. No other external resources are fetched.
Dependencies
| Library | Version | Source |
|---|---|---|
| D3.js | 7.8.5 | cdnjs.cloudflare.com (CDN) |
No build step required — everything is inlined into the returned HTML string.
How Arrows Work
Earlier versions drew link <line> elements between node centres, causing arrowheads to be hidden underneath the target rectangle. The current version uses rectEdgePoint() to compute where each line should start and end on the rectangle's boundary:
source centre ──► source rect edge ──────────────► target rect edge ──► arrowhead
A 4px gap is added between the arrowhead tip and the node border so arrows never appear to touch or clip.