auto-diagram
v1.0.2
Published
A Rust-based diagram generation library for JavaScript/TypeScript
Readme
auto-diagram
A Rust-based diagram layout engine compiled to WebAssembly for use in JavaScript/TypeScript projects. Provides automatic layout calculation for nodes, groups (including nested groups), and edges with orthogonal routing.
Features
- Automatic Layout - Calculates optimal positions for nodes and groups
- Nested Groups - Supports multi-level group hierarchy
- Edge Routing - Orthogonal path calculation with collision avoidance
- Shape Support - Rectangle and circle node shapes
- Custom Spacing - Configurable spacing between elements
- Direction-Aware Edges - Specify connection points (top, right, bottom, left)
Installation
npm install auto-diagramQuick Start
import init, { calculate_layout, version } from 'auto-diagram';
// Initialize WASM module
await init();
// Get library version
console.log(version());
// Define diagram structure
const input = {
config: {
node_spacing: 100,
group_margin: 20
},
root: [
{ type: "node", id: "n1", label: "Node A", width: 100, height: 50 },
{ type: "node", id: "n2", label: "Node B", width: 100, height: 50 }
],
root_layout: "horizontal",
edges: [
{
source: { id: "n1", direction: "right" },
target: { id: "n2", direction: "left" }
}
]
};
// Calculate layout
const result = JSON.parse(calculate_layout(JSON.stringify(input)));
console.log(result);API Reference
Functions
calculate_layout(input: string): string
Main entry point for layout calculation. Accepts a JSON string containing diagram definition and returns computed positions.
Parameters:
input- JSON string ofDiagramInput
Returns:
- JSON string of
LayoutResult
version(): string
Returns the library version string.
init(): Promise<void>
Initializes the WASM module. Must be called before using other functions.
Input Schema
DiagramInput
interface DiagramInput {
config?: LayoutConfig;
root: (NodeDef | GroupDef)[];
root_layout?: "horizontal" | "vertical";
edges?: EdgeDef[];
}LayoutConfig
interface LayoutConfig {
default_font_size?: number; // Font size in px (default: 14)
group_margin?: number; // Padding inside groups (default: 20)
group_spacing?: number; // Space between groups (default: 30)
node_label_margin?: number; // Space between node and label (default: 10)
node_spacing?: number; // Space between nodes (default: 100)
edge_min_segment?: number; // Minimum edge segment length (default: 20)
}NodeDef
interface NodeDef {
type: "node";
id: string; // Unique identifier
label: string; // Display text
width: number; // Width in pixels
height: number; // Height in pixels
shape?: "rect" | "circle"; // Node shape (default: "rect")
font_size?: number; // Override default font size
}GroupDef
interface GroupDef {
type: "group";
id: string; // Unique identifier
label?: string; // Group title
layout: "horizontal" | "vertical";
children: (NodeDef | GroupDef)[];
max_width?: number; // Maximum group width
max_height?: number; // Maximum group height
node_spacing_overrides?: SpacingOverride[];
}EdgeDef
interface EdgeDef {
source: {
id: string;
direction: "top" | "right" | "bottom" | "left";
};
target: {
id: string;
direction: "top" | "right" | "bottom" | "left";
};
label?: string;
label_position?: "start" | "middle" | "end";
}Output Schema
LayoutResult
interface LayoutResult {
nodes: NodeOutput[];
groups: GroupOutput[];
edges: EdgeOutput[];
bounds: {
width: number;
height: number;
};
}NodeOutput
interface NodeOutput {
id: string;
x: number; // X coordinate
y: number; // Y coordinate
width: number;
height: number;
label: string;
label_x: number; // Label X position
label_y: number; // Label Y position
font_size: number;
shape: string;
}GroupOutput
interface GroupOutput {
id: string;
x: number;
y: number;
width: number;
height: number;
label?: string;
label_x?: number;
label_y?: number;
}EdgeOutput
interface EdgeOutput {
source_id: string;
target_id: string;
path: { x: number; y: number }[]; // Waypoints for orthogonal path
label?: string;
label_x?: number;
label_y?: number;
}Examples
Simple Nodes
const input = {
root: [
{ type: "node", id: "a", label: "Start", width: 80, height: 40 },
{ type: "node", id: "b", label: "End", width: 80, height: 40 }
],
root_layout: "horizontal"
};Groups with Nested Structure
const input = {
root: [
{
type: "group",
id: "g1",
label: "Group A",
layout: "vertical",
children: [
{ type: "node", id: "n1", label: "Node 1", width: 100, height: 50 },
{ type: "node", id: "n2", label: "Node 2", width: 100, height: 50 }
]
}
],
edges: [
{
source: { id: "n1", direction: "bottom" },
target: { id: "n2", direction: "top" }
}
]
};Circle Nodes
const input = {
root: [
{ type: "node", id: "c1", label: "A", width: 50, height: 50, shape: "circle" },
{ type: "node", id: "c2", label: "B", width: 50, height: 50, shape: "circle" }
]
};Development
Prerequisites
Setup
# Install dependencies
npm install
# Build the project
npm run build
# Run tests
npm testBuild Commands
| Command | Description |
|---------|-------------|
| npm run build | Build both WASM and JavaScript wrapper |
| npm run build:wasm | Build WASM module only |
| npm run build:js | Build JavaScript wrapper only |
| npm run clean | Clean build artifacts |
Project Structure
auto-diagram/
├── src/ # Rust source code
│ ├── lib.rs # Main WASM entry point
│ ├── config.rs # Layout configuration
│ ├── input.rs # Input data structures
│ ├── output.rs # Output data structures
│ ├── layout/ # Layout algorithms
│ │ ├── calculator.rs # Main layout logic
│ │ ├── edge_routing.rs # Edge path calculation
│ │ ├── group_layout.rs # Group positioning
│ │ └── node_layout.rs # Node positioning
│ └── types/ # Core types
├── sample/ # Next.js sample application
├── tests/ # Integration tests
├── pkg/ # WASM build output
├── Cargo.toml # Rust configuration
└── package.json # NPM configurationLicense
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
