polly-graph 0.1.7 → 0.1.9
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 +308 -30
- package/dist/index.cjs +2930 -659
- package/dist/index.css +23 -11
- package/dist/index.d.cts +483 -8
- package/dist/index.d.ts +483 -8
- package/dist/index.js +2924 -649
- package/package.json +3 -3
package/dist/index.css
CHANGED
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
display: flex;
|
|
170
170
|
align-items: center;
|
|
171
171
|
gap: 12px;
|
|
172
|
-
font-size: 0.
|
|
172
|
+
font-size: 0.75rem;
|
|
173
173
|
color: #475569;
|
|
174
174
|
white-space: nowrap;
|
|
175
175
|
}
|
|
@@ -200,14 +200,17 @@
|
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
/* src/styles/graph-tooltip.css */
|
|
203
|
+
:root {
|
|
204
|
+
--dark-bg: color-mix(in srgb, #808080, #000000 20%);
|
|
205
|
+
}
|
|
203
206
|
.graph-tooltip {
|
|
204
207
|
position: absolute;
|
|
205
208
|
pointer-events: none;
|
|
206
209
|
z-index: 1000;
|
|
207
|
-
|
|
210
|
+
width: fit-content;
|
|
208
211
|
max-width: 280px;
|
|
209
|
-
border-radius:
|
|
210
|
-
background:
|
|
212
|
+
border-radius: 0.375rem;
|
|
213
|
+
background: var(--dark-bg);
|
|
211
214
|
color: #f8fafc;
|
|
212
215
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
213
216
|
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.22);
|
|
@@ -217,7 +220,7 @@
|
|
|
217
220
|
BlinkMacSystemFont,
|
|
218
221
|
"Segoe UI",
|
|
219
222
|
sans-serif;
|
|
220
|
-
font-size:
|
|
223
|
+
font-size: 10px;
|
|
221
224
|
line-height: 1.5;
|
|
222
225
|
opacity: 0;
|
|
223
226
|
transform: translateY(4px);
|
|
@@ -230,13 +233,15 @@
|
|
|
230
233
|
.graph-tooltip__content {
|
|
231
234
|
position: relative;
|
|
232
235
|
z-index: 2;
|
|
233
|
-
padding:
|
|
236
|
+
padding: 0.375rem 0.5rem;
|
|
237
|
+
word-wrap: break-word;
|
|
238
|
+
overflow-wrap: break-word;
|
|
234
239
|
}
|
|
235
240
|
.graph-tooltip__arrow {
|
|
236
241
|
position: absolute;
|
|
237
|
-
width:
|
|
238
|
-
height:
|
|
239
|
-
background:
|
|
242
|
+
width: 0.625rem;
|
|
243
|
+
height: 0.625rem;
|
|
244
|
+
background: var(--dark-bg);
|
|
240
245
|
transform: rotate(45deg);
|
|
241
246
|
z-index: 1;
|
|
242
247
|
}
|
|
@@ -269,7 +274,7 @@
|
|
|
269
274
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
270
275
|
}
|
|
271
276
|
.graph-tooltip__type {
|
|
272
|
-
font-size:
|
|
277
|
+
font-size: 9px;
|
|
273
278
|
font-weight: 600;
|
|
274
279
|
color: #94a3b8;
|
|
275
280
|
text-transform: uppercase;
|
|
@@ -277,10 +282,12 @@
|
|
|
277
282
|
}
|
|
278
283
|
.graph-tooltip__label {
|
|
279
284
|
margin-top: 4px;
|
|
280
|
-
font-size:
|
|
285
|
+
font-size: 11px;
|
|
281
286
|
font-weight: 600;
|
|
282
287
|
line-height: 1.4;
|
|
283
288
|
color: #ffffff;
|
|
289
|
+
word-wrap: break-word;
|
|
290
|
+
overflow-wrap: break-word;
|
|
284
291
|
}
|
|
285
292
|
|
|
286
293
|
/* src/styles/graph.css */
|
|
@@ -294,6 +301,10 @@
|
|
|
294
301
|
display: block;
|
|
295
302
|
width: 100%;
|
|
296
303
|
height: 100%;
|
|
304
|
+
cursor: grab;
|
|
305
|
+
}
|
|
306
|
+
.pg-canvas:active {
|
|
307
|
+
cursor: grabbing;
|
|
297
308
|
}
|
|
298
309
|
.pg-overlay {
|
|
299
310
|
position: absolute;
|
|
@@ -306,6 +317,7 @@
|
|
|
306
317
|
transition: r 0.2s ease, stroke-width 0.2s ease;
|
|
307
318
|
}
|
|
308
319
|
.pg-layer-links line {
|
|
320
|
+
cursor: pointer;
|
|
309
321
|
transition: stroke-opacity 0.2s ease;
|
|
310
322
|
}
|
|
311
323
|
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { SimulationNodeDatum, SimulationLinkDatum } from 'd3-force';
|
|
1
|
+
import { SimulationNodeDatum, SimulationLinkDatum, Simulation } from 'd3-force';
|
|
2
|
+
import { Selection } from 'd3-selection';
|
|
2
3
|
|
|
3
4
|
interface Coordinates {
|
|
4
5
|
readonly x: number;
|
|
@@ -32,7 +33,7 @@ interface LegendConfig {
|
|
|
32
33
|
readonly enabled?: boolean;
|
|
33
34
|
readonly title?: string;
|
|
34
35
|
readonly position?: LegendPosition;
|
|
35
|
-
readonly items
|
|
36
|
+
readonly items?: LegendItem[];
|
|
36
37
|
readonly collapsible?: boolean;
|
|
37
38
|
readonly defaultExpanded?: boolean;
|
|
38
39
|
}
|
|
@@ -85,6 +86,101 @@ interface LinkStyle {
|
|
|
85
86
|
readonly arrow?: LinkArrowStyle;
|
|
86
87
|
readonly label?: LinkLabelStyle;
|
|
87
88
|
}
|
|
89
|
+
interface ResolvedLinkLabelStyle {
|
|
90
|
+
readonly enabled: boolean;
|
|
91
|
+
readonly visibility: 'always' | 'hover' | 'selection';
|
|
92
|
+
readonly backgroundFill: string;
|
|
93
|
+
readonly borderColor: string;
|
|
94
|
+
readonly borderWidth: number;
|
|
95
|
+
readonly borderRadius: number;
|
|
96
|
+
readonly textColor: string;
|
|
97
|
+
readonly fontSize: number;
|
|
98
|
+
readonly paddingX: number;
|
|
99
|
+
readonly paddingY: number;
|
|
100
|
+
readonly height: number;
|
|
101
|
+
}
|
|
102
|
+
interface ResolvedLinkStyle {
|
|
103
|
+
readonly stroke: string;
|
|
104
|
+
readonly strokeWidth: number;
|
|
105
|
+
readonly opacity: number;
|
|
106
|
+
readonly dashArray: string | undefined;
|
|
107
|
+
readonly arrow: {
|
|
108
|
+
readonly enabled: boolean;
|
|
109
|
+
readonly size: number;
|
|
110
|
+
readonly fill: string;
|
|
111
|
+
};
|
|
112
|
+
readonly label: ResolvedLinkLabelStyle;
|
|
113
|
+
}
|
|
114
|
+
|
|
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;
|
|
120
|
+
}
|
|
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;
|
|
127
|
+
}
|
|
128
|
+
interface CollideForceConfig {
|
|
129
|
+
readonly enabled?: boolean;
|
|
130
|
+
readonly radius?: number | ((node: GraphNode) => number);
|
|
131
|
+
readonly strength?: number;
|
|
132
|
+
readonly iterations?: number;
|
|
133
|
+
}
|
|
134
|
+
interface CenterForceConfig {
|
|
135
|
+
readonly enabled?: boolean;
|
|
136
|
+
readonly strength?: number;
|
|
137
|
+
readonly x?: number;
|
|
138
|
+
readonly y?: number;
|
|
139
|
+
}
|
|
140
|
+
interface XForceConfig {
|
|
141
|
+
readonly enabled?: boolean;
|
|
142
|
+
readonly strength?: number;
|
|
143
|
+
readonly x?: number | ((node: GraphNode) => number);
|
|
144
|
+
}
|
|
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
|
+
};
|
|
165
|
+
}
|
|
166
|
+
interface WarmupConfig {
|
|
167
|
+
readonly enabled?: boolean;
|
|
168
|
+
readonly ticks?: number;
|
|
169
|
+
}
|
|
170
|
+
interface CooldownConfig {
|
|
171
|
+
readonly enabled?: boolean;
|
|
172
|
+
readonly delay?: number;
|
|
173
|
+
}
|
|
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;
|
|
183
|
+
}
|
|
88
184
|
|
|
89
185
|
type GraphTooltipTheme = 'dark' | 'light';
|
|
90
186
|
type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right' | 'auto';
|
|
@@ -120,11 +216,7 @@ interface GraphConfig {
|
|
|
120
216
|
readonly links: GraphLink[];
|
|
121
217
|
readonly autoFit?: boolean;
|
|
122
218
|
readonly responsive?: boolean;
|
|
123
|
-
readonly simulation?:
|
|
124
|
-
readonly alpha?: number;
|
|
125
|
-
readonly gravity?: number;
|
|
126
|
-
readonly linkDistance?: number | ((link: GraphLink) => number);
|
|
127
|
-
};
|
|
219
|
+
readonly simulation?: EnhancedSimulationConfig;
|
|
128
220
|
readonly interaction?: GraphInteractionConfig;
|
|
129
221
|
readonly controls?: GraphControlsConfig;
|
|
130
222
|
readonly legend?: LegendConfig;
|
|
@@ -138,6 +230,7 @@ interface GraphInstance {
|
|
|
138
230
|
fitView(): void;
|
|
139
231
|
destroy(): void;
|
|
140
232
|
exportGraph(fileName?: string): void;
|
|
233
|
+
clearSelection(): void;
|
|
141
234
|
on(event: 'nodeSelect', handler: (node: GraphNode, element: SVGCircleElement) => void): () => void;
|
|
142
235
|
on(event: 'nodeDeselect', handler: (node: GraphNode, element: SVGCircleElement) => void): () => void;
|
|
143
236
|
on(event: 'linkSelect', handler: (link: GraphLink, element: SVGLineElement) => void): () => void;
|
|
@@ -148,6 +241,388 @@ interface GraphInstance {
|
|
|
148
241
|
off(event: 'linkDeselect', handler: (link: GraphLink, element: SVGLineElement) => void): void;
|
|
149
242
|
}
|
|
150
243
|
|
|
244
|
+
/**
|
|
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
|
|
251
|
+
*/
|
|
151
252
|
declare function createGraph(config: GraphConfig): GraphInstance;
|
|
152
253
|
|
|
153
|
-
|
|
254
|
+
/**
|
|
255
|
+
* Comprehensive validation system for framework-independent graph configuration.
|
|
256
|
+
* Provides runtime validation to catch integration errors early.
|
|
257
|
+
*/
|
|
258
|
+
|
|
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 {
|
|
271
|
+
/**
|
|
272
|
+
* Validate complete graph configuration
|
|
273
|
+
*/
|
|
274
|
+
static validateConfig(config: GraphConfig): ValidationResult;
|
|
275
|
+
/**
|
|
276
|
+
* Validate container element
|
|
277
|
+
*/
|
|
278
|
+
private static validateContainer;
|
|
279
|
+
/**
|
|
280
|
+
* Validate graph nodes
|
|
281
|
+
*/
|
|
282
|
+
private static validateNodes;
|
|
283
|
+
/**
|
|
284
|
+
* Validate graph links
|
|
285
|
+
*/
|
|
286
|
+
private static validateLinks;
|
|
287
|
+
/**
|
|
288
|
+
* Validate interaction configuration
|
|
289
|
+
*/
|
|
290
|
+
private static validateInteraction;
|
|
291
|
+
/**
|
|
292
|
+
* Validate node style
|
|
293
|
+
*/
|
|
294
|
+
private static validateNodeStyle;
|
|
295
|
+
/**
|
|
296
|
+
* Validate runtime environment
|
|
297
|
+
*/
|
|
298
|
+
static validateEnvironment(): ValidationResult;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Validation error for framework integrations
|
|
302
|
+
*/
|
|
303
|
+
declare class GraphValidationError extends Error {
|
|
304
|
+
readonly errors: ValidationError[];
|
|
305
|
+
readonly warnings: string[];
|
|
306
|
+
constructor(result: ValidationResult);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Centralized error handling for framework-independent graph operations.
|
|
311
|
+
* Provides graceful degradation and helpful error messages.
|
|
312
|
+
*/
|
|
313
|
+
|
|
314
|
+
interface ErrorContext {
|
|
315
|
+
readonly operation: string;
|
|
316
|
+
readonly component?: string;
|
|
317
|
+
readonly data?: unknown;
|
|
318
|
+
}
|
|
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;
|
|
327
|
+
/**
|
|
328
|
+
* Handle errors with appropriate logging and recovery
|
|
329
|
+
*/
|
|
330
|
+
static handle(error: Error, context: ErrorContext, fallback?: () => void): void;
|
|
331
|
+
/**
|
|
332
|
+
* Wrap async operations with error handling
|
|
333
|
+
*/
|
|
334
|
+
static wrapAsync<T>(operation: () => Promise<T>, context: ErrorContext, fallback?: () => T): Promise<T>;
|
|
335
|
+
/**
|
|
336
|
+
* Wrap synchronous operations with error handling
|
|
337
|
+
*/
|
|
338
|
+
static wrap<T>(operation: () => T, context: ErrorContext, fallback?: () => T): T | undefined;
|
|
339
|
+
/**
|
|
340
|
+
* Safe DOM operation wrapper
|
|
341
|
+
*/
|
|
342
|
+
static safeDOMOperation<T>(operation: () => T, context: ErrorContext, fallback?: () => T): T | undefined;
|
|
343
|
+
/**
|
|
344
|
+
* Safe D3 operation wrapper
|
|
345
|
+
*/
|
|
346
|
+
static safeD3Operation<T>(operation: () => T, context: ErrorContext, fallback?: () => T): T | undefined;
|
|
347
|
+
/**
|
|
348
|
+
* Create recoverable error for non-critical failures
|
|
349
|
+
*/
|
|
350
|
+
static createRecoverableError(message: string, code: string, context: ErrorContext): GraphError;
|
|
351
|
+
/**
|
|
352
|
+
* Create non-recoverable error for critical failures
|
|
353
|
+
*/
|
|
354
|
+
static createCriticalError(message: string, code: string, context: ErrorContext): GraphError;
|
|
355
|
+
/**
|
|
356
|
+
* Validate and handle D3 selection operations
|
|
357
|
+
*/
|
|
358
|
+
static validateSelection<T extends {
|
|
359
|
+
size(): number;
|
|
360
|
+
}>(selection: T | null | undefined, context: ErrorContext, operation: (sel: T) => void): void;
|
|
361
|
+
/**
|
|
362
|
+
* Handle simulation errors with graceful degradation
|
|
363
|
+
*/
|
|
364
|
+
static handleSimulationError(error: Error, context: ErrorContext, simulation?: Simulation<GraphNode, GraphLink>): void;
|
|
365
|
+
/**
|
|
366
|
+
* Mark error handler as destroyed to prevent further operations
|
|
367
|
+
*/
|
|
368
|
+
static destroy(): void;
|
|
369
|
+
/**
|
|
370
|
+
* Reset error handler state
|
|
371
|
+
*/
|
|
372
|
+
static reset(): void;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Framework-independent event emitter for graph events.
|
|
377
|
+
* Provides better TypeScript support and event namespacing than manual Set management.
|
|
378
|
+
*/
|
|
379
|
+
|
|
380
|
+
type EventListener<T> = (data: T, element?: Element) => void;
|
|
381
|
+
interface EventUnsubscribe {
|
|
382
|
+
(): void;
|
|
383
|
+
}
|
|
384
|
+
interface EventEmitterOptions {
|
|
385
|
+
readonly maxListeners?: number;
|
|
386
|
+
readonly enableWarnings?: boolean;
|
|
387
|
+
}
|
|
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);
|
|
394
|
+
/**
|
|
395
|
+
* Add an event listener
|
|
396
|
+
*/
|
|
397
|
+
on<TEvent extends keyof TEventMap>(event: TEvent, listener: EventListener<TEventMap[TEvent]>, namespace?: string): EventUnsubscribe;
|
|
398
|
+
/**
|
|
399
|
+
* Add a one-time event listener
|
|
400
|
+
*/
|
|
401
|
+
once<TEvent extends keyof TEventMap>(event: TEvent, listener: EventListener<TEventMap[TEvent]>, namespace?: string): EventUnsubscribe;
|
|
402
|
+
/**
|
|
403
|
+
* Remove a specific listener
|
|
404
|
+
*/
|
|
405
|
+
off<TEvent extends keyof TEventMap>(event: TEvent, listener: EventListener<TEventMap[TEvent]>): void;
|
|
406
|
+
/**
|
|
407
|
+
* Remove listener by ID
|
|
408
|
+
*/
|
|
409
|
+
private removeListener;
|
|
410
|
+
/**
|
|
411
|
+
* Remove all listeners for an event or namespace
|
|
412
|
+
*/
|
|
413
|
+
removeAllListeners<TEvent extends keyof TEventMap>(event?: TEvent, namespace?: string): void;
|
|
414
|
+
/**
|
|
415
|
+
* Emit an event to all listeners
|
|
416
|
+
*/
|
|
417
|
+
emit<TEvent extends keyof TEventMap>(event: TEvent, data: TEventMap[TEvent], element?: Element): boolean;
|
|
418
|
+
/**
|
|
419
|
+
* Get the number of listeners for an event
|
|
420
|
+
*/
|
|
421
|
+
listenerCount<TEvent extends keyof TEventMap>(event: TEvent): number;
|
|
422
|
+
/**
|
|
423
|
+
* Get all event names that have listeners
|
|
424
|
+
*/
|
|
425
|
+
eventNames(): Array<keyof TEventMap>;
|
|
426
|
+
/**
|
|
427
|
+
* Get listeners for an event
|
|
428
|
+
*/
|
|
429
|
+
getListeners<TEvent extends keyof TEventMap>(event: TEvent): Array<EventListener<TEventMap[TEvent]>>;
|
|
430
|
+
/**
|
|
431
|
+
* Check if an event has listeners
|
|
432
|
+
*/
|
|
433
|
+
hasListeners<TEvent extends keyof TEventMap>(event: TEvent): boolean;
|
|
434
|
+
/**
|
|
435
|
+
* Get debug information about the emitter
|
|
436
|
+
*/
|
|
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
|
+
};
|
|
448
|
+
/**
|
|
449
|
+
* Clean up all listeners and mark as destroyed
|
|
450
|
+
*/
|
|
451
|
+
destroy(): void;
|
|
452
|
+
/**
|
|
453
|
+
* Reset the emitter (clear listeners but allow new ones)
|
|
454
|
+
*/
|
|
455
|
+
reset(): void;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Graph-specific event types
|
|
459
|
+
*/
|
|
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': {
|
|
488
|
+
scale: number;
|
|
489
|
+
x: number;
|
|
490
|
+
y: number;
|
|
491
|
+
};
|
|
492
|
+
'zoomEnd': {
|
|
493
|
+
scale: number;
|
|
494
|
+
x: number;
|
|
495
|
+
y: number;
|
|
496
|
+
};
|
|
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
|
+
/**
|
|
541
|
+
* Centralized selection management for graph nodes and links.
|
|
542
|
+
* Simplifies selection logic and ensures consistent behavior.
|
|
543
|
+
*/
|
|
544
|
+
|
|
545
|
+
interface SelectionState {
|
|
546
|
+
selectedNode: {
|
|
547
|
+
element: SVGCircleElement;
|
|
548
|
+
data: GraphNode;
|
|
549
|
+
} | null;
|
|
550
|
+
selectedLink: {
|
|
551
|
+
element: SVGLineElement;
|
|
552
|
+
data: GraphLink;
|
|
553
|
+
originalMarker: string | null;
|
|
554
|
+
} | null;
|
|
555
|
+
}
|
|
556
|
+
declare class SelectionManager {
|
|
557
|
+
private state;
|
|
558
|
+
private readonly eventEmitter;
|
|
559
|
+
private readonly config;
|
|
560
|
+
private readonly layers;
|
|
561
|
+
private readonly linkMarkerSnapshots;
|
|
562
|
+
private readonly root;
|
|
563
|
+
constructor(eventEmitter: TypedGraphEventEmitter, config: SelectionInteractionConfig, layers: GraphLayers, linkMarkerSnapshots: Map<SVGLineElement, string | null>, root: Selection<SVGGElement, unknown, null, undefined>);
|
|
564
|
+
/**
|
|
565
|
+
* Select a node, automatically deselecting any current selection
|
|
566
|
+
*/
|
|
567
|
+
selectNode(nodeElement: SVGCircleElement, nodeData: GraphNode): void;
|
|
568
|
+
/**
|
|
569
|
+
* Select a link, automatically deselecting any current selection
|
|
570
|
+
*/
|
|
571
|
+
selectLink(linkElement: SVGLineElement, renderableLink: RenderableGraphLink, event?: MouseEvent): void;
|
|
572
|
+
/**
|
|
573
|
+
* Deselect the currently selected node
|
|
574
|
+
*/
|
|
575
|
+
private deselectNode;
|
|
576
|
+
/**
|
|
577
|
+
* Deselect the currently selected link
|
|
578
|
+
*/
|
|
579
|
+
private deselectLink;
|
|
580
|
+
/**
|
|
581
|
+
* Clear all selections
|
|
582
|
+
*/
|
|
583
|
+
clearSelection(): void;
|
|
584
|
+
/**
|
|
585
|
+
* Get current selection state
|
|
586
|
+
*/
|
|
587
|
+
getSelectionState(): SelectionState;
|
|
588
|
+
/**
|
|
589
|
+
* Check if a specific node is selected
|
|
590
|
+
*/
|
|
591
|
+
isNodeSelected(nodeData: GraphNode): boolean;
|
|
592
|
+
/**
|
|
593
|
+
* Check if a specific link is selected
|
|
594
|
+
*/
|
|
595
|
+
isLinkSelected(linkData: GraphLink): boolean;
|
|
596
|
+
/**
|
|
597
|
+
* Handle click on background (deselect all)
|
|
598
|
+
*/
|
|
599
|
+
handleBackgroundClick(event: MouseEvent, svg: SVGSVGElement, interactionRect: SVGRectElement): void;
|
|
600
|
+
/**
|
|
601
|
+
* Bring node and related elements to front using selection layer sub-layers
|
|
602
|
+
*/
|
|
603
|
+
private bringNodeToFront;
|
|
604
|
+
/**
|
|
605
|
+
* Bring link and its label to front using selection layer
|
|
606
|
+
*/
|
|
607
|
+
private bringLinkToFront;
|
|
608
|
+
/**
|
|
609
|
+
* Restore elements back to their original layers
|
|
610
|
+
*/
|
|
611
|
+
private restoreSelectedElements;
|
|
612
|
+
/**
|
|
613
|
+
* Utility method to bring any SVG element to front using appendChild
|
|
614
|
+
* Based on the reference implementation pattern
|
|
615
|
+
*/
|
|
616
|
+
private bringElementToFront;
|
|
617
|
+
/**
|
|
618
|
+
* Clear hover state to prevent conflicts with selection
|
|
619
|
+
* Similar to the clearAllHoverLayers function in create-node-hover.ts
|
|
620
|
+
*/
|
|
621
|
+
private clearHoverState;
|
|
622
|
+
/**
|
|
623
|
+
* Clean up resources
|
|
624
|
+
*/
|
|
625
|
+
destroy(): void;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
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 };
|