vortx-gl 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +485 -35
- package/dist/engine/events.d.ts +32 -0
- package/dist/engine/interaction.d.ts +26 -0
- package/dist/engine/overlay.d.ts +80 -0
- package/dist/engine/picking.d.ts +40 -0
- package/dist/engine/renderer.d.ts +469 -0
- package/dist/engine/shaders.d.ts +4 -0
- package/dist/engine/types.d.ts +225 -0
- package/dist/index.d.ts +8 -1
- package/dist/vortx-gl.css +1 -1
- package/dist/vortx-gl.es.js +1 -1
- package/dist/vortx-gl.umd.js +1 -1
- package/examples/vue-example.vue +80 -0
- package/package.json +18 -25
- package/dist/webgl-graph-library.css +0 -1
- package/dist/webgl-graph.es.js +0 -1
- package/dist/webgl-graph.umd.js +0 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { mat3, vec2 } from "gl-matrix";
|
|
2
|
+
import type { NodeMetadata, EdgeMetadata, Combo, FlowConfig, PhantomEdge } from "./types";
|
|
3
|
+
export interface HUDAction {
|
|
4
|
+
comboId: string;
|
|
5
|
+
action: "expand" | "edit" | "delete";
|
|
6
|
+
}
|
|
7
|
+
export interface OverlayRenderParams {
|
|
8
|
+
positions: Float32Array | null;
|
|
9
|
+
nodeCount: number;
|
|
10
|
+
edgeCount: number;
|
|
11
|
+
edgeIndices: Uint32Array | null;
|
|
12
|
+
metadata: Map<number, NodeMetadata>;
|
|
13
|
+
edgeMetadata: Map<string, EdgeMetadata>;
|
|
14
|
+
combos: Map<string, Combo>;
|
|
15
|
+
theme: "dark" | "light";
|
|
16
|
+
zoom: number;
|
|
17
|
+
viewMatrix: mat3;
|
|
18
|
+
selectedNodeIds: Set<number>;
|
|
19
|
+
selectedEdgeId: string | null;
|
|
20
|
+
selectedComboId: string | null;
|
|
21
|
+
hoveredNodeId: number | null;
|
|
22
|
+
lockedNodes: Set<number>;
|
|
23
|
+
hiddenNodes: Set<number>;
|
|
24
|
+
isBoxSelecting: boolean;
|
|
25
|
+
selectionStart: vec2;
|
|
26
|
+
selectionEnd: vec2;
|
|
27
|
+
flow: FlowConfig;
|
|
28
|
+
selectedNodes: Set<number>;
|
|
29
|
+
phantomEdge: PhantomEdge | null;
|
|
30
|
+
edgeIndexToUserIdMap?: Map<string, string>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* @class OverlayManager
|
|
34
|
+
* @description Manages the high-performance 2D Canvas overlay for the graph.
|
|
35
|
+
* Handles labels, halos, selection marquees, flow animations, and viewport culling.
|
|
36
|
+
* Uses scratch variables and optimized loops to minimize GC impact.
|
|
37
|
+
*/
|
|
38
|
+
export declare class OverlayManager {
|
|
39
|
+
private canvas;
|
|
40
|
+
private ctx;
|
|
41
|
+
private hudRects;
|
|
42
|
+
/**
|
|
43
|
+
* Cached screen-space positions for the current frame.
|
|
44
|
+
* Format: [x0, y0, x1, y1, ...]
|
|
45
|
+
*/
|
|
46
|
+
private projectedCache;
|
|
47
|
+
constructor(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D);
|
|
48
|
+
private _posScratch;
|
|
49
|
+
private _spScratch;
|
|
50
|
+
private _s1Scratch;
|
|
51
|
+
private _s2Scratch;
|
|
52
|
+
/**
|
|
53
|
+
* Projects world coordinates to screen space.
|
|
54
|
+
*/
|
|
55
|
+
private project;
|
|
56
|
+
/**
|
|
57
|
+
* Helper to get theme-consistent colors for overlay elements.
|
|
58
|
+
*/
|
|
59
|
+
private getThemeColor;
|
|
60
|
+
/**
|
|
61
|
+
* Main render call for the overlay. Clears the canvas and draws all
|
|
62
|
+
* visible non-WebGL elements.
|
|
63
|
+
* @param params State parameters from the main engine.
|
|
64
|
+
*/
|
|
65
|
+
render(params: OverlayRenderParams): void;
|
|
66
|
+
private drawMarquee;
|
|
67
|
+
private drawCombos;
|
|
68
|
+
private drawGroupHUD;
|
|
69
|
+
pickHUDAction(mouseX: number, mouseY: number): HUDAction | null;
|
|
70
|
+
private drawNodeHighlights;
|
|
71
|
+
private drawEdgeHighlight;
|
|
72
|
+
private drawPhantomEdge;
|
|
73
|
+
private drawFlow;
|
|
74
|
+
private drawHoverHighlight;
|
|
75
|
+
private drawCustomEdges;
|
|
76
|
+
private drawEdgeLabels;
|
|
77
|
+
private drawNodeLabels;
|
|
78
|
+
private drawNodeIcon;
|
|
79
|
+
private drawLockIcon;
|
|
80
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { mat3 } from "gl-matrix";
|
|
2
|
+
import type { Combo } from "./types";
|
|
3
|
+
export declare class PickingEngine {
|
|
4
|
+
private gl;
|
|
5
|
+
constructor(gl: WebGL2RenderingContext);
|
|
6
|
+
pickNode(params: {
|
|
7
|
+
mouseX: number;
|
|
8
|
+
mouseY: number;
|
|
9
|
+
canvas: HTMLCanvasElement;
|
|
10
|
+
program: WebGLProgram;
|
|
11
|
+
pickingFramebuffer: WebGLFramebuffer;
|
|
12
|
+
vao: WebGLVertexArrayObject;
|
|
13
|
+
viewMatrix: mat3;
|
|
14
|
+
pointSize: number;
|
|
15
|
+
nodeCount: number;
|
|
16
|
+
}): number | null;
|
|
17
|
+
pickEdge(params: {
|
|
18
|
+
mouseX: number;
|
|
19
|
+
mouseY: number;
|
|
20
|
+
edgeIndices: Uint32Array | null;
|
|
21
|
+
positions: Float32Array | null;
|
|
22
|
+
nodeCount: number;
|
|
23
|
+
viewMatrix: mat3;
|
|
24
|
+
canvasW: number;
|
|
25
|
+
canvasH: number;
|
|
26
|
+
}): string | null;
|
|
27
|
+
pickCombo(params: {
|
|
28
|
+
mouseX: number;
|
|
29
|
+
mouseY: number;
|
|
30
|
+
combos: Map<string, Combo>;
|
|
31
|
+
positions: Float32Array | null;
|
|
32
|
+
nodeCount: number;
|
|
33
|
+
viewMatrix: mat3;
|
|
34
|
+
zoom: number;
|
|
35
|
+
canvasW: number;
|
|
36
|
+
canvasH: number;
|
|
37
|
+
}): string | null;
|
|
38
|
+
private distToSegment;
|
|
39
|
+
private project;
|
|
40
|
+
}
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import { vec2 } from "gl-matrix";
|
|
2
|
+
import type { NodeMetadata, EdgeMetadata, Combo, InteractionState, NodeInput, EdgeInput, NodeData, EdgeData, Stylesheet, RadialMenuItem, FlowConfig } from "./types";
|
|
3
|
+
export type { NodeMetadata, EdgeMetadata, Combo };
|
|
4
|
+
/**
|
|
5
|
+
* @class GraphEngine
|
|
6
|
+
* @description The main orchestrator for the WebGL graph visualization.
|
|
7
|
+
* It manages hardware-accelerated rendering of nodes/edges and coordinates with
|
|
8
|
+
* the PickingEngine for interaction and OverlayManager for UI elements.
|
|
9
|
+
*
|
|
10
|
+
* Supports incremental graph mutation (add/remove/update), a typed event system,
|
|
11
|
+
* element state (lock, hide, color), and is compatible with Cytoscape.js workflows.
|
|
12
|
+
*/
|
|
13
|
+
export declare class GraphEngine {
|
|
14
|
+
private gl;
|
|
15
|
+
private pickingEngine;
|
|
16
|
+
private overlayManager;
|
|
17
|
+
private emitter;
|
|
18
|
+
private program;
|
|
19
|
+
private edgeProgram;
|
|
20
|
+
private viewMatrix;
|
|
21
|
+
private vao;
|
|
22
|
+
private edgeVao;
|
|
23
|
+
private positionBuffer;
|
|
24
|
+
private colorBuffer;
|
|
25
|
+
private idBuffer;
|
|
26
|
+
private edgeIndexBuffer;
|
|
27
|
+
private pickingFramebuffer;
|
|
28
|
+
private pickingTexture;
|
|
29
|
+
private uMatrixLoc;
|
|
30
|
+
private uPointSizeLoc;
|
|
31
|
+
private uPickingModeLoc;
|
|
32
|
+
private uEdgeMatrixLoc;
|
|
33
|
+
private uEdgeColorLoc;
|
|
34
|
+
private nodeCount;
|
|
35
|
+
private edgeCount;
|
|
36
|
+
private positions;
|
|
37
|
+
private metadata;
|
|
38
|
+
private edgeIndices;
|
|
39
|
+
private edgeMetadata;
|
|
40
|
+
private combos;
|
|
41
|
+
private theme;
|
|
42
|
+
private static readonly MAX_ZOOM;
|
|
43
|
+
private static readonly MIN_ZOOM;
|
|
44
|
+
/** CPU-side per-node RGBA colors kept in sync with GPU colorBuffer. */
|
|
45
|
+
private colorData;
|
|
46
|
+
/** CPU-side per-node float IDs (= internal buffer index). */
|
|
47
|
+
private idData;
|
|
48
|
+
/** Current allocated GPU buffer capacity (in nodes). */
|
|
49
|
+
private capacity;
|
|
50
|
+
private autoNodeId;
|
|
51
|
+
private autoEdgeId;
|
|
52
|
+
/** User-facing string/number ID → internal buffer index */
|
|
53
|
+
private nodeIdMap;
|
|
54
|
+
/** Internal buffer index → user-facing ID */
|
|
55
|
+
private reverseIdMap;
|
|
56
|
+
/** The authoritative edge list used for mutation and CPU-side operations. */
|
|
57
|
+
private edgeList;
|
|
58
|
+
/** User edge ID → index in edgeList */
|
|
59
|
+
private edgeIdMap;
|
|
60
|
+
/** Internal "u-v" pick key → user edge ID, for translating GPU pick results. */
|
|
61
|
+
private edgeIndexToUserIdMap;
|
|
62
|
+
private stylesheet;
|
|
63
|
+
private lockedNodes;
|
|
64
|
+
private hiddenNodes;
|
|
65
|
+
private hiddenEdges;
|
|
66
|
+
private state;
|
|
67
|
+
private dragOffsets;
|
|
68
|
+
private canvas;
|
|
69
|
+
private overlayCanvas;
|
|
70
|
+
/**
|
|
71
|
+
* Sets a temporary "phantom" edge from a source node to a world position.
|
|
72
|
+
* Used for visual feedback during relation creation.
|
|
73
|
+
*/
|
|
74
|
+
setPhantomEdge(sourceNodeId: number, x: number, y: number): void;
|
|
75
|
+
/** Removes the temporary phantom edge. */
|
|
76
|
+
clearPhantomEdge(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Initializes the engine with the provided canvases.
|
|
79
|
+
* @param canvas The WebGL canvas for node/edge rendering.
|
|
80
|
+
* @param overlayCanvas The 2D canvas for labels and HUD elements.
|
|
81
|
+
*/
|
|
82
|
+
constructor(canvas: HTMLCanvasElement, overlayCanvas: HTMLCanvasElement);
|
|
83
|
+
/**
|
|
84
|
+
* Subscribe to a graph event.
|
|
85
|
+
* @param event Event name — see the Events Reference in the docs.
|
|
86
|
+
* @param handler Callback invoked with event-specific data.
|
|
87
|
+
* @returns An unsubscribe function for cleanup.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* const unsub = engine.on('node:click', ({ id }) => console.log('Clicked:', id));
|
|
91
|
+
* // Cleanup later:
|
|
92
|
+
* unsub();
|
|
93
|
+
*
|
|
94
|
+
* @events
|
|
95
|
+
* | Event | Payload |
|
|
96
|
+
* |---|---|
|
|
97
|
+
* | `node:add` | `{ id, index, position }` |
|
|
98
|
+
* | `node:remove` | `{ id }` |
|
|
99
|
+
* | `node:click` | `{ id, index }` |
|
|
100
|
+
* | `node:hover` | `{ id, index }` |
|
|
101
|
+
* | `node:hoverout` | `{}` |
|
|
102
|
+
* | `node:drag` | `{ id, index, x, y }` |
|
|
103
|
+
* | `node:select` | `{ id, index }` |
|
|
104
|
+
* | `nodes:select` | `{ ids[], indices[] }` |
|
|
105
|
+
* | `edge:add` | `{ id, source, target }` |
|
|
106
|
+
* | `edge:remove` | `{ id }` |
|
|
107
|
+
* | `edge:select` | `{ id }` |
|
|
108
|
+
* | `combo:select` | `{ id }` |
|
|
109
|
+
* | `graph:click` | `{ x, y }` |
|
|
110
|
+
* | `graph:pan` | `{ dx, dy, offset }` |
|
|
111
|
+
* | `graph:zoom` | `{ zoom }` |
|
|
112
|
+
* | `graph:clear` | `{}` |
|
|
113
|
+
*/
|
|
114
|
+
on<T = unknown>(event: string, handler: (data: T) => void): () => void;
|
|
115
|
+
/**
|
|
116
|
+
* Remove a previously registered event listener.
|
|
117
|
+
* @param event Event name.
|
|
118
|
+
* @param handler The exact handler reference passed to `on()`.
|
|
119
|
+
*/
|
|
120
|
+
off<T = unknown>(event: string, handler: (data: T) => void): void;
|
|
121
|
+
/**
|
|
122
|
+
* @internal Called by InteractionManager to fire events through the engine's emitter.
|
|
123
|
+
*/
|
|
124
|
+
emitEvent<T = unknown>(event: string, data?: T): void;
|
|
125
|
+
/**
|
|
126
|
+
* Sets the global stylesheet for the graph.
|
|
127
|
+
* Elements with matching 'classes' will inherit styles from this sheet.
|
|
128
|
+
*/
|
|
129
|
+
setStylesheet(sheet: Stylesheet): void;
|
|
130
|
+
/**
|
|
131
|
+
* Merges styles from multiple class names based on the current stylesheet.
|
|
132
|
+
*/
|
|
133
|
+
private resolveStyle;
|
|
134
|
+
/**
|
|
135
|
+
* Adds a single node to the live graph. GPU buffers are updated immediately.
|
|
136
|
+
* @param input Node configuration object.
|
|
137
|
+
* @returns The node's ID (user-provided or auto-generated).
|
|
138
|
+
* @fires `node:add`
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* const id = engine.addNode({
|
|
142
|
+
* id: 'alice',
|
|
143
|
+
* label: 'Alice',
|
|
144
|
+
* position: { x: 0.5, y: -0.3 },
|
|
145
|
+
* color: '#6bcb77',
|
|
146
|
+
* });
|
|
147
|
+
*/
|
|
148
|
+
addNode(input: NodeInput): string | number;
|
|
149
|
+
/**
|
|
150
|
+
* Updates an existing node's visual properties or data.
|
|
151
|
+
* @param input Node configuration containing the ID to update and new values.
|
|
152
|
+
*/
|
|
153
|
+
updateNode(input: NodeInput): void;
|
|
154
|
+
/**
|
|
155
|
+
* Removes a node (and all its connected edges) from the graph.
|
|
156
|
+
*
|
|
157
|
+
* Uses a **swap-with-last** strategy so GPU buffer updates are O(1) —
|
|
158
|
+
* the removed slot is overwritten by the last node, keeping the buffer compact.
|
|
159
|
+
*
|
|
160
|
+
* @param nodeId The user-facing node ID.
|
|
161
|
+
* @fires `node:remove`
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* engine.removeNode('alice');
|
|
165
|
+
*/
|
|
166
|
+
removeNode(nodeId: string | number): void;
|
|
167
|
+
/**
|
|
168
|
+
* Adds an edge between two existing nodes.
|
|
169
|
+
* @param input Edge configuration.
|
|
170
|
+
* @returns The edge's ID (user-provided or auto-generated).
|
|
171
|
+
* @fires `edge:add`
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* engine.addEdge({ source: 'alice', target: 'bob', label: 'knows' });
|
|
175
|
+
*/
|
|
176
|
+
addEdge(input: EdgeInput): string;
|
|
177
|
+
/**
|
|
178
|
+
* Updates metadata or properties of an existing edge.
|
|
179
|
+
*/
|
|
180
|
+
updateEdge(input: EdgeInput): void;
|
|
181
|
+
/**
|
|
182
|
+
* Removes an edge by its user-facing ID.
|
|
183
|
+
* @param edgeId The edge ID returned by `addEdge()` or set in `EdgeInput.id`.
|
|
184
|
+
* @fires `edge:remove`
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* engine.removeEdge('my-edge-id');
|
|
188
|
+
*/
|
|
189
|
+
removeEdge(edgeId: string): void;
|
|
190
|
+
/**
|
|
191
|
+
* Removes all nodes and edges from the graph and resets all state.
|
|
192
|
+
* @fires `graph:clear`
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* engine.clear();
|
|
196
|
+
*/
|
|
197
|
+
clear(): void;
|
|
198
|
+
/**
|
|
199
|
+
* Returns all nodes as plain data objects (not GPU references).
|
|
200
|
+
* @example
|
|
201
|
+
* const nodes = engine.getAllNodes();
|
|
202
|
+
* nodes.forEach(n => console.log(n.id, n.position));
|
|
203
|
+
*/
|
|
204
|
+
getAllNodes(): NodeData[];
|
|
205
|
+
/**
|
|
206
|
+
* Returns all edges as plain data objects.
|
|
207
|
+
* @example
|
|
208
|
+
* engine.getAllEdges().forEach(e => console.log(e.source, '→', e.target));
|
|
209
|
+
*/
|
|
210
|
+
getAllEdges(): EdgeData[];
|
|
211
|
+
/**
|
|
212
|
+
* Returns all nodes that have the specified class applied.
|
|
213
|
+
*/
|
|
214
|
+
getNodesByClass(className: string): NodeData[];
|
|
215
|
+
/**
|
|
216
|
+
* Returns all edges that have the specified class applied.
|
|
217
|
+
*/
|
|
218
|
+
getEdgesByClass(className: string): EdgeData[];
|
|
219
|
+
/**
|
|
220
|
+
* Returns a single node by its user-facing ID.
|
|
221
|
+
*/
|
|
222
|
+
getNode(nodeId: string | number): NodeData | null;
|
|
223
|
+
/**
|
|
224
|
+
* Returns the internal GPU buffer index for a node, or `null` if not found.
|
|
225
|
+
*/
|
|
226
|
+
getInternalIndex(nodeId: string | number): number | null;
|
|
227
|
+
/**
|
|
228
|
+
* Returns the user-facing ID for an internal buffer index, or `null`.
|
|
229
|
+
*/
|
|
230
|
+
getNodeId(index: number): string | number | null;
|
|
231
|
+
/**
|
|
232
|
+
* Returns the metadata (labels, icons, custom data) for a given node ID.
|
|
233
|
+
*/
|
|
234
|
+
getNodeMetadata(nodeId: string | number): NodeMetadata | null;
|
|
235
|
+
/**
|
|
236
|
+
* Returns the metadata for a given edge ID.
|
|
237
|
+
*/
|
|
238
|
+
getEdgeMetadata(edgeId: string): EdgeMetadata | null;
|
|
239
|
+
/**
|
|
240
|
+
* Locks a node so it cannot be dragged by the user.
|
|
241
|
+
* Programmatic position changes via `setNodePosition()` still work.
|
|
242
|
+
*/
|
|
243
|
+
lockNode(nodeId: string | number): void;
|
|
244
|
+
/**
|
|
245
|
+
* Unlocks a previously locked node.
|
|
246
|
+
*/
|
|
247
|
+
unlockNode(nodeId: string | number): void;
|
|
248
|
+
/**
|
|
249
|
+
* @internal Used by InteractionManager to check lock state before dragging.
|
|
250
|
+
*/
|
|
251
|
+
isNodeLocked(index: number): boolean;
|
|
252
|
+
/**
|
|
253
|
+
* Hides a node. Hidden nodes are invisible and cannot be picked or selected.
|
|
254
|
+
* The node remains in the graph and can be shown again with `showNode()`.
|
|
255
|
+
* @example
|
|
256
|
+
* engine.hideNode('alice');
|
|
257
|
+
*/
|
|
258
|
+
hideNode(nodeId: string | number): void;
|
|
259
|
+
/**
|
|
260
|
+
* Shows a previously hidden node.
|
|
261
|
+
* @example
|
|
262
|
+
* engine.showNode('alice');
|
|
263
|
+
*/
|
|
264
|
+
showNode(nodeId: string | number): void;
|
|
265
|
+
/**
|
|
266
|
+
* @internal Returns true if the node at `index` is hidden.
|
|
267
|
+
*/
|
|
268
|
+
isNodeHidden(index: number): boolean;
|
|
269
|
+
/**
|
|
270
|
+
* Sets the fill color of a node. Accepts 0–1 float components.
|
|
271
|
+
*/
|
|
272
|
+
setNodeColor(nodeId: string | number, r: number, g: number, b: number, a?: number): void;
|
|
273
|
+
/**
|
|
274
|
+
* Updates the display label of a node.
|
|
275
|
+
*/
|
|
276
|
+
setNodeLabel(nodeId: string | number, label: string): void;
|
|
277
|
+
/**
|
|
278
|
+
* Merges a plain object into a node's `data` field.
|
|
279
|
+
*/
|
|
280
|
+
setNodeData(nodeId: string | number, data: any): void;
|
|
281
|
+
/**
|
|
282
|
+
* Hides an edge. It will not be rendered or pickable.
|
|
283
|
+
* @example
|
|
284
|
+
* engine.hideEdge('edge-1');
|
|
285
|
+
*/
|
|
286
|
+
hideEdge(edgeId: string): void;
|
|
287
|
+
/**
|
|
288
|
+
* Shows a previously hidden edge.
|
|
289
|
+
*/
|
|
290
|
+
showEdge(edgeId: string): void;
|
|
291
|
+
reverseEdge(edgeId: string): void;
|
|
292
|
+
/**
|
|
293
|
+
* Updates the display label of an edge.
|
|
294
|
+
*/
|
|
295
|
+
setEdgeLabel(edgeId: string, label: string): void;
|
|
296
|
+
/**
|
|
297
|
+
* Merges a plain object into an edge's `data` field.
|
|
298
|
+
*/
|
|
299
|
+
setEdgeData(edgeId: string, data: any): void;
|
|
300
|
+
/**
|
|
301
|
+
* Deselects all nodes and edges.
|
|
302
|
+
*/
|
|
303
|
+
deselectAll(): void;
|
|
304
|
+
/**
|
|
305
|
+
* Uploads graph data to the GPU in bulk and initializes all internal state.
|
|
306
|
+
* After calling `setData`, the graph supports incremental mutation via
|
|
307
|
+
* `addNode` / `removeNode` / `addEdge` / `removeEdge`.
|
|
308
|
+
*
|
|
309
|
+
* @param positions Interleaved node coordinates [x1, y1, x2, y2, ...]
|
|
310
|
+
* @param colors Interleaved RGBA colors [r1,g1,b1,a1, r2,g2,b2,a2, ...]
|
|
311
|
+
* @param ids Unique numeric identifiers (typically [0,1,2,...,n])
|
|
312
|
+
* @param metadata Map of node metadata (labels, icons, etc.) keyed by index
|
|
313
|
+
* @param edgeIndices Source-target index pairs for edges [u1,v1, u2,v2, ...]
|
|
314
|
+
* @param nodeIdMap Optional map of UserID -> BufferIndex. If omitted, indices 0..N are used as IDs.
|
|
315
|
+
* @param edgeMetadata Map of edge metadata keyed by "u-v" strings or Edge IDs
|
|
316
|
+
*/
|
|
317
|
+
setData(positions: Float32Array, colors: Float32Array, ids: Float32Array, metadata: Map<number, NodeMetadata>, edgeIndices?: Uint32Array, edgeMetadata?: Map<string, EdgeMetadata>, nodeIdMap?: Map<string | number, number>): void;
|
|
318
|
+
updatePositions(positions: Float32Array): void;
|
|
319
|
+
setNodePosition(id: number, x: number, y: number): void;
|
|
320
|
+
getNodePosition(id: number): vec2 | null;
|
|
321
|
+
setFlowAnimation(enabled: boolean): void;
|
|
322
|
+
setTheme(theme: "dark" | "light"): void;
|
|
323
|
+
setFlowVelocity(velocity: number): void;
|
|
324
|
+
/**
|
|
325
|
+
* Sets the particle size for the energy flow animation.
|
|
326
|
+
* @param size Base radius in pixels.
|
|
327
|
+
*/
|
|
328
|
+
setFlowSize(size: number): void;
|
|
329
|
+
/**
|
|
330
|
+
* Sets a custom color for the energy flow particles.
|
|
331
|
+
* @param color CSS color string (e.g. '#00ff00', 'rgba(0,0,0,0.5)')
|
|
332
|
+
*/
|
|
333
|
+
setFlowColor(color: string | undefined): void;
|
|
334
|
+
/**
|
|
335
|
+
* Filters the energy flow to only show on specific edges.
|
|
336
|
+
* @param prop metadata.data property name.
|
|
337
|
+
* @param value Required value for the property to match.
|
|
338
|
+
*/
|
|
339
|
+
setFlowFilter(prop: string | null, value?: unknown): void;
|
|
340
|
+
/**
|
|
341
|
+
* Creates a group (combo) containing the specified nodes.
|
|
342
|
+
* @param id Unique group ID.
|
|
343
|
+
* @param label Display label for the group border.
|
|
344
|
+
* @param nodeIds Array of User IDs to include in the group.
|
|
345
|
+
* @fires `combo:add`
|
|
346
|
+
*/
|
|
347
|
+
createGroup(id: string, label: string, nodeIds: (string | number)[]): void;
|
|
348
|
+
/**
|
|
349
|
+
* Removes a group. The nodes inside the group are NOT deleted.
|
|
350
|
+
*/
|
|
351
|
+
removeGroup(id: string): void;
|
|
352
|
+
/**
|
|
353
|
+
* Adds a node to an existing group.
|
|
354
|
+
*/
|
|
355
|
+
addToGroup(groupId: string, nodeId: string | number): void;
|
|
356
|
+
/**
|
|
357
|
+
* Removes a node from a group.
|
|
358
|
+
*/
|
|
359
|
+
removeFromGroup(groupId: string, nodeId: string | number): void;
|
|
360
|
+
/**
|
|
361
|
+
* Toggles the collapsed/expanded state of a group.
|
|
362
|
+
* When collapsed, all members are hidden.
|
|
363
|
+
*/
|
|
364
|
+
toggleComboCollapse(groupId: string): void;
|
|
365
|
+
/**
|
|
366
|
+
* Moves an entire group by a world-space delta.
|
|
367
|
+
*/
|
|
368
|
+
moveGroup(groupId: string, dx: number, dy: number, skipSync?: boolean): void;
|
|
369
|
+
/**
|
|
370
|
+
* Returns all groups and their members.
|
|
371
|
+
*/
|
|
372
|
+
getAllGroups(): {
|
|
373
|
+
id: string;
|
|
374
|
+
label: string;
|
|
375
|
+
nodeIds: (string | number)[];
|
|
376
|
+
}[];
|
|
377
|
+
createCombo(id: string, label: string, nodeIds: (string | number)[]): void;
|
|
378
|
+
removeCombo(id: string): void;
|
|
379
|
+
updateCombo(id: string, label: string, nodeIds: (string | number)[]): void;
|
|
380
|
+
getCombo(id: string): Combo;
|
|
381
|
+
addNodeToCombo(comboId: string, nodeId: string | number): void;
|
|
382
|
+
removeNodeFromCombo(comboId: string, nodeId: string | number): void;
|
|
383
|
+
render(): void;
|
|
384
|
+
private renderOverlay;
|
|
385
|
+
getState(): InteractionState;
|
|
386
|
+
updateInteractionState(update: Partial<InteractionState>): void;
|
|
387
|
+
/**
|
|
388
|
+
* Configures the Energy Flow animation settings.
|
|
389
|
+
*/
|
|
390
|
+
setFlowConfig(config: Partial<FlowConfig>): void;
|
|
391
|
+
/**
|
|
392
|
+
* GPU color-buffer picking. Returns the internal index of the node under the cursor,
|
|
393
|
+
* or `null` if nothing was hit or if the hit node is hidden.
|
|
394
|
+
*/
|
|
395
|
+
pick(mouseX: number, mouseY: number): number | null;
|
|
396
|
+
/**
|
|
397
|
+
* CPU line-segment picking. Returns the user-facing edge ID under the cursor, or `null`.
|
|
398
|
+
* Hidden edges are excluded.
|
|
399
|
+
*/
|
|
400
|
+
getEdgeAt(mouseX: number, mouseY: number): string | null;
|
|
401
|
+
pickCombo(mouseX: number, mouseY: number): string | null;
|
|
402
|
+
pickHUD(mouseX: number, mouseY: number): import("./overlay").HUDAction;
|
|
403
|
+
fitToView(): void;
|
|
404
|
+
zoomIn(): void;
|
|
405
|
+
zoomOut(): void;
|
|
406
|
+
setCameraCenter(x: number, y: number): void;
|
|
407
|
+
setCameraZoom(zoom: number): void;
|
|
408
|
+
getSelectedNodeIds(): number[];
|
|
409
|
+
/**
|
|
410
|
+
* Returns the User IDs of all currently selected nodes.
|
|
411
|
+
*/
|
|
412
|
+
getSelectedUserIds(): (string | number)[];
|
|
413
|
+
selectNode(id: number | null): void;
|
|
414
|
+
zoomAt(mouseX: number, mouseY: number, delta: number): void;
|
|
415
|
+
/**
|
|
416
|
+
* Run a built-in geometric layout on the nodes.
|
|
417
|
+
* Supports Grid, Circle, and Random arrangements.
|
|
418
|
+
*
|
|
419
|
+
* @param type Layout algorithm to use.
|
|
420
|
+
* @param options Configuration for the layout run.
|
|
421
|
+
*/
|
|
422
|
+
runLayout(type: "grid" | "circle" | "random", options?: {
|
|
423
|
+
selectedOnly?: boolean;
|
|
424
|
+
}): void;
|
|
425
|
+
private radialMenuConfigs;
|
|
426
|
+
/**
|
|
427
|
+
* Configures the available items in the circular context menu for a specific type.
|
|
428
|
+
* @param type 'node', 'edge', or 'combo'
|
|
429
|
+
* @param items List of menu items.
|
|
430
|
+
*/
|
|
431
|
+
setRadialMenu(type: 'node' | 'edge' | 'combo', items: RadialMenuItem[]): void;
|
|
432
|
+
/**
|
|
433
|
+
* Returns the registered menu items for a type.
|
|
434
|
+
*/
|
|
435
|
+
getRadialMenu(type: string): RadialMenuItem[];
|
|
436
|
+
pan(dx: number, dy: number): void;
|
|
437
|
+
syncDragOffsets(mouseX: number, mouseY: number): void;
|
|
438
|
+
handleDragging(mouseX: number, mouseY: number): void;
|
|
439
|
+
performBoxSelection(): void;
|
|
440
|
+
unproject(screenX: number, screenY: number): vec2;
|
|
441
|
+
private initShaders;
|
|
442
|
+
private initBuffers;
|
|
443
|
+
private initPicking;
|
|
444
|
+
private handleResize;
|
|
445
|
+
private updateMatrix;
|
|
446
|
+
private createProgram;
|
|
447
|
+
/**
|
|
448
|
+
* Resolve a user-facing node ID (string or number) to the internal buffer index.
|
|
449
|
+
*/
|
|
450
|
+
private resolveNodeIndex;
|
|
451
|
+
/** Parse color input into a [r, g, b, a] tuple with 0–1 float components. */
|
|
452
|
+
private parseColor;
|
|
453
|
+
/**
|
|
454
|
+
* Ensures the CPU+GPU node buffers have at least `minCount` capacity.
|
|
455
|
+
* Uses a doubling strategy to amortize reallocation cost.
|
|
456
|
+
*/
|
|
457
|
+
private ensureNodeCapacity;
|
|
458
|
+
/**
|
|
459
|
+
* Rebuilds the GPU edge index buffer from `edgeList`, excluding hidden edges.
|
|
460
|
+
* Called after any edge mutation.
|
|
461
|
+
*/
|
|
462
|
+
private rebuildEdgeBuffer;
|
|
463
|
+
/** Rebuilds the `edgeIndexToUserIdMap` from scratch (called after node swaps). */
|
|
464
|
+
private rebuildEdgeIndexToUserIdMap;
|
|
465
|
+
/** Internal edge removal without buffer rebuild (for batched removeNode). */
|
|
466
|
+
private _removeEdgeInternal;
|
|
467
|
+
/** Pre-processes a node image into a circular, white-tinted off-screen canvas. */
|
|
468
|
+
private loadNodeImage;
|
|
469
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const NODE_VS = "#version 300 es\nlayout(location = 0) in vec2 a_position;\nlayout(location = 1) in vec4 a_color;\nlayout(location = 2) in float a_id;\n\nuniform mat3 u_matrix;\nuniform float u_pointSize;\nuniform bool u_pickingMode;\n\nout vec4 v_color;\nflat out uint v_id;\n\nvoid main() {\n vec3 position = u_matrix * vec3(a_position, 1.0);\n gl_Position = vec4(position.xy, 0, 1);\n gl_PointSize = u_pointSize;\n v_color = a_color;\n v_id = uint(a_id);\n}\n";
|
|
2
|
+
export declare const NODE_FS = "#version 300 es\nprecision highp float;\n\nin vec4 v_color;\nflat in uint v_id;\n\nuniform bool u_pickingMode;\nout vec4 outColor;\n\nvoid main() {\n float dist = distance(gl_PointCoord, vec2(0.5));\n if (dist > 0.5) discard;\n if (v_color.a <= 0.0) discard;\n\n if (u_pickingMode) {\n uint id = v_id + 1u;\n float r = float((id >> 16) & 0xFFu) / 255.0;\n float g = float((id >> 8) & 0xFFu) / 255.0;\n float b = float(id & 0xFFu) / 255.0;\n outColor = vec4(r, g, b, 1.0);\n } else {\n outColor = v_color;\n }\n}\n";
|
|
3
|
+
export declare const EDGE_VS = "#version 300 es\nlayout(location = 0) in vec2 a_position;\n\nuniform mat3 u_matrix;\n\nvoid main() {\n vec3 position = u_matrix * vec3(a_position, 1.0);\n gl_Position = vec4(position.xy, 0, 1);\n}\n";
|
|
4
|
+
export declare const EDGE_FS = "#version 300 es\nprecision highp float;\nuniform vec4 u_color;\nout vec4 outColor;\n\nvoid main() {\n outColor = u_color;\n}\n";
|