Inital commit
commit
cfd64ddd02
|
|
@ -0,0 +1,191 @@
|
|||
# NodeEditor.js API Documentation
|
||||
|
||||
`NodeEditor.js` is a lightweight, framework-agnostic, zero-dependency node editor library written in pure ES6 JavaScript. It leverages standard DOM elements for high-performance node manipulation and an SVG overlay plane for drawing scalable Bezier connections.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 1. HTML Setup
|
||||
Create a dedicated target container for the editor. Ensure the container has explicit dimensional bounds (`width` and `height`).
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Node Editor Instance</title>
|
||||
<style>
|
||||
body { margin: 0; background: #111; }
|
||||
#editor-container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="editor-container"></div>
|
||||
|
||||
<script type="module" src="./app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### 2. JavaScript Initialization (`app.js`)
|
||||
Import the `NodeEditor` module, hook it to your DOM node, and instantiate your first pipeline.
|
||||
|
||||
```javascript
|
||||
import { NodeEditor } from './NodeEditor.js';
|
||||
|
||||
// 1. Initialize the UI Engine
|
||||
const container = document.getElementById('editor-container');
|
||||
const editor = new NodeEditor(container);
|
||||
|
||||
// 2. Extract the State Manager
|
||||
const graph = editor.getGraphManager();
|
||||
|
||||
// 3. Spawning Nodes
|
||||
const nodeA = graph.addNode({
|
||||
type: 'source_node',
|
||||
title: 'Data Stream',
|
||||
x: 100,
|
||||
y: 150,
|
||||
inputs: [],
|
||||
outputs: [{ id: 'out_raw', name: 'Raw Buffer' }]
|
||||
});
|
||||
|
||||
const nodeB = graph.addNode({
|
||||
type: 'processing_node',
|
||||
title: 'Transform Matrix',
|
||||
x: 450,
|
||||
y: 250,
|
||||
inputs: [{ id: 'in_data', name: 'Payload' }],
|
||||
outputs: [{ id: 'out_success', name: 'Success' }]
|
||||
});
|
||||
|
||||
// 4. Create a programmatically driven wire connection
|
||||
graph.connect(nodeA.id, 'out_raw', nodeB.id, 'in_data');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Architecture Overview
|
||||
|
||||
The library enforces a strict separation of concerns via an asynchronous, decoupled state cycle:
|
||||
|
||||
```
|
||||
[User Action / UI Pointer Interaction]
|
||||
│
|
||||
▼
|
||||
[GraphManager State Engine] ◄─── (Single Source of Truth)
|
||||
│
|
||||
▼ (Dispatches Event Hub Actions)
|
||||
[NodeEditor Render Architecture]
|
||||
│
|
||||
┌──────────┴──────────┐
|
||||
▼ ▼
|
||||
[DOM Element Nodes] [SVG Vector Overlay Patches]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 API Reference
|
||||
|
||||
### `NodeEditor` (UI Controller)
|
||||
|
||||
The wrapper orchestration manager that structures layout elements, listens to user viewport transforms, and monitors state bindings.
|
||||
|
||||
* **`new NodeEditor(containerElement)`**
|
||||
Instantiates a fresh node pipeline map inside a target DOM container.
|
||||
* **`editor.getGraphManager()`**
|
||||
Returns the underlying data `GraphManager` engine operating behind the target instance.
|
||||
* **`editor.updateAllConnections()`**
|
||||
Forces an absolute layout recalculation of all connection nodes in view. Useful if you change node positions outside the lifecycle API or resize your external container dynamically.
|
||||
|
||||
---
|
||||
|
||||
### `GraphManager` (State Controller)
|
||||
|
||||
The isolated data engine that processes, updates, validates, and serializes graph states.
|
||||
|
||||
#### Node Management APIs
|
||||
* **`addNode(config)`**
|
||||
Registers a new data node. Returns the instantiated `NodeSchema` object.
|
||||
* `config.title`: (String) Header title text.
|
||||
* `config.x` / `config.y`: (Numbers) Absolute starting canvas positioning.
|
||||
* `config.inputs` / `config.outputs`: Array of port objects (`{ id: 'unique_port_id', name: 'Display Name' }`).
|
||||
* `config.id`: *(Optional)* Provide a deterministic string ID; otherwise, an internal generic system identifier will be automatically assigned.
|
||||
* **`deleteNode(nodeId)`**
|
||||
Destroys the node element matching the identifier and automatically sweeps/prunes any associated broken dependency lines.
|
||||
* **`updateNodePosition(nodeId, x, y)`**
|
||||
Mutates raw positioning values inside the memory reference model and triggers view updating layers.
|
||||
|
||||
#### Connection Management APIs
|
||||
* **`connect(fromNodeId, fromSocketId, toNodeId, toSocketId)`**
|
||||
Wires an active logical curve bridge between an output port and an input port. Returns `ConnectionSchema` object or `null` if the connection is illegal (e.g. self-looping or double mapping onto an input).
|
||||
* **`disconnect(connectionId)`**
|
||||
Severs a trace path across nodes using its direct line identifier.
|
||||
|
||||
#### Serialization & Hydration
|
||||
* **`getState()`**
|
||||
Returns a deep, JSON-serializable clone of the entire active workspace graph network topology.
|
||||
* **`loadState(graphState)`**
|
||||
Clears all active rendered interface objects and loads a freshly mapped `GraphState` configuration layer.
|
||||
|
||||
```javascript
|
||||
// Saving state to local storage
|
||||
const currentSnapshot = graph.getState();
|
||||
localStorage.setItem('my_graph', JSON.stringify(currentSnapshot));
|
||||
|
||||
// Restoring state later
|
||||
const cachedSnapshot = JSON.parse(localStorage.getItem('my_graph'));
|
||||
if (cachedSnapshot) {
|
||||
graph.loadState(cachedSnapshot);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎛️ Handling Graph Events
|
||||
|
||||
The `GraphManager` implements a lightweight publisher/subscriber layout. You can listen to lifecycle changes across your pipeline engine to trigger custom code:
|
||||
|
||||
```javascript
|
||||
// Capture changes to map properties to external reactive modules
|
||||
graph.on('stateChanged', (latestState) => {
|
||||
console.log("Global modifications registered:", latestState);
|
||||
});
|
||||
|
||||
// Trace isolated edge terminations
|
||||
graph.on('connectionRemoved', (connId) => {
|
||||
console.warn(`Connection item vanished from runtime: ${connId}`);
|
||||
});
|
||||
|
||||
// Trace node structural changes
|
||||
graph.on('nodeAdded', (node) => {
|
||||
console.log(`New node generated: ${node.title}`);
|
||||
});
|
||||
```
|
||||
|
||||
### Available Event Signatures
|
||||
|
||||
| Event Key | Callback Arguments | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| `'nodeAdded'` | `(nodeSchema)` | Dispatched when a node object joins the topology. |
|
||||
| `'nodeRemoved'` | `(nodeId)` | Dispatched when a node is removed from the canvas. |
|
||||
| `'nodeMoved'` | `(nodeSchema)` | Dispatched repeatedly when a node object moves coordinates. |
|
||||
| `'connectionAdded'`| `(connectionSchema)` | Dispatched when two nodes are connected. |
|
||||
| `'connectionRemoved'`| `(connectionId)` | Dispatched when an edge bridge is broken or deleted. |
|
||||
| `'stateChanged'` | `(graphState)` | Global catch-all event executed immediately after any graph mutation. |
|
||||
|
||||
---
|
||||
|
||||
## ⌨️ User Interface Interactions
|
||||
|
||||
* **Pan Canvas:** Click and drag anywhere on the empty background or the SVG connection space.
|
||||
* **Zoom Viewport:** Scroll your mouse wheel or trackpad up and down. The transformation framework calculates and pins vector values centered **directly on your mouse cursor location**.
|
||||
* **Drag Nodes:** Click and hold the node header bar container element. Movement velocities match your active zoom ratio precisely.
|
||||
* **Draw Wires:** Click a target circular socket connector on an output node and drag your mouse. Drop the temporary dashed wire onto a target input node socket to complete a bridge connection.
|
||||
* **Destroy Wires:** Click directly on an active solid colored connection bridge path vector line to delete it from the running memory structure.
|
||||
* **Destroy Nodes:** Click the small `✕` button positioned inside the upper-right corner of the node header frame.
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import { NodeEditor } from './NodeEditor.js';
|
||||
|
||||
// 1. Initialize the UI Engine
|
||||
const container = document.getElementById('editor-container');
|
||||
const editor = new NodeEditor(container);
|
||||
|
||||
// 2. Extract the State Manager
|
||||
const graph = editor.getGraphManager();
|
||||
|
||||
// 3. Spawning Nodes
|
||||
const nodeA = graph.addNode({
|
||||
type: 'source_node',
|
||||
title: 'Data Stream',
|
||||
x: 100,
|
||||
y: 150,
|
||||
inputs: [],
|
||||
outputs: [{ id: 'out_raw', name: 'Raw Buffer' }]
|
||||
});
|
||||
|
||||
const nodeB = graph.addNode({
|
||||
type: 'processing_node',
|
||||
title: 'Transform Matrix',
|
||||
x: 450,
|
||||
y: 250,
|
||||
inputs: [{ id: 'in_data', name: 'Payload' }],
|
||||
outputs: [{ id: 'out_success', name: 'Success' }]
|
||||
});
|
||||
|
||||
// 4. Create a programmatically driven wire connection
|
||||
graph.connect(nodeA.id, 'out_raw', nodeB.id, 'in_data');
|
||||
Loading…
Reference in New Issue