polly-graph 0.1.15 → 0.2.1

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/dist/index.d.ts CHANGED
@@ -1,42 +1,11 @@
1
1
  import { SimulationNodeDatum, SimulationLinkDatum, Simulation } from 'd3-force';
2
- import { Selection } from 'd3-selection';
2
+ import { ZoomBehavior } from 'd3-zoom';
3
+ import ColorTracker from 'canvas-color-tracker';
3
4
 
4
- interface Coordinates {
5
- readonly x: number;
6
- readonly y: number;
7
- }
8
- type Position = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
9
- type Orientation = 'vertical' | 'horizontal';
10
-
11
- type GraphControlsPosition = Position;
12
- type GraphControlsOrientation = Orientation;
13
- interface GraphControlsConfig {
14
- readonly enabled: boolean;
15
- readonly position?: GraphControlsPosition;
16
- readonly orientation?: GraphControlsOrientation;
17
- readonly offset?: Coordinates;
18
- readonly show?: {
19
- readonly zoomIn?: boolean;
20
- readonly zoomOut?: boolean;
21
- readonly reset?: boolean;
22
- readonly fit?: boolean;
23
- };
24
- }
25
-
26
- interface LegendItem {
27
- label: string;
28
- color: string;
29
- shape?: 'circle' | 'rect';
30
- }
31
- type LegendPosition = Position;
32
- interface LegendConfig {
33
- readonly enabled?: boolean;
34
- readonly title?: string;
35
- readonly position?: LegendPosition;
36
- readonly items?: LegendItem[];
37
- readonly collapsible?: boolean;
38
- readonly defaultExpanded?: boolean;
39
- }
5
+ /**
6
+ * Shared Graph Types
7
+ * Core interfaces used by both V1 (SVG) and V2 (Canvas) implementations
8
+ */
40
9
 
41
10
  interface GraphNode extends SimulationNodeDatum {
42
11
  readonly id: string;
@@ -45,6 +14,10 @@ interface GraphNode extends SimulationNodeDatum {
45
14
  readonly tooltip?: string;
46
15
  readonly style?: NodeStyle;
47
16
  }
17
+ interface GraphNodeWithInitial extends GraphNode {
18
+ initialX?: number;
19
+ initialY?: number;
20
+ }
48
21
  interface GraphLink extends SimulationLinkDatum<GraphNode> {
49
22
  readonly source: string | GraphNode;
50
23
  readonly target: string | GraphNode;
@@ -112,78 +85,206 @@ interface ResolvedLinkStyle {
112
85
  readonly label: ResolvedLinkLabelStyle;
113
86
  }
114
87
 
115
- interface LinkForceConfig {
116
- readonly enabled?: boolean;
117
- readonly distance?: number | ((link: GraphLink) => number);
118
- readonly strength?: number | ((link: GraphLink) => number);
119
- readonly iterations?: number;
88
+ /**
89
+ * V2 Canvas Graph - Render Style Types
90
+ *
91
+ * Canvas-optimized style interfaces for high-performance rendering
92
+ */
93
+
94
+ interface NodeLabelRenderStyle {
95
+ enabled: boolean;
96
+ font: string;
97
+ textColor: string;
98
+ textAlign: string;
99
+ textBaseline: string;
100
+ offsetY: number;
120
101
  }
121
- interface ChargeForceConfig {
122
- readonly enabled?: boolean;
123
- readonly strength?: number | ((node: GraphNode) => number);
124
- readonly theta?: number;
125
- readonly distanceMin?: number;
126
- readonly distanceMax?: number;
102
+ interface NodeRenderStyle {
103
+ fill: string;
104
+ stroke: string;
105
+ strokeWidth: number;
106
+ radius: number;
107
+ opacity: number;
108
+ textColor?: string;
109
+ label?: NodeLabelRenderStyle;
127
110
  }
128
- interface CollideForceConfig {
129
- readonly enabled?: boolean;
130
- readonly radius?: number | ((node: GraphNode) => number);
131
- readonly strength?: number;
132
- readonly iterations?: number;
111
+ interface LinkLabelRenderStyle {
112
+ enabled?: boolean;
113
+ visibility?: 'always' | 'hover' | 'selection';
114
+ text?: string;
115
+ font?: string;
116
+ textColor?: string;
117
+ backgroundColor?: string;
118
+ borderColor?: string;
119
+ borderWidth?: number;
120
+ borderRadius?: number;
121
+ paddingX?: number;
122
+ paddingY?: number;
133
123
  }
134
- interface CenterForceConfig {
135
- readonly enabled?: boolean;
136
- readonly strength?: number;
137
- readonly x?: number;
138
- readonly y?: number;
124
+ interface LinkRenderStyle {
125
+ stroke: string;
126
+ strokeWidth: number;
127
+ opacity: number;
128
+ arrow?: LinkArrowStyle;
129
+ label?: LinkLabelRenderStyle;
139
130
  }
140
- interface XForceConfig {
141
- readonly enabled?: boolean;
142
- readonly strength?: number;
143
- readonly x?: number | ((node: GraphNode) => number);
131
+ type ArrowRenderStyle = LinkArrowStyle;
132
+ interface HoverStyles {
133
+ readonly node: Partial<NodeRenderStyle>;
134
+ readonly link: Partial<LinkRenderStyle>;
144
135
  }
145
- interface YForceConfig {
146
- readonly enabled?: boolean;
147
- readonly strength?: number;
148
- readonly y?: number | ((node: GraphNode) => number);
149
- }
150
- interface SimulationForces {
151
- readonly link?: LinkForceConfig;
152
- readonly charge?: ChargeForceConfig;
153
- readonly collide?: CollideForceConfig;
154
- readonly center?: CenterForceConfig;
155
- readonly x?: XForceConfig;
156
- readonly y?: YForceConfig;
157
- }
158
- interface AdaptiveConfig {
159
- readonly enabled?: boolean;
160
- readonly nodeCountThresholds?: {
161
- readonly small?: number;
162
- readonly medium?: number;
163
- readonly large?: number;
164
- };
136
+ interface RenderStyles {
137
+ readonly node: Partial<NodeRenderStyle>;
138
+ readonly link: Partial<LinkRenderStyle>;
139
+ readonly hover: HoverStyles;
165
140
  }
166
- interface WarmupConfig {
167
- readonly enabled?: boolean;
168
- readonly ticks?: number;
141
+ interface CanvasRenderConfig {
142
+ readonly devicePixelRatio?: number;
143
+ readonly antialias?: boolean;
144
+ readonly alpha?: boolean;
169
145
  }
170
- interface CooldownConfig {
171
- readonly enabled?: boolean;
172
- readonly delay?: number;
146
+ declare const DEFAULT_LINK_LABEL_STYLE: LinkLabelRenderStyle;
147
+ declare const DEFAULT_LINK_STYLE: LinkRenderStyle;
148
+ declare const DEFAULT_HOVER_STYLES: HoverStyles;
149
+ declare function isValidNodeStyle(style: unknown): style is Partial<NodeRenderStyle>;
150
+ declare function isValidLinkStyle(style: unknown): style is Partial<LinkRenderStyle>;
151
+ declare function mergeNodeStyle(base: NodeRenderStyle, override?: Partial<NodeRenderStyle>): NodeRenderStyle;
152
+ declare function mergeLinkStyle(base: LinkRenderStyle, override?: Partial<LinkRenderStyle>): LinkRenderStyle;
153
+
154
+ interface StatsMetrics {
155
+ renderTotal: number;
156
+ renderNodes: number;
157
+ renderLinks: number;
158
+ renderLinkLabels: number;
159
+ renderNodeLabels: number;
160
+ styleResolution: number;
161
+ hoverChecks: number;
162
+ canvasCalls: number;
163
+ frameCount: number;
173
164
  }
174
- interface EnhancedSimulationConfig {
175
- readonly alpha?: number;
176
- readonly alphaMin?: number;
177
- readonly alphaDecay?: number;
178
- readonly velocityDecay?: number;
179
- readonly forces?: SimulationForces;
180
- readonly adaptive?: AdaptiveConfig;
181
- readonly warmup?: WarmupConfig;
182
- readonly cooldown?: CooldownConfig;
165
+
166
+ /**
167
+ * Color constants for polly-graph library
168
+ */
169
+ declare enum PrimaryColor {
170
+ PURPLE = "#8E42EE",
171
+ ORANGE = "#F78E12",
172
+ PINK = "#EC4899",
173
+ CYAN = "#06B6D4",
174
+ RED = "#FF004D",
175
+ BLUE = "#3C5DE2",
176
+ GREEN = "#24CF35",
177
+ YELLOW = "#F7E217"
178
+ }
179
+ declare enum SecondaryColor {
180
+ PURPLE = "#936DC3",
181
+ ORANGE = "#D98C30",
182
+ PINK = "#D85C99",
183
+ CYAN = "#21A3B9",
184
+ RED = "#CC3361",
185
+ BLUE = "#6173BD"
186
+ }
187
+ declare enum NeutralColor {
188
+ PURPLE = "#968AA6",
189
+ ORANGE = "#A18768",
190
+ PINK = "#AF859A",
191
+ CYAN = "#3A91A0",
192
+ RED = "#9F6073",
193
+ BLUE = "#7A82A4"
194
+ }
195
+ declare enum StandardColor {
196
+ WHITE = "#ffffff",
197
+ BLACK = "#000000",
198
+ NEUTRAL = "#808080"
199
+ }
200
+
201
+ /**
202
+ * Shared Constants - Polly Graph
203
+ * Colors, themes, and other constants used across V1, V2, and demo
204
+ */
205
+
206
+ declare const DEFAULT_COLORS: {
207
+ readonly nodes: readonly [PrimaryColor.BLUE, PrimaryColor.ORANGE, PrimaryColor.GREEN, PrimaryColor.RED, PrimaryColor.PURPLE, SecondaryColor.ORANGE, PrimaryColor.PINK, NeutralColor.BLUE, PrimaryColor.YELLOW, PrimaryColor.CYAN];
208
+ readonly links: {
209
+ readonly default: NeutralColor.BLUE;
210
+ readonly hover: SecondaryColor.BLUE;
211
+ readonly selected: PrimaryColor.BLUE;
212
+ };
213
+ readonly interaction: {
214
+ readonly nodeHover: PrimaryColor.PINK;
215
+ readonly nodeSelected: PrimaryColor.CYAN;
216
+ readonly linkHover: PrimaryColor.PINK;
217
+ readonly linkSelected: PrimaryColor.CYAN;
218
+ };
219
+ readonly ui: {
220
+ readonly background: StandardColor.WHITE;
221
+ readonly text: StandardColor.BLACK;
222
+ readonly border: NeutralColor.BLUE;
223
+ readonly shadow: NeutralColor.PURPLE;
224
+ };
225
+ };
226
+ type NodeColorPalette = typeof DEFAULT_COLORS.nodes;
227
+ type LinkColors = typeof DEFAULT_COLORS.links;
228
+ type InteractionColors = typeof DEFAULT_COLORS.interaction;
229
+ type UIColors = typeof DEFAULT_COLORS.ui;
230
+
231
+ /**
232
+ * Shared Icons - Polly Graph UI Icons
233
+ * Consolidated icons used across V1, V2, and demo
234
+ */
235
+ declare const icons: {
236
+ readonly fit: string;
237
+ readonly reset: string;
238
+ readonly plus: string;
239
+ readonly minus: string;
240
+ readonly caret: string;
241
+ };
242
+ declare const iconSvg: {
243
+ readonly fit: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M5 9V5H9\" />\n <path d=\"M19 9V5H15\" />\n <path d=\"M5 15V19H9\" />\n <path d=\"M19 15V19H15\" />\n </svg>";
244
+ readonly reset: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M20 12a8 8 0 1 1-2.3-5.7\" />\n <path d=\"M20 4.5v4h-4\" />\n </svg>";
245
+ readonly plus: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M5 12h14m-7-7v14\" />\n </svg>";
246
+ readonly minus: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M5 12h14\" />\n </svg>";
247
+ readonly caret: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M6 9l6 6 6-6\" />\n </svg>";
248
+ };
249
+ type IconName = keyof typeof icons;
250
+ type IconSvgName = keyof typeof iconSvg;
251
+ declare function getIcon(name: IconName): string;
252
+ declare function getIconSvg(name: IconSvgName): string;
253
+
254
+ /**
255
+ * Shared Graph Controls Interface
256
+ * Used by both V1 and V2 implementations
257
+ */
258
+ interface Coordinates {
259
+ readonly x: number;
260
+ readonly y: number;
261
+ }
262
+ type Position = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
263
+ type Orientation = 'vertical' | 'horizontal';
264
+ type GraphControlsPosition = Position;
265
+ type GraphControlsOrientation = Orientation;
266
+ interface GraphControlsConfig {
267
+ readonly enabled: boolean;
268
+ readonly position?: GraphControlsPosition;
269
+ readonly orientation?: GraphControlsOrientation;
270
+ readonly offset?: Coordinates;
271
+ readonly show?: {
272
+ readonly zoomIn?: boolean;
273
+ readonly zoomOut?: boolean;
274
+ readonly reset?: boolean;
275
+ readonly fit?: boolean;
276
+ };
183
277
  }
184
278
 
279
+ /**
280
+ * Shared Graph Configuration Interfaces
281
+ * Core configuration used by both V1 (SVG) and V2 (Canvas) implementations
282
+ */
283
+
185
284
  type GraphTooltipTheme = 'dark' | 'light';
186
285
  type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right' | 'auto';
286
+ type NodeSelectHandler = (node: GraphNode, element?: HTMLElement) => void;
287
+ type LinkSelectHandler = (link: GraphLink, element?: HTMLElement) => void;
187
288
  interface TooltipInteractionConfig {
188
289
  readonly enabled?: boolean;
189
290
  readonly theme?: GraphTooltipTheme;
@@ -210,426 +311,1161 @@ interface GraphInteractionConfig {
210
311
  readonly hover?: HoverInteractionConfig;
211
312
  readonly selection?: SelectionInteractionConfig;
212
313
  }
213
- interface GraphConfig {
314
+
315
+ type LegendPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
316
+ interface LegendConfig {
317
+ readonly enabled?: boolean;
318
+ readonly position?: LegendPosition;
319
+ readonly collapsible?: boolean;
320
+ readonly defaultExpanded?: boolean;
321
+ readonly offset?: {
322
+ readonly x: number;
323
+ readonly y: number;
324
+ };
325
+ }
326
+ interface SimulationConfig {
327
+ readonly alphaDecay?: number;
328
+ readonly velocityDecay?: number;
329
+ readonly forces?: Record<string, unknown>;
330
+ }
331
+ interface BaseGraphConfig {
214
332
  readonly container: HTMLElement;
215
333
  readonly nodes: GraphNode[];
216
334
  readonly links: GraphLink[];
217
335
  readonly autoFit?: boolean;
218
336
  readonly responsive?: boolean;
219
- readonly simulation?: EnhancedSimulationConfig;
337
+ readonly simulation?: SimulationConfig;
220
338
  readonly interaction?: GraphInteractionConfig;
221
339
  readonly controls?: GraphControlsConfig;
222
340
  readonly legend?: LegendConfig;
223
341
  }
342
+ interface ControlsController {
343
+ mount(): void;
344
+ destroy(): void;
345
+ }
346
+
347
+ /**
348
+ * V2 Canvas Graph - Type Definitions
349
+ */
224
350
 
225
- interface GraphInstance {
351
+ interface V2Node extends SimulationNodeDatum {
352
+ id: string;
353
+ entityType: 'Node';
354
+ type: string;
355
+ label?: string;
356
+ tooltip?: string;
357
+ x?: number;
358
+ y?: number;
359
+ fx?: number | null;
360
+ fy?: number | null;
361
+ vx?: number;
362
+ vy?: number;
363
+ style?: Partial<NodeRenderStyle>;
364
+ __indexColor?: string;
365
+ __indexColorRGB?: [number, number, number];
366
+ }
367
+ interface V2Link extends SimulationLinkDatum<V2Node> {
368
+ source: string | V2Node;
369
+ target: string | V2Node;
370
+ entityType: 'Link';
371
+ label?: string;
372
+ tooltip?: string;
373
+ style?: Partial<LinkRenderStyle>;
374
+ __indexColor?: string;
375
+ __indexColorRGB?: [number, number, number];
376
+ }
377
+ interface InteractionConfig {
378
+ readonly hover?: HoverInteractionConfig;
379
+ readonly selection?: SelectionInteractionConfig;
380
+ }
381
+ interface V2Config {
382
+ container: HTMLElement;
383
+ nodes: V2Node[];
384
+ links: V2Link[];
385
+ width?: number;
386
+ height?: number;
387
+ backgroundColor?: string;
388
+ interaction?: InteractionConfig;
389
+ controls?: GraphControlsConfig;
390
+ legend?: LegendConfig;
391
+ autoFitView?: boolean;
392
+ cooldownTime?: number;
393
+ }
394
+ interface V2Instance {
226
395
  render(): void;
227
- zoomIn(): void;
228
- zoomOut(): void;
229
- resetView(): void;
230
- fitView(): void;
231
396
  destroy(): void;
232
- exportGraph(fileName?: string): void;
397
+ testZoom(): {
398
+ scale: number;
399
+ x: number;
400
+ y: number;
401
+ };
402
+ getZoomBehavior(): ZoomBehavior<HTMLCanvasElement, unknown> | undefined;
403
+ getCanvas(): HTMLCanvasElement;
404
+ fitView(): Promise<void>;
405
+ resetView(): void;
406
+ zoomIn(factor?: number, center?: [number, number]): void;
407
+ zoomOut(factor?: number, center?: [number, number]): void;
233
408
  clearSelection(): void;
234
- on(event: 'nodeSelect', handler: (node: GraphNode, element: SVGCircleElement) => void): () => void;
235
- on(event: 'nodeDeselect', handler: (node: GraphNode, element: SVGCircleElement) => void): () => void;
236
- on(event: 'linkSelect', handler: (link: GraphLink, element: SVGLineElement) => void): () => void;
237
- on(event: 'linkDeselect', handler: (link: GraphLink, element: SVGLineElement) => void): () => void;
238
- off(event: 'nodeSelect', handler: (node: GraphNode, element: SVGCircleElement) => void): void;
239
- off(event: 'nodeDeselect', handler: (node: GraphNode, element: SVGCircleElement) => void): void;
240
- off(event: 'linkSelect', handler: (link: GraphLink, element: SVGLineElement) => void): void;
241
- off(event: 'linkDeselect', handler: (link: GraphLink, element: SVGLineElement) => void): void;
409
+ on(event: 'nodeSelect', handler: (node: V2Node, element: HTMLCanvasElement) => void): () => void;
410
+ on(event: 'nodeDeselect', handler: (node: V2Node, element: HTMLCanvasElement) => void): () => void;
411
+ on(event: 'linkSelect', handler: (link: V2Link, element: HTMLCanvasElement) => void): () => void;
412
+ on(event: 'linkDeselect', handler: (link: V2Link, element: HTMLCanvasElement) => void): () => void;
413
+ on(event: 'nodeHover', handler: (node: V2Node, element: HTMLCanvasElement) => void): () => void;
414
+ on(event: 'nodeUnhover', handler: (node: V2Node, element: HTMLCanvasElement) => void): () => void;
415
+ on(event: 'linkHover', handler: (link: V2Link, element: HTMLCanvasElement) => void): () => void;
416
+ on(event: 'linkUnhover', handler: (link: V2Link, element: HTMLCanvasElement) => void): () => void;
417
+ off(event: 'nodeSelect', handler: (node: V2Node, element: HTMLCanvasElement) => void): void;
418
+ off(event: 'nodeDeselect', handler: (node: V2Node, element: HTMLCanvasElement) => void): void;
419
+ off(event: 'linkSelect', handler: (link: V2Link, element: HTMLCanvasElement) => void): void;
420
+ off(event: 'linkDeselect', handler: (link: V2Link, element: HTMLCanvasElement) => void): void;
421
+ off(event: 'nodeHover', handler: (node: V2Node, element: HTMLCanvasElement) => void): void;
422
+ off(event: 'nodeUnhover', handler: (node: V2Node, element: HTMLCanvasElement) => void): void;
423
+ off(event: 'linkHover', handler: (link: V2Link, element: HTMLCanvasElement) => void): void;
424
+ off(event: 'linkUnhover', handler: (link: V2Link, element: HTMLCanvasElement) => void): void;
425
+ exportGraph(fileName?: string): Promise<void>;
426
+ getPerformanceMetrics(): StatsMetrics;
427
+ logPerformanceMetrics(): void;
428
+ resetPerformanceMetrics(): void;
242
429
  }
243
430
 
244
431
  /**
245
- * Main Graph Factory - Creates and manages a graph instance
246
- *
247
- * Clean modular architecture:
248
- * - GraphManager: State management and coordination
249
- * - RenderPipeline: Rendering workflow
250
- * - InteractionManager: User interactions
432
+ * V2 Canvas Graph - Error Handling
251
433
  */
252
- declare function createGraph(config: GraphConfig): GraphInstance;
253
434
 
435
+ type ErrorContext = Record<string, unknown>;
436
+ declare class V2GraphError extends Error {
437
+ code: string;
438
+ context?: ErrorContext | undefined;
439
+ constructor(message: string, code: string, context?: ErrorContext | undefined);
440
+ }
441
+ declare class ValidationError extends V2GraphError {
442
+ constructor(message: string, context?: ErrorContext);
443
+ }
254
444
  /**
255
- * Comprehensive validation system for framework-independent graph configuration.
256
- * Provides runtime validation to catch integration errors early.
445
+ * Error handler utility functions
257
446
  */
447
+ declare const ErrorHandler: {
448
+ /**
449
+ * Validates container element
450
+ */
451
+ validateContainer(container: unknown): HTMLElement;
452
+ /**
453
+ * Validates nodes array
454
+ */
455
+ validateNodes(nodes: unknown): V2Node[];
456
+ /**
457
+ * Validates links array
458
+ */
459
+ validateLinks(links: unknown): V2Link[];
460
+ /**
461
+ * Safe canvas context getter with error handling
462
+ */
463
+ getCanvasContext(canvas: HTMLCanvasElement, type: "2d"): CanvasRenderingContext2D;
464
+ /**
465
+ * Safely handles async operations with error recovery
466
+ */
467
+ withRetry<T>(operation: () => T | Promise<T>, maxRetries?: number, delay?: number): Promise<T>;
468
+ /**
469
+ * Logs errors with context in development
470
+ */
471
+ logError(error: Error, context?: ErrorContext): void;
472
+ };
258
473
 
259
- interface ValidationError {
260
- readonly field: string;
261
- readonly message: string;
262
- readonly value: unknown;
263
- readonly code: string;
264
- }
265
- interface ValidationResult {
266
- readonly isValid: boolean;
267
- readonly errors: ValidationError[];
268
- readonly warnings: string[];
269
- }
270
- declare class GraphValidator {
474
+ /**
475
+ * V2 Timer Management - Copied from V1
476
+ * Centralized timer management for framework-independent graph operations.
477
+ * Provides better cleanup and prevents memory leaks across all frameworks.
478
+ */
479
+ declare class TimerManager {
480
+ private readonly activeTimers;
481
+ private isDestroyed;
482
+ /**
483
+ * Schedule a timeout with automatic cleanup tracking
484
+ */
485
+ setTimeout(name: string, callback: () => void, delay: number): void;
486
+ /**
487
+ * Schedule an interval with automatic cleanup tracking
488
+ */
489
+ setInterval(name: string, callback: () => void, delay: number): void;
271
490
  /**
272
- * Validate complete graph configuration
491
+ * Clear a specific timer by name
273
492
  */
274
- static validateConfig(config: GraphConfig): ValidationResult;
493
+ clearTimer(name: string): boolean;
275
494
  /**
276
- * Validate container element
495
+ * Check if a timer is currently active
277
496
  */
278
- private static validateContainer;
497
+ hasActiveTimer(name: string): boolean;
279
498
  /**
280
- * Validate graph nodes
499
+ * Get information about active timers
281
500
  */
282
- private static validateNodes;
501
+ getActiveTimers(): Array<{
502
+ name: string;
503
+ type: string;
504
+ age: number;
505
+ }>;
283
506
  /**
284
- * Validate graph links
507
+ * Debounced execution - only runs the latest call after delay
285
508
  */
286
- private static validateLinks;
509
+ debounce(name: string, callback: () => void, delay: number): void;
287
510
  /**
288
- * Validate interaction configuration
511
+ * Throttled execution - limits frequency of execution
289
512
  */
290
- private static validateInteraction;
513
+ throttle(name: string, callback: () => void, delay: number): void;
291
514
  /**
292
- * Validate node style
515
+ * Clear all timers and prevent new ones from being created
293
516
  */
294
- private static validateNodeStyle;
517
+ destroy(): void;
295
518
  /**
296
- * Validate runtime environment
519
+ * Reset manager (clear all timers but allow new ones)
297
520
  */
298
- static validateEnvironment(): ValidationResult;
521
+ reset(): void;
522
+ /**
523
+ * Get count of active timers
524
+ */
525
+ getActiveTimerCount(): number;
299
526
  }
527
+
300
528
  /**
301
- * Validation error for framework integrations
529
+ * V2 Canvas Graph - Canvas Manager
530
+ *
531
+ * Manages canvas creation, setup, and lifecycle
302
532
  */
303
- declare class GraphValidationError extends Error {
304
- readonly errors: ValidationError[];
305
- readonly warnings: string[];
306
- constructor(result: ValidationResult);
533
+
534
+ interface CanvasState {
535
+ canvas: HTMLCanvasElement;
536
+ shadowCanvas: HTMLCanvasElement;
537
+ ctx: CanvasRenderingContext2D;
538
+ shadowCtx: CanvasRenderingContext2D;
539
+ colorTracker: ColorTracker;
540
+ width: number;
541
+ height: number;
542
+ }
543
+ declare class CanvasManager {
544
+ private state?;
545
+ private resizeCleanup?;
546
+ private resizeCallback?;
547
+ /**
548
+ * Initialize canvas system
549
+ */
550
+ initialize(config: V2Config): CanvasState;
551
+ /**
552
+ * Get current canvas state
553
+ */
554
+ getState(): CanvasState;
555
+ /**
556
+ * Clear both canvases
557
+ */
558
+ clear(): void;
559
+ /**
560
+ * Apply transform to both canvases
561
+ */
562
+ applyTransform(transform: {
563
+ x: number;
564
+ y: number;
565
+ k: number;
566
+ }): void;
567
+ /**
568
+ * Setup resize observer for responsive canvas
569
+ * Following force-graph patterns for container-driven resizing
570
+ */
571
+ setupResize(container: HTMLElement, onResize?: (width: number, height: number) => void): void;
572
+ /**
573
+ * Resize canvas to new dimensions
574
+ * Following force-graph's adjustCanvasSize pattern with device pixel ratio scaling
575
+ */
576
+ resizeCanvas(width: number, height: number): void;
577
+ /**
578
+ * Get current canvas dimensions
579
+ */
580
+ getDimensions(): {
581
+ width: number;
582
+ height: number;
583
+ };
584
+ /**
585
+ * Destroy canvas system
586
+ */
587
+ destroy(): void;
588
+ /**
589
+ * Get canvas statistics
590
+ */
591
+ getStats(): {
592
+ dimensions: {
593
+ width: number;
594
+ height: number;
595
+ };
596
+ colorTracker: ColorTracker;
597
+ devicePixelRatio: number;
598
+ };
307
599
  }
308
600
 
309
601
  /**
310
- * Centralized error handling for framework-independent graph operations.
311
- * Provides graceful degradation and helpful error messages.
602
+ * V2 Canvas Graph - Physics Manager
603
+ *
604
+ * Manages D3 force simulation lifecycle and behavior
312
605
  */
313
606
 
314
- interface ErrorContext {
315
- readonly operation: string;
316
- readonly component?: string;
317
- readonly data?: unknown;
607
+ interface PhysicsConfig {
608
+ nodes: V2Node[];
609
+ links: V2Link[];
610
+ width: number;
611
+ height: number;
612
+ onTick: () => void;
613
+ onEnd?: () => void;
614
+ autoFitView?: boolean;
615
+ cooldownTime?: number;
318
616
  }
319
- declare class GraphError extends Error {
320
- readonly code: string;
321
- readonly context: ErrorContext;
322
- readonly recoverable: boolean;
323
- constructor(message: string, code: string, context: ErrorContext, recoverable?: boolean);
324
- }
325
- declare class ErrorHandler {
326
- private static isDestroyed;
617
+ declare class PhysicsManager {
618
+ private simulation?;
619
+ private config?;
620
+ private simulationStartTime?;
621
+ private simulationEndTime?;
622
+ private cooldownTimer?;
623
+ private hasInitialAutoFitCompleted;
624
+ private timerManager;
625
+ constructor(timerManager: TimerManager);
626
+ /**
627
+ * Initialize physics simulation
628
+ */
629
+ initialize(config: PhysicsConfig): void;
630
+ /**
631
+ * Handle simulation end
632
+ */
633
+ private handleSimulationEnd;
634
+ /**
635
+ * Check if initial auto-fitview should happen and mark it as completed
636
+ */
637
+ shouldDoInitialAutoFitView(): boolean;
327
638
  /**
328
- * Handle errors with appropriate logging and recovery
639
+ * Setup cooldown timer (force-graph pattern)
329
640
  */
330
- static handle(error: Error, context: ErrorContext, fallback?: () => void): void;
641
+ private setupCooldownTimer;
331
642
  /**
332
- * Wrap async operations with error handling
643
+ * Get simulation instance
333
644
  */
334
- static wrapAsync<T>(operation: () => Promise<T>, context: ErrorContext, fallback?: () => T): Promise<T>;
645
+ getSimulation(): Simulation<V2Node, V2Link>;
335
646
  /**
336
- * Wrap synchronous operations with error handling
647
+ * Reheat simulation for drag interactions
337
648
  */
338
- static wrap<T>(operation: () => T, context: ErrorContext, fallback?: () => T): T | undefined;
649
+ reheat(alphaTarget?: number): void;
339
650
  /**
340
- * Safe DOM operation wrapper
651
+ * Cool down simulation
341
652
  */
342
- static safeDOMOperation<T>(operation: () => T, context: ErrorContext, fallback?: () => T): T | undefined;
653
+ cooldown(): void;
343
654
  /**
344
- * Safe D3 operation wrapper
655
+ * Update force parameters
345
656
  */
346
- static safeD3Operation<T>(operation: () => T, context: ErrorContext, fallback?: () => T): T | undefined;
657
+ updateForces(options: {
658
+ linkStrength?: number;
659
+ chargeStrength?: number;
660
+ centerStrength?: number;
661
+ linkDistance?: number | ((link: V2Link) => number);
662
+ }): void;
347
663
  /**
348
- * Create recoverable error for non-critical failures
664
+ * Update center force position for new canvas dimensions
665
+ * Following force-graph pattern for container resizing
349
666
  */
350
- static createRecoverableError(message: string, code: string, context: ErrorContext): GraphError;
667
+ updateCenterForce(x: number, y: number): void;
351
668
  /**
352
- * Create non-recoverable error for critical failures
669
+ * Adjust link distances to account for visual shortening
353
670
  */
354
- static createCriticalError(message: string, code: string, context: ErrorContext): GraphError;
671
+ adjustLinkDistancesForVisualShortening(): void;
355
672
  /**
356
- * Validate and handle D3 selection operations
673
+ * Calculate base distance based on graph size and node count
357
674
  */
358
- static validateSelection<T extends {
359
- size(): number;
360
- }>(selection: T | null | undefined, context: ErrorContext, operation: (sel: T) => void): void;
675
+ private calculateBaseDistance;
361
676
  /**
362
- * Handle simulation errors with graceful degradation
677
+ * Find node by ID
363
678
  */
364
- static handleSimulationError(error: Error, context: ErrorContext, simulation?: Simulation<GraphNode, GraphLink>): void;
679
+ private findNodeById;
365
680
  /**
366
- * Mark error handler as destroyed to prevent further operations
681
+ * Get node radius from style or default
367
682
  */
368
- static destroy(): void;
683
+ private getNodeRadius;
369
684
  /**
370
- * Reset error handler state
685
+ * Get arrow length from link style or default
371
686
  */
372
- static reset(): void;
687
+ private getLinkArrowLength;
688
+ /**
689
+ * Initialize node positions if not set
690
+ */
691
+ initializePositions(): void;
692
+ /**
693
+ * Stop simulation
694
+ */
695
+ stop(): void;
696
+ /**
697
+ * Get simulation timing information
698
+ */
699
+ getSimulationTiming(): {
700
+ startTime?: number;
701
+ endTime?: number;
702
+ duration?: number;
703
+ isRunning: boolean;
704
+ elapsed: number;
705
+ };
706
+ /**
707
+ * Check if simulation is currently running
708
+ */
709
+ isSimulationRunning(): boolean;
710
+ /**
711
+ * Pause the simulation
712
+ */
713
+ pause(): void;
714
+ /**
715
+ * Resume the simulation
716
+ */
717
+ resume(): void;
718
+ /**
719
+ * Destroy physics simulation
720
+ */
721
+ destroy(): void;
722
+ }
723
+
724
+ interface PointerState {
725
+ x: number;
726
+ y: number;
727
+ }
728
+ declare class PointerManager {
729
+ initialize(): void;
730
+ destroy(): void;
731
+ testHitDetection(): null;
373
732
  }
374
733
 
375
734
  /**
376
- * Framework-independent event emitter for graph events.
377
- * Provides better TypeScript support and event namespacing than manual Set management.
735
+ * V2 Canvas Graph - Hover Manager (Force-Graph Pattern)
736
+ *
737
+ * Exact replication of force-graph's hover detection mechanism
378
738
  */
379
739
 
380
- type EventListener<T> = (data: T, element?: Element) => void;
381
- interface EventUnsubscribe {
382
- (): void;
740
+ interface HoverState {
741
+ currentHovered: {
742
+ type: 'Node' | 'Link';
743
+ d: V2Node | V2Link;
744
+ } | null;
745
+ previousHovered: {
746
+ type: 'Node' | 'Link';
747
+ d: V2Node | V2Link;
748
+ } | null;
749
+ pointerPosition: {
750
+ x: number;
751
+ y: number;
752
+ } | null;
753
+ isDragging: boolean;
383
754
  }
384
- interface EventEmitterOptions {
385
- readonly maxListeners?: number;
386
- readonly enableWarnings?: boolean;
755
+ interface HoverEvent {
756
+ type: 'nodeHover' | 'nodeUnhover' | 'linkHover' | 'linkUnhover';
757
+ current: V2Node | V2Link | null;
758
+ previous: V2Node | V2Link | null;
387
759
  }
388
- declare class GraphEventEmitter<TEventMap extends Record<string, unknown>> {
389
- private readonly listeners;
390
- private readonly options;
391
- private isDestroyed;
392
- private listenerIdCounter;
393
- constructor(options?: EventEmitterOptions);
760
+ declare class HoverManager {
761
+ private canvasState?;
762
+ private hoverState;
763
+ private eventHandlers;
764
+ private container?;
765
+ private refreshShadowCanvas?;
766
+ private flushShadowCanvas?;
767
+ private hasValidPointerPosition;
768
+ private containerWarningLogged;
394
769
  /**
395
- * Add an event listener
770
+ * Initialize hover manager with force-graph pattern
396
771
  */
397
- on<TEvent extends keyof TEventMap>(event: TEvent, listener: EventListener<TEventMap[TEvent]>, namespace?: string): EventUnsubscribe;
772
+ initialize(canvasState: CanvasState): void;
398
773
  /**
399
- * Add a one-time event listener
774
+ * Setup pointer position tracking (exact force-graph pattern)
400
775
  */
401
- once<TEvent extends keyof TEventMap>(event: TEvent, listener: EventListener<TEventMap[TEvent]>, namespace?: string): EventUnsubscribe;
776
+ private setupPointerTracking;
402
777
  /**
403
- * Remove a specific listener
778
+ * Get element offset (force-graph lines 544-549)
404
779
  */
405
- off<TEvent extends keyof TEventMap>(event: TEvent, listener: EventListener<TEventMap[TEvent]>): void;
780
+ private getOffset;
406
781
  /**
407
- * Remove listener by ID
782
+ * Setup shadow canvas throttling (force-graph pattern lines 598-609)
408
783
  */
409
- private removeListener;
784
+ private setupShadowCanvasThrottling;
410
785
  /**
411
- * Remove all listeners for an event or namespace
786
+ * Render shadow canvas for hit detection
412
787
  */
413
- removeAllListeners<TEvent extends keyof TEventMap>(event?: TEvent, namespace?: string): void;
788
+ private renderShadowCanvas;
414
789
  /**
415
- * Emit an event to all listeners
790
+ * Get object under pointer (exact force-graph pattern lines 386-395)
416
791
  */
417
- emit<TEvent extends keyof TEventMap>(event: TEvent, data: TEventMap[TEvent], element?: Element): boolean;
792
+ getObjUnderPointer(): {
793
+ type: 'Node' | 'Link';
794
+ d: V2Node | V2Link;
795
+ } | null;
418
796
  /**
419
- * Get the number of listeners for an event
797
+ * Compare two hover objects for equality
420
798
  */
421
- listenerCount<TEvent extends keyof TEventMap>(event: TEvent): number;
799
+ private isSameHoverObject;
422
800
  /**
423
- * Get all event names that have listeners
801
+ * Update hover state (force-graph pattern lines 618-646)
424
802
  */
425
- eventNames(): Array<keyof TEventMap>;
803
+ updateHover(): void;
426
804
  /**
427
- * Get listeners for an event
805
+ * Set dragging state (to disable hover during drag)
428
806
  */
429
- getListeners<TEvent extends keyof TEventMap>(event: TEvent): Array<EventListener<TEventMap[TEvent]>>;
807
+ setDragging(isDragging: boolean): void;
430
808
  /**
431
- * Check if an event has listeners
809
+ * Update cursor based on hover state
432
810
  */
433
- hasListeners<TEvent extends keyof TEventMap>(event: TEvent): boolean;
811
+ private updateCursor;
434
812
  /**
435
- * Get debug information about the emitter
813
+ * Get current hover state
436
814
  */
437
- getDebugInfo(): {
438
- totalEvents: number;
439
- totalListeners: number;
440
- events: {
441
- [k: string]: number;
442
- };
443
- namespaces: {
444
- [k: string]: number;
445
- };
446
- isDestroyed: boolean;
447
- };
815
+ getHoverState(): HoverState;
816
+ /**
817
+ * Add event listener
818
+ */
819
+ on(event: string, handler: (event: HoverEvent) => void): void;
820
+ /**
821
+ * Remove event listener
822
+ */
823
+ off(event: string, handler: (event: HoverEvent) => void): void;
824
+ /**
825
+ * Emit event to all listeners
826
+ */
827
+ private emit;
448
828
  /**
449
- * Clean up all listeners and mark as destroyed
829
+ * Flush shadow canvas immediately (force-graph pattern)
830
+ */
831
+ flushShadow(): void;
832
+ /**
833
+ * Debug hover state
834
+ */
835
+ debugHoverState(): void;
836
+ /**
837
+ * Destroy hover manager
450
838
  */
451
839
  destroy(): void;
840
+ }
841
+
842
+ /**
843
+ * V2 Canvas Graph - Drag Manager
844
+ *
845
+ * Manages node dragging interactions with physics simulation
846
+ */
847
+
848
+ interface DragConfig {
849
+ canvas: HTMLCanvasElement;
850
+ physicsManager: PhysicsManager;
851
+ hoverManager: HoverManager;
852
+ onRender: () => void;
853
+ }
854
+ interface DragState {
855
+ isDragging: boolean;
856
+ isPointerDragging: boolean;
857
+ }
858
+ declare class DragManager {
859
+ private config?;
860
+ private state;
861
+ private readonly DRAG_CLICK_TOLERANCE_PX;
452
862
  /**
453
- * Reset the emitter (clear listeners but allow new ones)
863
+ * Initialize drag behavior
454
864
  */
455
- reset(): void;
865
+ initialize(config: DragConfig): void;
866
+ /**
867
+ * Get drag subject (node under pointer)
868
+ */
869
+ private getDragSubject;
870
+ /**
871
+ * Handle drag start
872
+ */
873
+ private handleDragStart;
874
+ /**
875
+ * Handle drag movement
876
+ */
877
+ private handleDrag;
878
+ /**
879
+ * Handle drag end
880
+ */
881
+ private handleDragEnd;
882
+ /**
883
+ * Get current drag state
884
+ */
885
+ getState(): DragState;
886
+ /**
887
+ * Check if currently dragging
888
+ */
889
+ isDragging(): boolean;
890
+ /**
891
+ * Check if pointer is dragging
892
+ */
893
+ isPointerDragging(): boolean;
894
+ /**
895
+ * Destroy drag manager
896
+ */
897
+ destroy(): void;
456
898
  }
899
+
457
900
  /**
458
- * Graph-specific event types
901
+ * V2 Canvas Graph - Zoom Manager
902
+ *
903
+ * Manages zoom and pan interactions
459
904
  */
460
- interface GraphEventMap {
461
- 'nodeSelect': {
462
- node: GraphNode;
463
- element: SVGCircleElement;
464
- };
465
- 'nodeDeselect': {
466
- node: GraphNode;
467
- element: SVGCircleElement;
468
- };
469
- 'linkSelect': {
470
- link: GraphLink;
471
- element: SVGLineElement;
472
- };
473
- 'linkDeselect': {
474
- link: GraphLink;
475
- element: SVGLineElement;
476
- };
477
- 'graphRender': {
478
- nodeCount: number;
479
- linkCount: number;
480
- };
481
- 'simulationStart': {
482
- alpha: number;
483
- };
484
- 'simulationEnd': {
485
- iterations: number;
486
- };
487
- 'zoomStart': {
905
+
906
+ interface ZoomConfig {
907
+ canvas: HTMLCanvasElement;
908
+ canvasManager: CanvasManager;
909
+ onRender: () => void;
910
+ minZoom?: number;
911
+ maxZoom?: number;
912
+ isOverEntity?: () => boolean;
913
+ }
914
+ declare class ZoomManager {
915
+ private config?;
916
+ private zoomBehavior?;
917
+ /**
918
+ * Initialize zoom behavior
919
+ */
920
+ initialize(config: ZoomConfig): void;
921
+ /**
922
+ * Set initial centered transform (call after physics starts)
923
+ */
924
+ setInitialTransform(): void;
925
+ /**
926
+ * Handle zoom start (when panning begins)
927
+ */
928
+ private handleZoomStart;
929
+ /**
930
+ * Handle zoom events
931
+ */
932
+ private handleZoom;
933
+ /**
934
+ * Handle zoom end (when panning ends)
935
+ */
936
+ private handleZoomEnd;
937
+ /**
938
+ * Get zoom behavior instance
939
+ */
940
+ getZoomBehavior(): ZoomBehavior<HTMLCanvasElement, unknown> | undefined;
941
+ /**
942
+ * Get current zoom transform
943
+ */
944
+ getTransform(): {
488
945
  scale: number;
489
946
  x: number;
490
947
  y: number;
491
948
  };
492
- 'zoomEnd': {
493
- scale: number;
949
+ /**
950
+ * Programmatically zoom in
951
+ */
952
+ zoomIn(factor?: number, center?: [number, number]): void;
953
+ /**
954
+ * Programmatically zoom out
955
+ */
956
+ zoomOut(factor?: number, center?: [number, number]): void;
957
+ /**
958
+ * Reset zoom to scale=1 but center the content like fitView
959
+ */
960
+ resetZoom(duration?: number): void;
961
+ /**
962
+ * Set zoom to specific transform
963
+ */
964
+ setTransform(transform: {
965
+ k: number;
494
966
  x: number;
495
967
  y: number;
968
+ }, duration?: number): void;
969
+ /**
970
+ * Fit view to content bounds (force-graph zoomToFit implementation)
971
+ */
972
+ fitView(bounds: {
973
+ x: [number, number];
974
+ y: [number, number];
975
+ }, padding?: number): Promise<void>;
976
+ /**
977
+ * Check if zoom is at reset state (scale=1, centered)
978
+ */
979
+ isAtIdentity(): boolean;
980
+ /**
981
+ * Get zoom statistics
982
+ */
983
+ getStats(): {
984
+ transform: {
985
+ scale: number;
986
+ x: number;
987
+ y: number;
988
+ };
989
+ scaleExtent: [number, number];
990
+ isAtIdentity: boolean;
496
991
  };
497
- [key: string]: unknown;
498
- }
499
- type GraphEventName = keyof GraphEventMap;
500
- /**
501
- * Type-safe graph event emitter
502
- */
503
- declare class TypedGraphEventEmitter extends GraphEventEmitter<GraphEventMap> {
504
- constructor(options?: EventEmitterOptions);
505
- }
506
-
507
- interface GraphLayers {
508
- readonly svg: SVGSVGElement;
509
- readonly overlay: HTMLDivElement;
510
- readonly interactionLayer: SVGGElement;
511
- readonly interactionRect: SVGRectElement;
512
- readonly root: SVGGElement;
513
- readonly links: SVGGElement;
514
- readonly nodeRings: SVGGElement;
515
- readonly nodes: SVGGElement;
516
- readonly nodeLabels: SVGGElement;
517
- readonly linkLabels: SVGGElement;
518
- readonly hoverLayer: {
519
- readonly container: SVGGElement;
520
- readonly links: SVGGElement;
521
- readonly nodes: SVGGElement;
522
- readonly nodeLabels: SVGGElement;
523
- readonly linkLabels: SVGGElement;
524
- };
525
- readonly selectionLayer: {
526
- readonly container: SVGGElement;
527
- readonly links: SVGGElement;
528
- readonly nodes: SVGGElement;
529
- readonly nodeLabels: SVGGElement;
530
- readonly linkLabels: SVGGElement;
531
- };
532
- }
533
-
534
- interface RenderableGraphLink {
535
- readonly link: GraphLink;
536
- readonly style: ResolvedLinkStyle;
537
- readonly markerEnd: string;
538
- }
539
-
540
- interface NodeTooltipBinding {
992
+ /**
993
+ * Destroy zoom manager
994
+ */
541
995
  destroy(): void;
542
- reposition(): void;
543
- hide(): void;
544
996
  }
545
997
 
546
998
  /**
547
- * Centralized selection management for graph nodes and links.
548
- * Simplifies selection logic and ensures consistent behavior.
999
+ * V2 Canvas Graph - Selection Manager
1000
+ *
1001
+ * Manages node and link selection interactions and events
549
1002
  */
550
1003
 
551
1004
  interface SelectionState {
552
- selectedNode: {
553
- element: SVGCircleElement;
554
- data: GraphNode;
555
- } | null;
556
- selectedLink: {
557
- element: SVGLineElement;
558
- data: GraphLink;
559
- originalMarker: string | null;
560
- } | null;
1005
+ selectedNode: V2Node | null;
1006
+ selectedLink: V2Link | null;
1007
+ }
1008
+ interface SelectionEvent {
1009
+ type: 'nodeSelect' | 'nodeDeselect' | 'linkSelect' | 'linkDeselect';
1010
+ current: V2Node | V2Link | null;
1011
+ previous: V2Node | V2Link | null;
561
1012
  }
562
1013
  declare class SelectionManager {
563
- private state;
564
- private readonly eventEmitter;
565
- private readonly config;
566
- private readonly layers;
567
- private readonly linkMarkerSnapshots;
568
- private readonly root;
569
- private readonly tooltipBinding?;
570
- constructor(eventEmitter: TypedGraphEventEmitter, config: SelectionInteractionConfig, layers: GraphLayers, linkMarkerSnapshots: Map<SVGLineElement, string | null>, root: Selection<SVGGElement, unknown, null, undefined>, tooltipBinding?: NodeTooltipBinding);
1014
+ private canvasState?;
1015
+ private selectionState;
1016
+ private eventHandlers;
1017
+ private container?;
1018
+ /**
1019
+ * Initialize selection manager
1020
+ */
1021
+ initialize(canvasState: CanvasState): void;
1022
+ /**
1023
+ * Setup click/tap listeners for selection
1024
+ */
1025
+ private setupSelectionListeners;
571
1026
  /**
572
- * Select a node, automatically deselecting any current selection
1027
+ * Handle selection click
573
1028
  */
574
- selectNode(nodeElement: SVGCircleElement, nodeData: GraphNode): void;
1029
+ private handleSelectionClick;
575
1030
  /**
576
- * Select a link, automatically deselecting any current selection
1031
+ * Get object under pointer coordinates (using shadow canvas)
577
1032
  */
578
- selectLink(linkElement: SVGLineElement, renderableLink: RenderableGraphLink, event?: MouseEvent): void;
1033
+ private getObjUnderPointer;
579
1034
  /**
580
- * Deselect the currently selected node
1035
+ * Select a node
581
1036
  */
582
- private deselectNode;
1037
+ selectNode(node: V2Node): void;
583
1038
  /**
584
- * Deselect the currently selected link
1039
+ * Select a link
585
1040
  */
586
- private deselectLink;
1041
+ selectLink(link: V2Link): void;
587
1042
  /**
588
1043
  * Clear all selections
589
1044
  */
590
1045
  clearSelection(): void;
1046
+ /**
1047
+ * Check if two nodes are the same
1048
+ */
1049
+ private isSameNode;
1050
+ /**
1051
+ * Check if two links are the same
1052
+ */
1053
+ private isSameLink;
1054
+ /**
1055
+ * Check if a node is currently selected
1056
+ */
1057
+ isNodeSelected(node: V2Node): boolean;
1058
+ /**
1059
+ * Check if a link is currently selected
1060
+ */
1061
+ isLinkSelected(link: V2Link): boolean;
591
1062
  /**
592
1063
  * Get current selection state
593
1064
  */
594
1065
  getSelectionState(): SelectionState;
595
1066
  /**
596
- * Check if a specific node is selected
1067
+ * Add event listener
1068
+ */
1069
+ on(event: string, handler: (event: SelectionEvent) => void): void;
1070
+ /**
1071
+ * Remove event listener
1072
+ */
1073
+ off(event: string, handler: (event: SelectionEvent) => void): void;
1074
+ /**
1075
+ * Emit event to all listeners
1076
+ */
1077
+ private emit;
1078
+ /**
1079
+ * Destroy selection manager
1080
+ */
1081
+ destroy(): void;
1082
+ }
1083
+
1084
+ /**
1085
+ * V2 Canvas Graph - Renderer (Force-Graph Pattern)
1086
+ *
1087
+ * Clean implementation following force-graph's exact architecture
1088
+ */
1089
+
1090
+ declare class Renderer {
1091
+ private config?;
1092
+ private canvasState?;
1093
+ private hoverManager?;
1094
+ private selectionManager?;
1095
+ private styleResolver?;
1096
+ private nodeMap;
1097
+ private shadowCanvasDirty;
1098
+ private lastShadowRenderTime;
1099
+ private readonly SHADOW_RENDER_THROTTLE;
1100
+ private hasLoggedLargeGraphOptimization;
1101
+ private performanceMetrics;
1102
+ private linkHoverPrecision;
1103
+ /**
1104
+ * Initialize the renderer
1105
+ */
1106
+ initialize(config: {
1107
+ nodes: V2Node[];
1108
+ links: V2Link[];
1109
+ interaction?: InteractionConfig;
1110
+ }, canvasState: CanvasState, hoverManager: HoverManager, selectionManager?: SelectionManager): void;
1111
+ /**
1112
+ * Main render method with performance metrics (Instrumented)
1113
+ */
1114
+ render(): void;
1115
+ /**
1116
+ * Render with transform (called during zoom/pan) with shadow canvas dirty marking (Step 6 optimization)
1117
+ */
1118
+ renderWithTransform(): void;
1119
+ /**
1120
+ * Render shadow canvas for hit detection with throttling (Step 6 optimization)
1121
+ */
1122
+ renderShadowCanvas(): void;
1123
+ /**
1124
+ * Mark shadow canvas as dirty for next render (Step 6 optimization)
1125
+ */
1126
+ markShadowCanvasDirty(): void;
1127
+ /**
1128
+ * Force shadow canvas render (Step 6 optimization)
1129
+ */
1130
+ forceShadowCanvasRender(): void;
1131
+ /**
1132
+ * Clear canvas context
1133
+ */
1134
+ private clearCanvas;
1135
+ /**
1136
+ * Apply transform to canvas context
1137
+ */
1138
+ private applyTransform;
1139
+ /**
1140
+ * Get unique link ID for tracking (consistent with LinkLabelsRenderer)
1141
+ */
1142
+ private getLinkId;
1143
+ /**
1144
+ * Render main canvas nodes
1145
+ */
1146
+ private renderNodes;
1147
+ /**
1148
+ * Render node labels
1149
+ */
1150
+ private renderNodeLabels;
1151
+ /**
1152
+ * Render shadow links with __indexColor (force-graph pattern)
1153
+ */
1154
+ private renderShadowLinks;
1155
+ /**
1156
+ * Render shadow link labels for hit detection
1157
+ */
1158
+ private renderShadowLinkLabels;
1159
+ /**
1160
+ * Render shadow nodes with __indexColor (force-graph pattern)
1161
+ */
1162
+ private renderShadowNodes;
1163
+ /**
1164
+ * Get currently hovered node ID directly (Critical Performance Fix)
597
1165
  */
598
- isNodeSelected(nodeData: GraphNode): boolean;
1166
+ private getCurrentlyHoveredNodeId;
599
1167
  /**
600
- * Check if a specific link is selected
1168
+ * Get currently selected node ID directly (Critical Performance Fix)
601
1169
  */
602
- isLinkSelected(linkData: GraphLink): boolean;
1170
+ private getCurrentlySelectedNodeId;
603
1171
  /**
604
- * Handle click on background (deselect all)
1172
+ * Get currently hovered link (Critical Performance Fix)
605
1173
  */
606
- handleBackgroundClick(event: MouseEvent, svg: SVGSVGElement, interactionRect: SVGRectElement): void;
1174
+ private getCurrentlyHoveredLink;
607
1175
  /**
608
- * Bring node and related elements to front using selection layer sub-layers
1176
+ * Get currently selected link (Critical Performance Fix)
609
1177
  */
610
- private bringNodeToFront;
1178
+ private getCurrentlySelectedLink;
611
1179
  /**
612
- * Bring link and its label to front using selection layer
1180
+ * Log performance metrics for analysis
613
1181
  */
614
- private bringLinkToFront;
1182
+ private logPerformanceMetrics;
615
1183
  /**
616
- * Restore elements back to their original layers
1184
+ * Reset performance metrics
617
1185
  */
618
- private restoreSelectedElements;
1186
+ resetPerformanceMetrics(): void;
619
1187
  /**
620
- * Utility method to bring any SVG element to front using appendChild
621
- * Based on the reference implementation pattern
1188
+ * Get current performance metrics
622
1189
  */
623
- private bringElementToFront;
1190
+ getPerformanceMetrics(): StatsMetrics;
624
1191
  /**
625
- * Clear hover state to prevent conflicts with selection
626
- * Similar to the clearAllHoverLayers function in create-node-hover.ts
1192
+ * Force log performance metrics immediately (for debugging)
627
1193
  */
628
- private clearHoverState;
1194
+ forceLogMetrics(): void;
629
1195
  /**
630
- * Clean up resources
1196
+ * Check if a node is currently hovered
1197
+ */
1198
+ private isNodeHovered;
1199
+ /**
1200
+ * Check if a link is currently hovered (either directly or through associated node hover)
1201
+ */
1202
+ private isLinkHovered;
1203
+ /**
1204
+ * Check if a node is currently selected
1205
+ */
1206
+ private isNodeSelected;
1207
+ /**
1208
+ * Check if a link is currently selected
1209
+ */
1210
+ private isLinkSelected;
1211
+ /**
1212
+ * Check if a link's label should be visible due to selection
1213
+ * (either the link itself is selected, or its connected node is selected)
1214
+ */
1215
+ private shouldShowLinkLabelForSelection;
1216
+ /**
1217
+ * Calculate midpoint of a link for label positioning
1218
+ */
1219
+ private getLinkMidpoint;
1220
+ /**
1221
+ * Render directed link with arrow head
1222
+ */
1223
+ private renderDirectedLink;
1224
+ /**
1225
+ * V1-compatible link shortening for source point
1226
+ */
1227
+ private getShortenedSourcePoint;
1228
+ /**
1229
+ * V1-compatible link shortening for target point
1230
+ */
1231
+ private getShortenedTargetPoint;
1232
+ /**
1233
+ * Render arrow head at specific points
1234
+ */
1235
+ private renderArrowAtPoint;
1236
+ /**
1237
+ * Render arrow head (legacy method for backward compatibility)
1238
+ */
1239
+ private renderArrow;
1240
+ /**
1241
+ * Initialize node positions if needed
1242
+ */
1243
+ initializeNodePositions(): void;
1244
+ /**
1245
+ * Update configuration
1246
+ */
1247
+ updateConfig(updates: Partial<{
1248
+ nodes: V2Node[];
1249
+ links: V2Link[];
1250
+ }>): void;
1251
+ /**
1252
+ * Get renderer statistics
1253
+ */
1254
+ getStats(): {
1255
+ renderCounts: {
1256
+ nodes: number;
1257
+ links: number;
1258
+ };
1259
+ renderTime: {
1260
+ lastRender: number;
1261
+ };
1262
+ };
1263
+ /**
1264
+ * Debug shadow canvas export (force-graph pattern)
1265
+ */
1266
+ debugShadowCanvas(): void;
1267
+ /**
1268
+ * Build node index for O(1) lookups (Step 3 optimization)
1269
+ */
1270
+ private buildNodeIndex;
1271
+ /**
1272
+ * Get node by ID using O(1) lookup (Step 3 optimization)
1273
+ */
1274
+ private getNodeById;
1275
+ /**
1276
+ * Render with z-index layers (for renderWithTransform)
1277
+ */
1278
+ private renderWithLayers;
1279
+ /**
1280
+ * Render with z-index layers and performance metrics (for main render)
1281
+ */
1282
+ private renderWithLayersAndMetrics;
1283
+ /**
1284
+ * Helper methods for getting current interaction states
1285
+ */
1286
+ private getHoveredNode;
1287
+ private getSelectedNode;
1288
+ private getHoveredLink;
1289
+ private getSelectedLink;
1290
+ /**
1291
+ * Layer-specific rendering methods (render subsets of entities)
1292
+ */
1293
+ private renderNodesWithLabelsLayer;
1294
+ /**
1295
+ * Helper method to truncate labels (copied from NodeLabelsRenderer)
1296
+ */
1297
+ private truncateLabel;
1298
+ private renderLinksLayer;
1299
+ private renderLinkLabelsLayer;
1300
+ private renderNodesLayer;
1301
+ private renderNodeLabelsLayer;
1302
+ /**
1303
+ * Destroy renderer and clean up resources
631
1304
  */
632
1305
  destroy(): void;
633
1306
  }
634
1307
 
635
- export { type ErrorContext, ErrorHandler, type EventUnsubscribe, type GraphConfig, type GraphControlsConfig, GraphError, type GraphEventMap, type GraphEventName, type GraphInstance, type GraphInteractionConfig, type GraphLink, type GraphNode, GraphValidationError, GraphValidator, type LegendConfig, SelectionManager, type SelectionState, TypedGraphEventEmitter, type ValidationError, type ValidationResult, createGraph };
1308
+ /**
1309
+ * V2 Canvas Graph - Modular Implementation
1310
+ *
1311
+ * High-performance canvas-based graph with comprehensive error handling
1312
+ * and modular architecture.
1313
+ */
1314
+
1315
+ declare class V2Graph implements V2Instance {
1316
+ private config?;
1317
+ private canvasManager;
1318
+ private timerManager;
1319
+ private physicsManager;
1320
+ private dragManager;
1321
+ private zoomManager;
1322
+ private hoverManager;
1323
+ private selectionManager;
1324
+ private renderer;
1325
+ private tooltipManager?;
1326
+ private controlsManager?;
1327
+ private legendsManager?;
1328
+ private lastRenderTime;
1329
+ private isInitialLoad;
1330
+ /**
1331
+ * Initialize the graph
1332
+ */
1333
+ initialize(config: V2Config): void;
1334
+ /**
1335
+ * Assign __indexColor to objects (force-graph pattern)
1336
+ */
1337
+ private assignIndexColors;
1338
+ /**
1339
+ * Setup shadow canvas update handler
1340
+ */
1341
+ private setupShadowCanvasHandler;
1342
+ /**
1343
+ * Setup tooltip event handlers (force-graph pattern)
1344
+ */
1345
+ private setupTooltipHandlers;
1346
+ /**
1347
+ * Setup hover event listeners to trigger re-renders for visual effects
1348
+ */
1349
+ private setupHoverRerender;
1350
+ /**
1351
+ * Setup selection event listeners to trigger re-renders for visual effects
1352
+ */
1353
+ private setupSelectionRerender;
1354
+ /**
1355
+ * Coordinate drag and hover interactions (force-graph pattern)
1356
+ */
1357
+ private coordinateDragHover;
1358
+ /**
1359
+ * Setup resize observer for responsive canvas behavior
1360
+ * Following force-graph and V1 patterns with debounced fit view
1361
+ */
1362
+ private setupResizeObserver;
1363
+ /**
1364
+ * Validate configuration
1365
+ */
1366
+ private validateConfig;
1367
+ /**
1368
+ * Render the graph
1369
+ */
1370
+ render(): void;
1371
+ /**
1372
+ * Get current zoom transform
1373
+ */
1374
+ testZoom(): {
1375
+ scale: number;
1376
+ x: number;
1377
+ y: number;
1378
+ };
1379
+ /**
1380
+ * Get zoom behavior (for V1 API compatibility)
1381
+ */
1382
+ getZoomBehavior(): ZoomBehavior<HTMLCanvasElement, unknown> | undefined;
1383
+ /**
1384
+ * Get canvas element (for V1 API compatibility)
1385
+ */
1386
+ getCanvas(): HTMLCanvasElement;
1387
+ /**
1388
+ * Zoom in programmatically
1389
+ */
1390
+ zoomIn(factor?: number, center?: [number, number]): void;
1391
+ /**
1392
+ * Zoom out programmatically
1393
+ */
1394
+ zoomOut(factor?: number, center?: [number, number]): void;
1395
+ /**
1396
+ * Reset zoom to identity
1397
+ */
1398
+ resetView(): void;
1399
+ /**
1400
+ * Fit view to content (force-graph zoomToFit implementation)
1401
+ */
1402
+ fitView(): Promise<void>;
1403
+ /**
1404
+ * Debug hover state (for development)
1405
+ */
1406
+ debugHover(): void;
1407
+ /**
1408
+ * Debug shadow canvas (for development)
1409
+ */
1410
+ debugShadowCanvas(): void;
1411
+ /**
1412
+ * Clear current selection
1413
+ */
1414
+ clearSelection(): void;
1415
+ /**
1416
+ * Get performance metrics from renderer
1417
+ */
1418
+ getPerformanceMetrics(): StatsMetrics;
1419
+ /**
1420
+ * Force log performance metrics immediately
1421
+ */
1422
+ logPerformanceMetrics(): void;
1423
+ /**
1424
+ * Reset performance metrics
1425
+ */
1426
+ resetPerformanceMetrics(): void;
1427
+ /**
1428
+ * V1-style event handlers - type-safe and reliable
1429
+ */
1430
+ on(event: 'nodeSelect', handler: (node: V2Node, element: HTMLCanvasElement) => void): () => void;
1431
+ on(event: 'nodeDeselect', handler: (node: V2Node, element: HTMLCanvasElement) => void): () => void;
1432
+ on(event: 'linkSelect', handler: (link: V2Link, element: HTMLCanvasElement) => void): () => void;
1433
+ on(event: 'linkDeselect', handler: (link: V2Link, element: HTMLCanvasElement) => void): () => void;
1434
+ on(event: 'nodeHover', handler: (node: V2Node, element: HTMLCanvasElement) => void): () => void;
1435
+ on(event: 'nodeUnhover', handler: (node: V2Node, element: HTMLCanvasElement) => void): () => void;
1436
+ on(event: 'linkHover', handler: (link: V2Link, element: HTMLCanvasElement) => void): () => void;
1437
+ on(event: 'linkUnhover', handler: (link: V2Link, element: HTMLCanvasElement) => void): () => void;
1438
+ /**
1439
+ * V1-style event handler removal - type-safe
1440
+ */
1441
+ off(event: 'nodeSelect', handler: (node: V2Node, element: HTMLCanvasElement) => void): void;
1442
+ off(event: 'nodeDeselect', handler: (node: V2Node, element: HTMLCanvasElement) => void): void;
1443
+ off(event: 'linkSelect', handler: (link: V2Link, element: HTMLCanvasElement) => void): void;
1444
+ off(event: 'linkDeselect', handler: (link: V2Link, element: HTMLCanvasElement) => void): void;
1445
+ off(event: 'nodeHover', handler: (node: V2Node, element: HTMLCanvasElement) => void): void;
1446
+ off(event: 'nodeUnhover', handler: (node: V2Node, element: HTMLCanvasElement) => void): void;
1447
+ off(event: 'linkHover', handler: (link: V2Link, element: HTMLCanvasElement) => void): void;
1448
+ off(event: 'linkUnhover', handler: (link: V2Link, element: HTMLCanvasElement) => void): void;
1449
+ /**
1450
+ * Export graph as PNG image
1451
+ */
1452
+ exportGraph(fileName?: string): Promise<void>;
1453
+ /**
1454
+ * Perform the actual export capture after fit view
1455
+ */
1456
+ private performExportCapture;
1457
+ /**
1458
+ * Draw legend on export canvas
1459
+ */
1460
+ private drawLegendOnExportCanvas;
1461
+ /**
1462
+ * Destroy the graph and clean up resources
1463
+ */
1464
+ destroy(): void;
1465
+ }
1466
+ /**
1467
+ * Factory function for creating V2 graphs
1468
+ */
1469
+ declare function createV2Graph(config: V2Config): V2Instance;
1470
+
1471
+ export { type ArrowRenderStyle, type BaseGraphConfig, CanvasManager, type CanvasRenderConfig, type CanvasState, type ControlsController, type Coordinates, DEFAULT_COLORS, DEFAULT_HOVER_STYLES, DEFAULT_LINK_LABEL_STYLE, DEFAULT_LINK_STYLE, type DragConfig, type DragInteractionConfig, DragManager, type DragState, ErrorHandler, type GraphControlsConfig, type GraphControlsOrientation, type GraphControlsPosition, type GraphInteractionConfig, type GraphLink, type GraphNode, type GraphNodeWithInitial, type GraphTooltipTheme, type HoverEvent, type HoverInteractionConfig, HoverManager, type HoverState, type HoverStyles, type IconName, type IconSvgName, type InteractionColors, type InteractionConfig, type LegendConfig, type LegendPosition, type LinkArrowStyle, type LinkColors, type LinkLabelRenderStyle, type LinkLabelStyle, type LinkRenderStyle, type LinkSelectHandler, type LinkStyle, NeutralColor, type NodeColorPalette, type NodeLabelRenderStyle, type NodeRenderStyle, type NodeSelectHandler, type NodeStyle, type Orientation, type PhysicsConfig, PhysicsManager, PointerManager, type PointerState, type Position, PrimaryColor, type RenderStyles, Renderer, type ResolvedLinkLabelStyle, type ResolvedLinkStyle, SecondaryColor, type SelectionEvent, type SelectionInteractionConfig, SelectionManager, type SelectionState, type SimulationConfig, StandardColor, type TooltipInteractionConfig, type TooltipPlacement, type UIColors, type V2Config, V2Graph, type V2Instance, type V2Link, type V2Node, ValidationError, type ZoomConfig, ZoomManager, createV2Graph, getIcon, getIconSvg, iconSvg, icons, isValidLinkStyle, isValidNodeStyle, mergeLinkStyle, mergeNodeStyle };