netviz
Version:
Network visualization library with multiple layout algorithms and rendering modes. Create interactive, publication-quality network visualizations with a simple, reactive API.
252 lines (187 loc) • 6.32 kB
Markdown
A **network visualization library** providing multiple layout algorithms and rendering modes. Create interactive, publication-quality network visualizations with a simple, reactive API.
Currently includes force-directed graphs with SVG and Canvas rendering, edge bundling, grouping layouts, and more visualization idioms coming soon.
Based on the [Observable notebook](https://observablehq.com/@john-guerra/force-directed-graph) and following the [reactive widgets](https://reactivewidgets.org) pattern.
```bash
npm install netviz d3
```
**TypeScript:** Type definitions are included. No additional @types packages needed.
```javascript
import { ForceGraph } from "netviz";
const data = {
nodes: [
{ id: "A", group: 1 },
{ id: "B", group: 1 },
{ id: "C", group: 2 }
],
links: [
{ source: "A", target: "B", value: 1 },
{ source: "B", target: "C", value: 2 }
]
};
const graph = ForceGraph(data, {
width: 800,
height: 600,
renderer: "svg" // or "canvas"
});
document.body.appendChild(graph);
```
**Alternative:** Use the `NodeLink` alias for semantic clarity:
```javascript
import { NodeLink } from "netviz";
const graph = NodeLink(data, options);
```
- **Dual Rendering**: Both SVG and Canvas with same API
- **Edge Bundling**: Optional force-based edge bundling
- **Force-in-a-Box**: Grouping layout algorithm
- **Smart Labels**: Voronoi-based label placement with occlusion detection
- **Zoom & Drag**: Interactive controls
- **AutoFit**: Automatic viewport fitting
- **Reactive Widgets**: Compatible with Observable and reactive frameworks
- **Observable Compatible**: Works seamlessly with Observable notebooks
Additional network visualization idioms will be added to this library
Interactive examples are available in the `examples/` directory, using Les Misérables character co-occurrence data:
- **basic.html** - Simple force-directed graph with SVG/Canvas rendering
- **advanced.html** - Edge bundling, grouping, and advanced features
- **observable-desktop.html** - Observable Desktop / Notebook Kit format
- **observable-framework.md** - Observable Framework format
To run the examples locally:
```bash
npm run serve
```
Or use any static server:
```bash
npx http-server
```
The examples use local data from `examples/data/miserables.json` for faster loading and offline use.
Creates a force-directed graph visualization. `NodeLink` is an alias for semantic clarity.
**Parameters:**
- `data` - Object with `{nodes, links}`
- `nodes`: Array of node objects with at least an `id` property
- `links`: Array of link objects with `source` and `target` properties
- Links support multiple formats:
```javascript
// String/number IDs (most common)
{ source: "nodeA", target: "nodeB" }
// Node object references
{ source: nodeObjA, target: nodeObjB }
// Numeric indices (e.g., vega-datasets format)
{ source: 0, target: 1 } // References nodes[0] and nodes[1]
```
- `options` - Configuration object (see Options below)
**Returns:** HTML Element (SVG or Canvas) with additional properties:
- `.value` - Currently selected nodes/edges (TODO)
- `.update(newData, newOptions)` - Update the graph
- `.destroy()` - Cleanup and stop simulation
- `.simulation` - Access to underlying D3 force simulation
- `.nodes` - Array of node objects
- `.links` - Array of link objects
### Key Options
```javascript
{
// Rendering
renderer: "canvas", // "svg" or "canvas"
width: 800,
height: 600,
// Nodes
nodeId: d => d.id,
nodeGroup: d => d.group, // For coloring
nodeRadius: 5, // Number or function
nodeLabel: d => d.id,
// Links
linkStrokeWidth: 1.5, // Number or function
linkStrokeOpacity: 0.6,
// Features
useEdgeBundling: false,
useForceInABox: false, // Group nodes by nodeGroup
useSmartLabels: true,
useZoom: true,
autoFit: true,
// Observable compatibility
invalidation: promise, // Auto-cleanup on promise resolution
_this: previousGraph // Preserve state
}
```
See `src/defaults.js` for all 100+ available options.
```javascript
// In an Observable notebook
{
const graph = ForceGraph(data, {
width,
invalidation // Auto-cleanup when cell re-runs
});
return graph;
}
```
```javascript
// Update with new data (preserves positions)
graph.update(newData, { renderer: "svg" });
// Cleanup
graph.destroy();
```
Full TypeScript support with comprehensive type definitions:
```typescript
import { ForceGraph, GraphData, ForceGraphOptions } from "netviz";
const data: GraphData = {
nodes: [
{ id: "A", group: 1 },
{ id: "B", group: 1 },
{ id: "C", group: 2 }
],
links: [
{ source: "A", target: "B" },
{ source: "B", target: "C" }
]
};
const options: ForceGraphOptions = {
width: 800,
height: 600,
renderer: "svg",
nodeRadius: 5
};
const graph = ForceGraph(data, options);
document.body.appendChild(graph);
```
```bash
npm install
npm run build
npm run dev
npm test
npm run test:lint
npm run format
npm run serve
```
This library bundles code from several sources:
- **Edge Bundling**: Based on [d3.ForceBundle](https://github.com/upphiminn/d3.ForceBundle) (GPL v2)
- **Custom Forces**: From Observable notebook [21d2053b3bc85bce](https://observablehq.com/d/21d2053b3bc85bce)
- **Smart Labels**: Uses [smart-labels](https://www.npmjs.com/package/smart-labels)
- **Force-in-a-Box**: Uses [force-in-a-box](https://www.npmjs.com/package/force-in-a-box)
ISC License - see LICENSE file for details
[](https://johnguerra.co)
- [Observable Notebook](https://observablehq.com/@john-guerra/force-directed-graph)
- [GitHub Repository](https://github.com/john-guerra/node-link)
- [NPM Package](https://www.npmjs.com/package/netviz)