vortx-gl 1.0.2 → 1.0.27
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/components/DatasetSelector.d.ts +19 -0
- package/dist/components/FPSMonitor.d.ts +2 -0
- package/dist/components/GraphCanvas.d.ts +109 -0
- package/dist/components/LayoutControls.d.ts +18 -0
- package/dist/components/LucideIcon.d.ts +10 -0
- package/dist/components/PropertyPanel.d.ts +28 -0
- package/dist/components/RadialMenu.d.ts +33 -0
- package/dist/components/SearchBar.d.ts +12 -0
- package/dist/components/ViewControls.d.ts +18 -0
- package/dist/engine/Minimap.d.ts +25 -0
- package/dist/engine/api/adapter.d.ts +35 -0
- package/dist/engine/api/index.d.ts +2 -0
- package/dist/engine/api/types.d.ts +86 -0
- package/dist/engine/config.d.ts +117 -0
- package/dist/engine/core/Camera.d.ts +34 -0
- package/dist/engine/core/ComboStore.d.ts +23 -0
- package/dist/engine/core/EdgeStore.d.ts +37 -0
- package/dist/engine/core/NodeStore.d.ts +34 -0
- package/dist/engine/core/context.d.ts +20 -0
- package/dist/engine/events.d.ts +19 -0
- package/dist/engine/gpu/GpuBufferManager.d.ts +39 -0
- package/dist/engine/interaction/GroupInteraction.d.ts +40 -0
- package/dist/engine/interaction.d.ts +31 -0
- package/dist/engine/overlay/ComboRenderer.d.ts +25 -0
- package/dist/engine/overlay/EdgeRenderer.d.ts +32 -0
- package/dist/engine/overlay/NodeRenderer.d.ts +52 -0
- package/dist/engine/overlay/OverlayManager.d.ts +38 -0
- package/dist/engine/overlay/SharedOverlayState.d.ts +47 -0
- package/dist/engine/overlay/effects.d.ts +15 -0
- package/dist/engine/overlay/index.d.ts +2 -0
- package/dist/engine/overlay/shapes.d.ts +7 -0
- package/dist/engine/overlay/text.d.ts +15 -0
- package/dist/engine/picking.d.ts +51 -0
- package/dist/engine/renderConstants.d.ts +13 -0
- package/dist/engine/renderer.d.ts +222 -0
- package/dist/engine/shaders/edge.glsl.d.ts +2 -0
- package/dist/engine/shaders/node.glsl.d.ts +2 -0
- package/dist/engine/shaders.d.ts +2 -0
- package/dist/engine/spatialIndex.d.ts +32 -0
- package/dist/engine/types.d.ts +688 -0
- package/dist/engine/utils/pointSize.d.ts +23 -0
- package/dist/engine/utils/styleResolver.d.ts +163 -0
- package/dist/index.d.ts +14 -1
- package/dist/vortx-gl.css +1206 -1
- package/dist/vortx-gl.es.js +3718 -1
- package/dist/vortx-gl.umd.js +3706 -1
- package/package.json +7 -6
- package/dist/assets/layout.worker-CBxeMMC3.js +0 -1
- package/dist/favicon.ico +0 -0
- package/dist/logo.png +0 -0
- package/dist/vite.svg +0 -1
- 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,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handler function that consumes event data.
|
|
3
|
+
* T defaults to `unknown` for maximum safety.
|
|
4
|
+
*/
|
|
5
|
+
export type EventHandler<T = unknown> = (data: T) => void;
|
|
6
|
+
/**
|
|
7
|
+
* Lightweight typed EventEmitter used internally by GraphEngine
|
|
8
|
+
* to expose a clean `engine.on('node:click', handler)` API.
|
|
9
|
+
*/
|
|
10
|
+
export declare class EventEmitter {
|
|
11
|
+
private listeners;
|
|
12
|
+
on<T = unknown>(event: string, handler: EventHandler<T>): () => void;
|
|
13
|
+
off<T = unknown>(event: string, handler: EventHandler<T>): void;
|
|
14
|
+
emit<T = unknown>(event: string, data?: T): void;
|
|
15
|
+
/**
|
|
16
|
+
* Remove all handlers for a specific event, or all events if no name given.
|
|
17
|
+
*/
|
|
18
|
+
removeAllListeners(event?: string): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export declare class GpuBufferManager {
|
|
2
|
+
program: WebGLProgram | null;
|
|
3
|
+
edgeProgram: WebGLProgram | null;
|
|
4
|
+
vao: WebGLVertexArrayObject | null;
|
|
5
|
+
edgeVao: WebGLVertexArrayObject | null;
|
|
6
|
+
positionBuffer: WebGLBuffer | null;
|
|
7
|
+
colorBuffer: WebGLBuffer | null;
|
|
8
|
+
idBuffer: WebGLBuffer | null;
|
|
9
|
+
shapeBuffer: WebGLBuffer | null;
|
|
10
|
+
sizeBuffer: WebGLBuffer | null;
|
|
11
|
+
targetPositionBuffer: WebGLBuffer | null;
|
|
12
|
+
edgeIndexBuffer: WebGLBuffer | null;
|
|
13
|
+
pickingFramebuffer: WebGLFramebuffer | null;
|
|
14
|
+
pickingTexture: WebGLTexture | null;
|
|
15
|
+
uMatrixLoc: WebGLUniformLocation | null;
|
|
16
|
+
uPointSizeLoc: WebGLUniformLocation | null;
|
|
17
|
+
uPointSizeMaxLoc: WebGLUniformLocation | null;
|
|
18
|
+
uPickingModeLoc: WebGLUniformLocation | null;
|
|
19
|
+
uEdgeMatrixLoc: WebGLUniformLocation | null;
|
|
20
|
+
uEdgeColorLoc: WebGLUniformLocation | null;
|
|
21
|
+
uTransitionProgressLoc: WebGLUniformLocation | null;
|
|
22
|
+
uEdgeTransitionProgressLoc: WebGLUniformLocation | null;
|
|
23
|
+
private gl;
|
|
24
|
+
private canvas;
|
|
25
|
+
constructor(gl: WebGL2RenderingContext, canvas: HTMLCanvasElement);
|
|
26
|
+
init(): void;
|
|
27
|
+
private initShaders;
|
|
28
|
+
private initBuffers;
|
|
29
|
+
initPicking(): void;
|
|
30
|
+
private createProgram;
|
|
31
|
+
reallocateNodeBuffers(positions: Float32Array, colorData: Float32Array, idData: Float32Array, shapeData: Float32Array, sizeData?: Float32Array): void;
|
|
32
|
+
syncNode(idx: number, positions: Float32Array, colorData: Float32Array, idData: Float32Array, shapeData: Float32Array, sizeData?: Float32Array): void;
|
|
33
|
+
/** Push a single node's size multiplier to the GPU. Used by updateNode. */
|
|
34
|
+
syncSize(idx: number, sizeData: Float32Array): void;
|
|
35
|
+
syncEdges(indices: Uint32Array | null): void;
|
|
36
|
+
syncPositions(positions: Float32Array): void;
|
|
37
|
+
syncAllPositions(positions: Float32Array): void;
|
|
38
|
+
destroy(): void;
|
|
39
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { vec2 } from 'gl-matrix';
|
|
2
|
+
import { GraphEngine } from '../renderer';
|
|
3
|
+
import { HUDAction } from '../overlay';
|
|
4
|
+
/**
|
|
5
|
+
* GroupInteraction manages all combo/group related interactions.
|
|
6
|
+
*
|
|
7
|
+
* Behavior design:
|
|
8
|
+
* - Click on combo HUD: Toggle collapse/expand or enter Edit Mode.
|
|
9
|
+
* - Edit Mode: Highlights the group and selects all its members.
|
|
10
|
+
* - Drag nodes INTO a group hull: Add nodes to that group.
|
|
11
|
+
* - Drag nodes OUT of a group hull: Remove nodes from that group.
|
|
12
|
+
* - Click on combo hull: Drag the entire group.
|
|
13
|
+
*/
|
|
14
|
+
export declare class GroupInteraction {
|
|
15
|
+
private engine;
|
|
16
|
+
private canvas;
|
|
17
|
+
private _lastDropPickTime;
|
|
18
|
+
constructor(engine: GraphEngine, canvas: HTMLCanvasElement);
|
|
19
|
+
/**
|
|
20
|
+
* Handles HUD button actions (expand/collapse, edit).
|
|
21
|
+
* Returns true if handled — caller should return early.
|
|
22
|
+
*/
|
|
23
|
+
handleHUDAction(hudAction: HUDAction): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Throttled drop-target highlight during node dragging.
|
|
26
|
+
* Shows orange feedback when dragging over a group.
|
|
27
|
+
*/
|
|
28
|
+
handleDragOver(mouseX: number, mouseY: number): void;
|
|
29
|
+
/**
|
|
30
|
+
* Called on mouse/touch-up after dragging nodes.
|
|
31
|
+
* Membership is updated based on where the nodes were dropped.
|
|
32
|
+
*/
|
|
33
|
+
handleDrop(mouseX: number, mouseY: number): void;
|
|
34
|
+
/**
|
|
35
|
+
* Moves the selected combo by the world-space delta from last mouse position.
|
|
36
|
+
*/
|
|
37
|
+
handleGroupDrag(mouseX: number, mouseY: number, lastMouse: vec2): void;
|
|
38
|
+
/** Exits edit mode and clears selection. Call when clicking on empty space. */
|
|
39
|
+
exitEditMode(): void;
|
|
40
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { GraphEngine } from './renderer';
|
|
2
|
+
export declare class InteractionManager {
|
|
3
|
+
private lastMouse;
|
|
4
|
+
private isPanning;
|
|
5
|
+
private isDraggingCombo;
|
|
6
|
+
private engine;
|
|
7
|
+
private canvas;
|
|
8
|
+
private groups;
|
|
9
|
+
private lastTouchDistance;
|
|
10
|
+
private lastTouchMidpoint;
|
|
11
|
+
private isTouching;
|
|
12
|
+
private touchStartTime;
|
|
13
|
+
private touchStartPos;
|
|
14
|
+
private longPressTimer;
|
|
15
|
+
private isLongPress;
|
|
16
|
+
private lastPickTime;
|
|
17
|
+
private _zoomSettleTimer;
|
|
18
|
+
private _disposers;
|
|
19
|
+
constructor(engine: GraphEngine, canvas: HTMLCanvasElement);
|
|
20
|
+
private setupListeners;
|
|
21
|
+
destroy(): void;
|
|
22
|
+
private handleMouseDown;
|
|
23
|
+
private handleMouseMove;
|
|
24
|
+
private handleMouseUp;
|
|
25
|
+
private handleWheel;
|
|
26
|
+
private handleTouchStart;
|
|
27
|
+
private handleTouchMove;
|
|
28
|
+
private handleTouchEnd;
|
|
29
|
+
private clearLongPress;
|
|
30
|
+
private triggerContextMenu;
|
|
31
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { mat3 } from 'gl-matrix';
|
|
2
|
+
import { Combo } from '../types';
|
|
3
|
+
import { SharedOverlayState } from './SharedOverlayState';
|
|
4
|
+
export interface HUDAction {
|
|
5
|
+
comboId: string;
|
|
6
|
+
action: "expand" | "edit" | "delete";
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Renders combo (group) hulls, their summary circles when collapsed, and
|
|
10
|
+
* the floating HUD strip used to expand/edit each one.
|
|
11
|
+
*
|
|
12
|
+
* Owns the `hudRects` map so HUD hit-testing can stay co-located with
|
|
13
|
+
* the drawing code that produced the rectangles.
|
|
14
|
+
*/
|
|
15
|
+
export declare class ComboRenderer {
|
|
16
|
+
private hudRects;
|
|
17
|
+
private state;
|
|
18
|
+
constructor(state: SharedOverlayState);
|
|
19
|
+
/** Hit-test the rendered HUD strip. Returns the action under the cursor, or null. */
|
|
20
|
+
pickHUDAction(mouseX: number, mouseY: number): HUDAction | null;
|
|
21
|
+
draw(combos: Map<string, Combo>, positions: Float32Array, nodeCount: number, viewMatrix: mat3, zoom: number, selectedComboId: string | null, dropTargetId: string | null, editingComboId: string | null, theme: string, dpr: number): void;
|
|
22
|
+
private drawCollapsedCombo;
|
|
23
|
+
private drawExpandedCombo;
|
|
24
|
+
private drawGroupHUD;
|
|
25
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { mat3 } from 'gl-matrix';
|
|
2
|
+
import { NodeMetadata, EdgeMetadata, PhantomEdge } from '../types';
|
|
3
|
+
import { SharedOverlayState } from './SharedOverlayState';
|
|
4
|
+
/**
|
|
5
|
+
* Renders custom edges (when overriding the GPU edge buffer), edge labels,
|
|
6
|
+
* arrowheads, hover/selected highlights, and the drag-to-create phantom edge.
|
|
7
|
+
*
|
|
8
|
+
* Owns the small adjacency cache used by the hover pass so we don't rescan
|
|
9
|
+
* the full edge list every frame.
|
|
10
|
+
*/
|
|
11
|
+
export declare class EdgeRenderer {
|
|
12
|
+
private hoverNeighborCache;
|
|
13
|
+
private hoverCachedNodeId;
|
|
14
|
+
private hoverCachedEdgeCount;
|
|
15
|
+
private state;
|
|
16
|
+
constructor(state: SharedOverlayState);
|
|
17
|
+
drawHighlight(u: number, v: number, edgeId: string, positions: Float32Array, viewMatrix: mat3, dpr: number, nodeMetadata: Map<number, NodeMetadata>, edgeMetadata: Map<string, EdgeMetadata>, pointSize: number): void;
|
|
18
|
+
drawPhantom(phantom: PhantomEdge, positions: Float32Array, viewMatrix: mat3, dpr: number): void;
|
|
19
|
+
/**
|
|
20
|
+
* Draws every edge connected to `hoveredId` in the secondary highlight color.
|
|
21
|
+
* Adjacency list is cached and only rebuilt when the hovered node or edge
|
|
22
|
+
* topology changes — a major win on high-degree nodes.
|
|
23
|
+
*/
|
|
24
|
+
drawHoverHighlight(hoveredId: number, indices: Uint32Array, count: number, theme: "dark" | "light", dpr: number, nodeMetadata: Map<number, NodeMetadata>, pointSize: number): void;
|
|
25
|
+
/**
|
|
26
|
+
* Draws edges that opt into custom styling (color, width, curvature, dash).
|
|
27
|
+
* Plain edges keep using the GPU pipeline.
|
|
28
|
+
*/
|
|
29
|
+
drawCustomEdges(indices: Uint32Array, count: number, edgeMetadata: Map<string, EdgeMetadata>, edgeIndexToId: string[], theme: string, dpr: number, nodeMetadata: Map<number, NodeMetadata>, pointSize: number): void;
|
|
30
|
+
drawLabels(indices: Uint32Array, count: number, edgeMetadata: Map<string, EdgeMetadata>, edgeIndexToId: string[], theme: "dark" | "light", dpr: number, zoom: number, nodeMetadata: Map<number, NodeMetadata>, pointSize: number, defaultLabelMinZoom?: number, defaultLabelMaxZoom?: number): void;
|
|
31
|
+
drawArrows(indices: Uint32Array, count: number, edgeMetadata: Map<string, EdgeMetadata>, edgeIndexToId: string[], theme: string, dpr: number, zoom: number, nodeMetadata: Map<number, NodeMetadata>, pointSize: number): void;
|
|
32
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { mat3 } from 'gl-matrix';
|
|
2
|
+
import { NodeMetadata } from '../types';
|
|
3
|
+
import { SharedOverlayState } from './SharedOverlayState';
|
|
4
|
+
/**
|
|
5
|
+
* Draws everything that lives on a node: selection halos, shape borders,
|
|
6
|
+
* icons, labels, badges, and lock indicators.
|
|
7
|
+
*/
|
|
8
|
+
export declare class NodeRenderer {
|
|
9
|
+
private state;
|
|
10
|
+
constructor(state: SharedOverlayState);
|
|
11
|
+
/**
|
|
12
|
+
* Selection ring stroked just outside each selected node. Off-screen
|
|
13
|
+
* selections get a small directional ping.
|
|
14
|
+
*/
|
|
15
|
+
drawHighlights(ids: Set<number>, count: number, positions: Float32Array, viewMatrix: mat3, pointSize: number, dpr: number, hiddenNodes: Set<number>, shapeData?: Float32Array, metadata?: Map<number, NodeMetadata>): void;
|
|
16
|
+
/**
|
|
17
|
+
* Re-fills each selected node with its `colorOnSelect` (when set). Must run
|
|
18
|
+
* AFTER `punchOutNodes` and BEFORE `drawLabels` so the icon stays on top.
|
|
19
|
+
*/
|
|
20
|
+
drawSelectionFills(ids: Set<number>, count: number, metadata: Map<number, NodeMetadata>, pointSize: number, hiddenNodes: Set<number>, shapeData?: Float32Array): void;
|
|
21
|
+
/**
|
|
22
|
+
* Two offset shadow circles behind any node carrying the "nodeGroup" class,
|
|
23
|
+
* conveying that the node represents multiple collapsed entities.
|
|
24
|
+
*/
|
|
25
|
+
drawGroupStackShadows(_count: number, metadata: Map<number, NodeMetadata>, pointSize: number, dpr: number, colorData: Float32Array): void;
|
|
26
|
+
/**
|
|
27
|
+
* Dark count badge top-right of every nodeGroup-classed node, showing
|
|
28
|
+
* `metadata.groupCount`. Skipped when groupCount is undefined or zero.
|
|
29
|
+
*/
|
|
30
|
+
drawGroupBadges(_count: number, metadata: Map<number, NodeMetadata>, pointSize: number, dpr: number): void;
|
|
31
|
+
/**
|
|
32
|
+
* Dark expand-button (+) top-right of every nodeGroup-classed node.
|
|
33
|
+
*/
|
|
34
|
+
drawExpandButtons(_count: number, metadata: Map<number, NodeMetadata>, pointSize: number, dpr: number): void;
|
|
35
|
+
/**
|
|
36
|
+
* Draws a thin shape outline + clipped icon/image for each visible node, then
|
|
37
|
+
* places its label according to alignment metadata. Caps total drawn nodes
|
|
38
|
+
* at `maxLabels` so very dense graphs don't tank the frame.
|
|
39
|
+
*/
|
|
40
|
+
drawLabels(count: number, metadata: Map<number, NodeMetadata>, theme: "dark" | "light", dpr: number, pointSize: number, zoom: number, lockedNodes: Set<number>, shapeData?: Float32Array, defaultLabelMinZoom?: number, defaultLabelMaxZoom?: number, hoveredNodeId?: number | null, priorityNodeIds?: Set<number>, colorData?: Float32Array): void;
|
|
41
|
+
private drawLabelLoop;
|
|
42
|
+
/** Draws round badges at the four corners around a node circle. */
|
|
43
|
+
drawBadges(_count: number, metadata: Map<number, NodeMetadata>, dpr: number, pointSize: number, zoom: number): void;
|
|
44
|
+
/**
|
|
45
|
+
* Punches transparent holes where each node's circle sits, so that overlay
|
|
46
|
+
* elements drawn earlier (edge labels, arrows) are visually clipped behind
|
|
47
|
+
* the WebGL-rendered node beneath them.
|
|
48
|
+
*/
|
|
49
|
+
punchOutNodes(_count: number, metadata: Map<number, NodeMetadata>, pointSize: number): void;
|
|
50
|
+
private drawNodeIcon;
|
|
51
|
+
private drawLockIcon;
|
|
52
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { OverlayRenderParams } from '../types';
|
|
2
|
+
import { HUDAction } from './ComboRenderer';
|
|
3
|
+
/**
|
|
4
|
+
* Top-level Canvas2D overlay coordinator.
|
|
5
|
+
*
|
|
6
|
+
* Responsibilities are kept narrow:
|
|
7
|
+
* - own the shared scratch state + projection cache
|
|
8
|
+
* - compute viewport bounds and pre-project visible nodes
|
|
9
|
+
* - dispatch each render phase to a focused sub-renderer
|
|
10
|
+
*
|
|
11
|
+
* All actual drawing lives in ComboRenderer / NodeRenderer / EdgeRenderer
|
|
12
|
+
* and the small free-function modules in this directory.
|
|
13
|
+
*/
|
|
14
|
+
export declare class OverlayManager {
|
|
15
|
+
private state;
|
|
16
|
+
private combos;
|
|
17
|
+
private nodes;
|
|
18
|
+
private edges;
|
|
19
|
+
private invViewScratch;
|
|
20
|
+
private tlScratch;
|
|
21
|
+
private brScratch;
|
|
22
|
+
private vMinX;
|
|
23
|
+
private vMaxX;
|
|
24
|
+
private vMinY;
|
|
25
|
+
private vMaxY;
|
|
26
|
+
private wasProjecting;
|
|
27
|
+
constructor(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D);
|
|
28
|
+
/** Fast clear for animation frames — skips all drawing work. */
|
|
29
|
+
clearOnly(): void;
|
|
30
|
+
/** Hit-test the combo HUD strip (delegates to ComboRenderer). */
|
|
31
|
+
pickHUDAction(mouseX: number, mouseY: number): HUDAction | null;
|
|
32
|
+
render(params: OverlayRenderParams): void;
|
|
33
|
+
/**
|
|
34
|
+
* Walks every node, marking culled ones with NaN in `projectedCache` and
|
|
35
|
+
* filling the rest with screen-space coords.
|
|
36
|
+
*/
|
|
37
|
+
private projectVisibleNodes;
|
|
38
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { mat3, vec2, vec3 } from 'gl-matrix';
|
|
2
|
+
/**
|
|
3
|
+
* Shared mutable state passed to every overlay sub-renderer.
|
|
4
|
+
*
|
|
5
|
+
* Owns the projection cache, scratch vectors, and `project()` helper so that
|
|
6
|
+
* sub-renderers can avoid re-allocating per frame and stay aligned on a single
|
|
7
|
+
* world→screen mapping.
|
|
8
|
+
*/
|
|
9
|
+
export declare class SharedOverlayState {
|
|
10
|
+
canvas: HTMLCanvasElement;
|
|
11
|
+
ctx: CanvasRenderingContext2D;
|
|
12
|
+
/** Screen-space (x,y) for every node, indexed by node id. NaN means culled. */
|
|
13
|
+
projectedCache: Float32Array<ArrayBuffer>;
|
|
14
|
+
/** Pre-built [0..count] index array, reused for label iteration. */
|
|
15
|
+
nodeIndices: Int32Array<ArrayBuffer>;
|
|
16
|
+
/**
|
|
17
|
+
* Subset of nodeIndices whose projected coords fall inside the canvas
|
|
18
|
+
* (plus a small margin). Built once per frame in OverlayManager.render
|
|
19
|
+
* after projection. Per-node overlay passes (punchOutNodes, drawLabels,
|
|
20
|
+
* drawBadges, drawGroupBadges, drawExpandButtons) iterate THIS instead
|
|
21
|
+
* of nodeIndices so they walk ~visible-count entries instead of N.
|
|
22
|
+
*
|
|
23
|
+
* On a 100K-node graph with ~500 nodes visible, this turns O(N)
|
|
24
|
+
* iterations per pass into O(visible) — typically 10–100× faster per
|
|
25
|
+
* Canvas2D pass during pan/zoom.
|
|
26
|
+
*/
|
|
27
|
+
visibleNodeIndices: Int32Array<ArrayBuffer>;
|
|
28
|
+
/** Number of valid entries at the start of `visibleNodeIndices`. */
|
|
29
|
+
visibleNodeCount: number;
|
|
30
|
+
posScratch: vec3;
|
|
31
|
+
spScratch: vec2;
|
|
32
|
+
s1Scratch: vec2;
|
|
33
|
+
s2Scratch: vec2;
|
|
34
|
+
maxLabelsPerFrame: number;
|
|
35
|
+
smallGraphThreshold: number;
|
|
36
|
+
viewportCullMargin: number;
|
|
37
|
+
/** CSS pixels of inset between the icon and the node's outer border. */
|
|
38
|
+
nodeIconPaddingPx: number;
|
|
39
|
+
/** Toggle for the off-canvas-edge dot+arrow that marks a selected node
|
|
40
|
+
* outside the viewport. Mirrors GraphConfig.style.showOffscreenSelectionIndicator. */
|
|
41
|
+
showOffscreenSelectionIndicator: boolean;
|
|
42
|
+
constructor(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D);
|
|
43
|
+
/** World→screen projection. Writes to `out` and returns it for chaining. */
|
|
44
|
+
project(x: number, y: number, viewMatrix: mat3, out: vec2): vec2;
|
|
45
|
+
/** Grow projection/index buffers if the node count exceeds current capacity. */
|
|
46
|
+
ensureCapacity(nodeCount: number): void;
|
|
47
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { vec2 } from 'gl-matrix';
|
|
2
|
+
import { EdgeMetadata, FlowConfig } from '../types';
|
|
3
|
+
/** Box-selection marquee rectangle. */
|
|
4
|
+
export declare function drawMarquee(ctx: CanvasRenderingContext2D, start: vec2, end: vec2, dpr: number): void;
|
|
5
|
+
/**
|
|
6
|
+
* Small "ping" + arrow at the screen edge pointing to an off-screen target.
|
|
7
|
+
* Used so users notice selected nodes/edges that have scrolled out of view.
|
|
8
|
+
*/
|
|
9
|
+
export declare function drawOffscreenIndicator(ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, target1: vec2, target2: vec2, color: string, dpr: number): void;
|
|
10
|
+
/**
|
|
11
|
+
* Animated particles travelling along edges. Reads endpoint positions from
|
|
12
|
+
* the projection cache (NaN endpoints are skipped). Particle count is capped
|
|
13
|
+
* via `step` so very dense graphs don't blow out path complexity.
|
|
14
|
+
*/
|
|
15
|
+
export declare function drawFlow(ctx: CanvasRenderingContext2D, projectedCache: Float32Array, indices: Uint32Array, count: number, zoom: number, dpr: number, theme: "dark" | "light", flow: FlowConfig, edgeMetadata: Map<string, EdgeMetadata>, selectedNodes: Set<number>): void;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shape index → Canvas2D path. Numeric ids match the GPU shader's switch:
|
|
3
|
+
* 0=circle, 1=square, 2=triangle, 3=diamond, 4=round-rect, 5=cut-rect.
|
|
4
|
+
*
|
|
5
|
+
* Caller is responsible for `beginPath()` before and `fill()`/`stroke()`/`clip()` after.
|
|
6
|
+
*/
|
|
7
|
+
export declare function drawShapePath(ctx: CanvasRenderingContext2D, x: number, y: number, r: number, shape: number): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { NodeMetadata, EdgeMetadata } from '../types';
|
|
2
|
+
/** Strip HTML tags so they aren't drawn literally onto the canvas. */
|
|
3
|
+
export declare function stripHtml(text: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the text actually rendered for a node/edge. Honors `labelHidden`
|
|
6
|
+
* and `labelSource` (which pulls a value from `meta.data`).
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveLabelText(meta: NodeMetadata | EdgeMetadata): string;
|
|
9
|
+
/**
|
|
10
|
+
* Draws a metadata-driven text label with optional background, border, outline,
|
|
11
|
+
* uppercase/lowercase transform, and word-wrapping.
|
|
12
|
+
*
|
|
13
|
+
* `isMiddle` indicates an edge mid-label (different default styling than node labels).
|
|
14
|
+
*/
|
|
15
|
+
export declare function drawStyledText(ctx: CanvasRenderingContext2D, text: string, x: number, y: number, meta: NodeMetadata | EdgeMetadata, theme: "dark" | "light", dpr: number, isMiddle?: boolean, bgOpacityOverride?: number, isHovered?: boolean, scale?: number): void;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { mat3 } from 'gl-matrix';
|
|
2
|
+
import { Combo, EdgeMetadata } from './types';
|
|
3
|
+
export declare class PickingEngine {
|
|
4
|
+
private gl;
|
|
5
|
+
private _v1;
|
|
6
|
+
private _v2;
|
|
7
|
+
private _v3;
|
|
8
|
+
private _bSeg0;
|
|
9
|
+
private _bSeg1;
|
|
10
|
+
private _p1;
|
|
11
|
+
private _invViewScratch;
|
|
12
|
+
private _mouseNDC;
|
|
13
|
+
constructor(gl: WebGL2RenderingContext);
|
|
14
|
+
pickNode(params: {
|
|
15
|
+
mouseX: number;
|
|
16
|
+
mouseY: number;
|
|
17
|
+
canvas: HTMLCanvasElement;
|
|
18
|
+
program: WebGLProgram;
|
|
19
|
+
pickingFramebuffer: WebGLFramebuffer;
|
|
20
|
+
vao: WebGLVertexArrayObject;
|
|
21
|
+
viewMatrix: mat3;
|
|
22
|
+
pointSize: number;
|
|
23
|
+
nodeCount: number;
|
|
24
|
+
}): number | null;
|
|
25
|
+
pickEdge(params: {
|
|
26
|
+
mouseX: number;
|
|
27
|
+
mouseY: number;
|
|
28
|
+
edgeIndices: Uint32Array | null;
|
|
29
|
+
positions: Float32Array | null;
|
|
30
|
+
nodeCount: number;
|
|
31
|
+
viewMatrix: mat3;
|
|
32
|
+
canvasW: number;
|
|
33
|
+
canvasH: number;
|
|
34
|
+
edgeMetadata: Map<string, EdgeMetadata>;
|
|
35
|
+
edgeIndexToId: string[];
|
|
36
|
+
}): string | null;
|
|
37
|
+
pickCombo(params: {
|
|
38
|
+
mouseX: number;
|
|
39
|
+
mouseY: number;
|
|
40
|
+
combos: Map<string, Combo>;
|
|
41
|
+
positions: Float32Array | null;
|
|
42
|
+
nodeCount: number;
|
|
43
|
+
viewMatrix: mat3;
|
|
44
|
+
zoom: number;
|
|
45
|
+
canvasW: number;
|
|
46
|
+
canvasH: number;
|
|
47
|
+
excludeIndices?: Set<number>;
|
|
48
|
+
}): string | null;
|
|
49
|
+
private distToSegment;
|
|
50
|
+
private projectTo;
|
|
51
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const SELECTION_RING_COLOR: "#4A9EFF";
|
|
2
|
+
export declare const SELECTION_RING_WIDTH_PX: 3;
|
|
3
|
+
export declare const SELECTION_RING_RADIUS_FACTOR: 1.1;
|
|
4
|
+
export declare const NODE_GROUP_BADGE_RADIUS_PX: 10;
|
|
5
|
+
export declare const NODE_GROUP_BADGE_FILL: "#76ABE7";
|
|
6
|
+
export declare const NODE_GROUP_BADGE_TEXT: "#ffffff";
|
|
7
|
+
export declare const NODE_GROUP_BADGE_TEXT_PX: 10;
|
|
8
|
+
export declare const NODE_GROUP_STACK_SHADOW_OFFSETS: readonly number[];
|
|
9
|
+
export declare const NODE_GROUP_STACK_SHADOW_OPACITY: 0.2;
|
|
10
|
+
export declare const NODE_EXPAND_BUTTON_RADIUS_PX: 10;
|
|
11
|
+
export declare const NODE_EXPAND_BUTTON_FILL: "#1a1a1a";
|
|
12
|
+
export declare const NODE_EXPAND_BUTTON_ICON: "#ffffff";
|
|
13
|
+
export declare const NODE_EXPAND_BUTTON_ICON_PX: 12;
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { vec2 } from 'gl-matrix';
|
|
2
|
+
import { NodeStore } from './core/NodeStore';
|
|
3
|
+
import { EdgeStore } from './core/EdgeStore';
|
|
4
|
+
import { ComboStore } from './core/ComboStore';
|
|
5
|
+
import { Camera } from './core/Camera';
|
|
6
|
+
import { GpuBufferManager } from './gpu/GpuBufferManager';
|
|
7
|
+
import { Minimap } from './Minimap';
|
|
8
|
+
import { BackendGraphData } from './api/types';
|
|
9
|
+
import { PartialGraphConfig, ResolvedGraphConfig, GraphOptions } from './config';
|
|
10
|
+
import { SpatialIndex } from './spatialIndex';
|
|
11
|
+
import { ResolvedNodeStyle, ResolvedNodeSelectStyle, ResolvedEdgeStyle, ResolvedEdgeSelectStyle } from './utils/styleResolver';
|
|
12
|
+
import { NodeMetadata, EdgeMetadata, Combo, InteractionState, NodeInput, EdgeInput, Stylesheet, RadialMenuItem, FlowConfig, GraphEvent, GraphEventPayloadMap } from './types';
|
|
13
|
+
export type { NodeMetadata, EdgeMetadata, Combo };
|
|
14
|
+
export declare class GraphEngine {
|
|
15
|
+
private gl;
|
|
16
|
+
private canvas;
|
|
17
|
+
private overlayCanvas;
|
|
18
|
+
private emitter;
|
|
19
|
+
private pickingEngine;
|
|
20
|
+
private overlayManager;
|
|
21
|
+
nodes: NodeStore;
|
|
22
|
+
edges: EdgeStore;
|
|
23
|
+
combos: ComboStore;
|
|
24
|
+
camera: Camera;
|
|
25
|
+
gpu: GpuBufferManager;
|
|
26
|
+
private theme;
|
|
27
|
+
private fullStyleRange;
|
|
28
|
+
readonly config: ResolvedGraphConfig;
|
|
29
|
+
private needsUpdate;
|
|
30
|
+
private renderLoopActive;
|
|
31
|
+
_cameraDirty: boolean;
|
|
32
|
+
/** When true, full renders (including slow overlay) are suppressed in favor of WebGL-only draws */
|
|
33
|
+
isInteracting: boolean;
|
|
34
|
+
/** When true, labels are ALWAYS suppressed regardless of zoom level (for layout transitions) */
|
|
35
|
+
isLayoutAnimating: boolean;
|
|
36
|
+
_positionsDirty: boolean;
|
|
37
|
+
private _edgeColorBuf;
|
|
38
|
+
private _transitionProgress;
|
|
39
|
+
/** Global default zoom thresholds for label visibility (overridable per-element). */
|
|
40
|
+
private _labelMinZoom?;
|
|
41
|
+
private _labelMaxZoom?;
|
|
42
|
+
private state;
|
|
43
|
+
private dragOffsets;
|
|
44
|
+
private _lastViewportNodeCount;
|
|
45
|
+
private _viewportCountDirty;
|
|
46
|
+
private _dpr;
|
|
47
|
+
private _contextLost;
|
|
48
|
+
private _destroyed;
|
|
49
|
+
private _disposers;
|
|
50
|
+
private interactionManager;
|
|
51
|
+
spatialIndex: SpatialIndex;
|
|
52
|
+
resolvedNodeStyles: Map<number, ResolvedNodeStyle>;
|
|
53
|
+
resolvedNodeSelectStyles: Map<number, ResolvedNodeSelectStyle>;
|
|
54
|
+
resolvedEdgeStyles: Map<string, ResolvedEdgeStyle>;
|
|
55
|
+
resolvedEdgeSelectStyles: Map<string, ResolvedEdgeSelectStyle>;
|
|
56
|
+
private _lastBackendData;
|
|
57
|
+
constructor(canvas: HTMLCanvasElement, overlayCanvas: HTMLCanvasElement, configOverrides?: PartialGraphConfig);
|
|
58
|
+
destroy(): void;
|
|
59
|
+
attachMinimap(canvas: HTMLCanvasElement, intervalMs?: number): Minimap;
|
|
60
|
+
on<E extends GraphEvent>(event: E, handler: (data: GraphEventPayloadMap[E]) => void): () => void;
|
|
61
|
+
on<T = unknown>(event: string, handler: (data: T) => void): () => void;
|
|
62
|
+
off<E extends GraphEvent>(event: E, handler: (data: GraphEventPayloadMap[E]) => void): void;
|
|
63
|
+
off<T = unknown>(event: string, handler: (data: T) => void): void;
|
|
64
|
+
emitEvent<E extends GraphEvent>(event: E, data?: GraphEventPayloadMap[E]): void;
|
|
65
|
+
emitEvent<T = unknown>(event: string, data?: T): void;
|
|
66
|
+
requestRender(): void;
|
|
67
|
+
private startRenderLoop;
|
|
68
|
+
render(): void;
|
|
69
|
+
/** Shared WebGL clear + LOD + edge + node draw. Called by both render paths. */
|
|
70
|
+
private _drawWebGL;
|
|
71
|
+
/** Fast-path render for layout animations: draws WebGL only, skips the Canvas2D overlay entirely. */
|
|
72
|
+
doRenderWebGLOnly(): void;
|
|
73
|
+
doRender(): void;
|
|
74
|
+
private renderOverlay;
|
|
75
|
+
private handleResize;
|
|
76
|
+
get positions(): Float32Array<ArrayBufferLike> | null;
|
|
77
|
+
setData(positions: Float32Array, colors: Float32Array, ids: Float32Array, metadata: Map<number, NodeMetadata>, edgeIndices?: Uint32Array, edgeMetadata?: Map<string, EdgeMetadata>, nodeIdMap?: Map<string | number, number>): void;
|
|
78
|
+
applyResolvedStyles(): void;
|
|
79
|
+
setStylesheet(sheet: Stylesheet): void;
|
|
80
|
+
get destroyed(): boolean;
|
|
81
|
+
addNode(input: NodeInput): string | number;
|
|
82
|
+
private _findFreePosition;
|
|
83
|
+
updateNode(input: NodeInput): void;
|
|
84
|
+
removeNode(id: string | number): void;
|
|
85
|
+
addEdge(input: EdgeInput): string;
|
|
86
|
+
updateEdge(input: EdgeInput): void;
|
|
87
|
+
removeEdge(id: string): void;
|
|
88
|
+
removeNodes(ids: ReadonlyArray<string | number>): void;
|
|
89
|
+
removeEdges(ids: ReadonlyArray<string>): void;
|
|
90
|
+
getAllNodes(): import('./types').NodeData[];
|
|
91
|
+
getAllEdges(): import('./types').EdgeData[];
|
|
92
|
+
getNode(id: string | number): {
|
|
93
|
+
id: string | number;
|
|
94
|
+
_index: number;
|
|
95
|
+
position: {
|
|
96
|
+
x: number;
|
|
97
|
+
y: number;
|
|
98
|
+
};
|
|
99
|
+
label: string | undefined;
|
|
100
|
+
icon: string | undefined;
|
|
101
|
+
data: Record<string, unknown> | undefined;
|
|
102
|
+
classes: string[] | undefined;
|
|
103
|
+
} | null;
|
|
104
|
+
getNodeMetadata(id: string | number): NodeMetadata | null;
|
|
105
|
+
getEdgeMetadata(id: string): EdgeMetadata | null;
|
|
106
|
+
getNodeId(index: number): string | number | null;
|
|
107
|
+
clear(): void;
|
|
108
|
+
loadData(data: BackendGraphData): void;
|
|
109
|
+
private buildStyleCache;
|
|
110
|
+
recomputeStyles(): void;
|
|
111
|
+
setGraphOptions(patch: Partial<GraphOptions>): void;
|
|
112
|
+
private _nodeIdForIdx;
|
|
113
|
+
private applyNodeSelectStyle;
|
|
114
|
+
private applyNodeDeselectStyle;
|
|
115
|
+
private applyEdgeSelectStyle;
|
|
116
|
+
private applyEdgeDeselectStyle;
|
|
117
|
+
setSelectedEdges(ids: ReadonlyArray<string>): void;
|
|
118
|
+
selectNodes(ids: ReadonlyArray<string | number>): void;
|
|
119
|
+
clearSelection(): void;
|
|
120
|
+
fitView(): void;
|
|
121
|
+
fitToView(): void;
|
|
122
|
+
fitGroupToView(id: string): void;
|
|
123
|
+
zoomIn(): void;
|
|
124
|
+
zoomOut(): void;
|
|
125
|
+
zoomAt(x: number, y: number, d: number): void;
|
|
126
|
+
pan(dx: number, dy: number): void;
|
|
127
|
+
unproject(x: number, y: number): vec2;
|
|
128
|
+
setCameraCenter(x: number, y: number): void;
|
|
129
|
+
setCameraZoom(z: number): void;
|
|
130
|
+
/**
|
|
131
|
+
* Set the global default zoom range for label visibility.
|
|
132
|
+
* Per-element `labelMinZoom` / `labelMaxZoom` on node or edge metadata
|
|
133
|
+
* always take precedence; these are the fallback defaults.
|
|
134
|
+
* Pass `undefined` for either bound to leave it unconstrained.
|
|
135
|
+
*/
|
|
136
|
+
setLabelZoomRange(min?: number, max?: number): void;
|
|
137
|
+
countNodesInViewport(): number;
|
|
138
|
+
createGroup(id: string, lbl: string, ids: (string | number)[]): void;
|
|
139
|
+
removeGroup(id: string): void;
|
|
140
|
+
addToGroup(gid: string, nid: string | number): void;
|
|
141
|
+
removeFromGroup(gid: string, nid: string | number): void;
|
|
142
|
+
toggleComboCollapse(id: string): void;
|
|
143
|
+
moveGroup(id: string, dx: number, dy: number, skipSync?: boolean): void;
|
|
144
|
+
findNodeGroup(id: string | number): string | null;
|
|
145
|
+
getAllGroups(): {
|
|
146
|
+
id: string;
|
|
147
|
+
label: string;
|
|
148
|
+
nodeIds: (string | number)[];
|
|
149
|
+
}[];
|
|
150
|
+
getState(): InteractionState;
|
|
151
|
+
updateInteractionState(update: Partial<InteractionState>): void;
|
|
152
|
+
setTheme(theme: "dark" | "light"): void;
|
|
153
|
+
pick(mouseX: number, mouseY: number): number | null;
|
|
154
|
+
getEdgeAt(mouseX: number, mouseY: number): string | null;
|
|
155
|
+
pickCombo(mouseX: number, mouseY: number, exclude?: Set<number>): string | null;
|
|
156
|
+
pickHUD(mouseX: number, mouseY: number): import('./overlay').HUDAction | null;
|
|
157
|
+
deselectAll(): void;
|
|
158
|
+
selectNode(id: number | null): void;
|
|
159
|
+
lockNode(id: string | number): void;
|
|
160
|
+
unlockNode(id: string | number): void;
|
|
161
|
+
hideNode(id: string | number): void;
|
|
162
|
+
showNode(id: string | number): void;
|
|
163
|
+
isNodeLocked(idx: number): boolean;
|
|
164
|
+
isNodeHidden(idx: number): boolean;
|
|
165
|
+
setNodeColor(id: string | number, r: number, g: number, b: number, a?: number): void;
|
|
166
|
+
hideEdge(edgeId: string): void;
|
|
167
|
+
showEdge(edgeId: string): void;
|
|
168
|
+
/**
|
|
169
|
+
* Toggle (or explicitly set) a node's hidden state. Also updates the
|
|
170
|
+
* underlying `meta.hidden` flag so the property is the source of truth.
|
|
171
|
+
*/
|
|
172
|
+
setNodeHidden(id: string | number, hidden?: boolean): void;
|
|
173
|
+
isNodeHiddenById(id: string | number): boolean;
|
|
174
|
+
/** Toggle (or explicitly set) an edge's hidden state. */
|
|
175
|
+
setEdgeHidden(edgeId: string, hidden?: boolean): void;
|
|
176
|
+
isEdgeHidden(edgeId: string): boolean;
|
|
177
|
+
/** Un-hide every node and edge currently flagged as hidden. */
|
|
178
|
+
showAllHidden(): void;
|
|
179
|
+
/** Toggle (or explicitly set) the visibility of a node's label. */
|
|
180
|
+
setNodeLabelHidden(id: string | number, hidden?: boolean): void;
|
|
181
|
+
isNodeLabelHidden(id: string | number): boolean;
|
|
182
|
+
/** Toggle (or explicitly set) the visibility of an edge's label. */
|
|
183
|
+
setEdgeLabelHidden(edgeId: string, hidden?: boolean): void;
|
|
184
|
+
isEdgeLabelHidden(edgeId: string): boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Choose which property to render as the node's label.
|
|
187
|
+
* Pass a key (e.g. "displayName") to read `meta.data[key]`, or `undefined`
|
|
188
|
+
* to revert to the original `meta.label`.
|
|
189
|
+
*/
|
|
190
|
+
setNodeLabelSource(id: string | number, source?: string): void;
|
|
191
|
+
getNodeLabelSource(id: string | number): string | undefined;
|
|
192
|
+
/** Edge equivalent of `setNodeLabelSource`. */
|
|
193
|
+
setEdgeLabelSource(edgeId: string, source?: string): void;
|
|
194
|
+
reverseEdge(edgeId: string): void;
|
|
195
|
+
setPhantomEdge(sourceNodeId: number, x: number, y: number): void;
|
|
196
|
+
clearPhantomEdge(): void;
|
|
197
|
+
setFlowAnimation(enabled: boolean): void;
|
|
198
|
+
setFlowVelocity(v: number): void;
|
|
199
|
+
setFlowSize(s: number): void;
|
|
200
|
+
setFlowFilter(prop: string | null, value?: unknown): void;
|
|
201
|
+
setFlowConfig(config: Partial<FlowConfig>): void;
|
|
202
|
+
setTransitionState(t: number): void;
|
|
203
|
+
setTargetPositions(t: Float32Array): void;
|
|
204
|
+
updatePositions(p: Float32Array): void;
|
|
205
|
+
setNodePosition(id: number, x: number, y: number): void;
|
|
206
|
+
getNodePosition(id: number): vec2 | null;
|
|
207
|
+
private radialMenuConfigs;
|
|
208
|
+
setRadialMenu(type: "node" | "edge" | "combo", items: RadialMenuItem[]): void;
|
|
209
|
+
getRadialMenu(type: string): RadialMenuItem[];
|
|
210
|
+
syncDragOffsets(mouseX: number, mouseY: number): void;
|
|
211
|
+
private _dragScratch;
|
|
212
|
+
handleDragging(mouseX: number, mouseY: number): void;
|
|
213
|
+
performBoxSelection(): void;
|
|
214
|
+
getInternalIndex(id: string | number): number | null;
|
|
215
|
+
getSelectedUserIds(): (string | number)[];
|
|
216
|
+
removeCombo(id: string): void;
|
|
217
|
+
createCombo(id: string, label: string, nodeIds: (string | number)[]): void;
|
|
218
|
+
updateCombo(id: string, label: string, nodeIds: (string | number)[]): void;
|
|
219
|
+
getCombo(id: string): Combo | undefined;
|
|
220
|
+
addNodeToCombo(comboId: string, nodeId: string | number): void;
|
|
221
|
+
removeNodeFromCombo(comboId: string, nodeId: string | number): void;
|
|
222
|
+
}
|