@neo4j-nvl/base 2.0.0-8a6da460 → 2.0.0-c8e499dc

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.
@@ -0,0 +1,596 @@
1
+ # NVL — API Surface Reference
2
+
3
+ Source: `@neo4j-nvl/base@2.0`, `@neo4j-nvl/interaction-handlers@2.0`, `@neo4j-nvl/react@2.0`.
4
+
5
+ ## Packages
6
+
7
+ | Package | Main export | Notes |
8
+ |---|---|---|
9
+ | `@neo4j-nvl/base` | `NVL` (also default), types, `nvlResultTransformer`, layout constants | Framework-agnostic core |
10
+ | `@neo4j-nvl/interaction-handlers` | `ZoomInteraction`, `PanInteraction`, `ClickInteraction`, `HoverInteraction`, `DragNodeInteraction`, `BoxSelectInteraction`, `LassoInteraction`, `KeyboardInteraction` | Compose onto an `NVL` instance |
11
+ | `@neo4j-nvl/react` | `InteractiveNvlWrapper`, `BasicNvlWrapper`, `StaticPictureWrapper` | React 19 |
12
+ | `@neo4j-nvl/layout-workers` | (transitive) | Force-directed + hierarchical workers |
13
+
14
+ ---
15
+
16
+ ## `NVL` Class
17
+
18
+ ### Constructor
19
+
20
+ ```typescript
21
+ new NVL(
22
+ frame: HTMLElement,
23
+ nvlNodes?: Node[], // default []
24
+ nvlRels?: Relationship[], // default []
25
+ options?: NvlOptions, // default {}
26
+ callbacks?: ExternalCallbacks // default {}
27
+ )
28
+ ```
29
+
30
+ ### Element CRUD
31
+
32
+ | Method | Signature | Purpose |
33
+ |---|---|---|
34
+ | `addAndUpdateElementsInGraph` | `(nodes: Node[] \| PartialNode[], rels: Relationship[] \| PartialRelationship[]) => void` | Insert new; update existing by id |
35
+ | `addElementsToGraph` | `(nodes: Node[], rels: Relationship[]) => void` | Insert only |
36
+ | `updateElementsInGraph` | `(nodes: PartialNode[], rels: PartialRelationship[]) => void` | Update existing only; ignores unknown ids |
37
+ | `removeNodesWithIds` | `(ids: string[]) => void` | Remove nodes + adjacent relationships |
38
+ | `removeRelationshipsWithIds` | `(ids: string[]) => void` | Remove relationships |
39
+
40
+ ### Element Read
41
+
42
+ | Method | Signature |
43
+ |---|---|
44
+ | `getNodes` | `() => NodeWithClientPosition[]` |
45
+ | `getRelationships` | `() => Relationship[]` |
46
+ | `getNodeById` | `(id: string) => Node` |
47
+ | `getRelationshipById` | `(id: string) => Relationship` |
48
+ | `getPositionById` | `(id: string) => Node` |
49
+ | `getNodesOnScreen` | `() => { nodes: Node[]; rels: Relationship[] }` |
50
+ | `getNodePositions` | `() => (Node & Point)[]` |
51
+ | `setNodePositions` | `(data: Node[], updateLayout?: boolean) => void` |
52
+ | `getSelectedNodes` | `() => (Node & Point)[]` |
53
+ | `getSelectedRelationships` | `() => Relationship[]` |
54
+ | `deselectAll` | `() => void` |
55
+
56
+ ### Viewport
57
+
58
+ | Method | Signature |
59
+ |---|---|
60
+ | `fit` | `(nodeIds: string[], zoomOptions?: ZoomOptions) => void` (empty array = fit all) |
61
+ | `resetZoom` | `() => void` |
62
+ | `setZoom` | `(zoom: number) => void` |
63
+ | `setPan` | `(panX: number, panY: number) => void` |
64
+ | `setZoomAndPan` | `(zoom: number, panX: number, panY: number) => void` |
65
+ | `getScale` | `() => number` |
66
+ | `getPan` | `() => Point` |
67
+ | `getZoomLimits` | `() => { minZoom: number; maxZoom: number }` |
68
+
69
+ ### Layout / Renderer / Pin
70
+
71
+ | Method | Signature |
72
+ |---|---|
73
+ | `setLayout` | `(layout: Layout) => void` |
74
+ | `setLayoutOptions` | `(options: LayoutOptions) => void` |
75
+ | `isLayoutMoving` | `() => boolean` |
76
+ | `setRenderer` | `(renderer: 'canvas' \| 'webgl') => void` |
77
+ | `setDisableWebGL` | `(disabled?: boolean) => void` |
78
+ | `pinNode` | `(nodeId: string) => void` |
79
+ | `unPinNode` | `(nodeIds: string[]) => void` |
80
+
81
+ ### Export / Save
82
+
83
+ | Method | Signature |
84
+ |---|---|
85
+ | `saveToFile` | `(opts?: { filename?: string; backgroundColor?: string }) => void` (PNG of current view) |
86
+ | `saveFullGraphToLargeFile` | `(opts?: { filename?: string; backgroundColor?: string }) => void` (PNG of full graph) |
87
+ | `saveToSvg` | `(opts?: { filename?: string; backgroundColor?: string }) => void` (experimental) |
88
+ | `getImageDataUrl` | `(opts?: { backgroundColor?: string }) => string` |
89
+ | `getSvgDataUrl` | `(opts?: { backgroundColor?: string }) => Promise<string>` |
90
+
91
+ ### Hit Testing
92
+
93
+ ```typescript
94
+ getHits(
95
+ evt: MouseEvent,
96
+ targets?: ('node' | 'relationship' | 'cluster')[], // default: all three
97
+ hitOptions?: { hitNodeMarginWidth: number } // default 0
98
+ ): NvlMouseEvent
99
+ ```
100
+
101
+ ### Lifecycle / Misc
102
+
103
+ | Method | Signature |
104
+ |---|---|
105
+ | `getCurrentOptions` | `() => NvlOptions` |
106
+ | `getContainer` | `() => HTMLElement` |
107
+ | `restart` | `(options?: NvlOptions, retainPositions?: boolean) => void` |
108
+ | `destroy` | `() => void` |
109
+
110
+ ---
111
+
112
+ ## Core Types
113
+
114
+ ### `Node`
115
+
116
+ | Field | Type | Notes |
117
+ |---|---|---|
118
+ | `id` | `string` | Required; unique across nodes AND relationships |
119
+ | `caption` | `string` | Single caption (superseded by `captions`) |
120
+ | `captions` | `StyledCaption[]` | Multi-line captions with styles |
121
+ | `captionSize` | `number` | Text size |
122
+ | `captionAlign` | `'top' \| 'bottom' \| 'center'` | |
123
+ | `color` | `string` | Fill color |
124
+ | `size` | `number` | Radius |
125
+ | `pinned` | `boolean` | Excluded from layout forces |
126
+ | `x` / `y` | `number` | Position |
127
+ | `selected` | `boolean` | |
128
+ | `hovered` | `boolean` | |
129
+ | `activated` | `boolean` | |
130
+ | `disabled` | `boolean` | |
131
+ | `icon` | `string` | URL to image inside node |
132
+ | `html` | `HTMLElement` | DOM overlay |
133
+ | `overlayIcon` | `{ url: string; position?: number[]; size?: number }` | |
134
+
135
+ `getNodes()` and `onLayoutStep` use:
136
+
137
+ ```typescript
138
+ type NodeWithClientPosition = Node & Point & {
139
+ clientPosition: Point
140
+ }
141
+ ```
142
+
143
+ `x` and `y` are canvas/layout coordinates. `clientPosition` is relative to the canvas element.
144
+
145
+ ### `Relationship`
146
+
147
+ | Field | Type | Notes |
148
+ |---|---|---|
149
+ | `id` | `string` | Required; unique across nodes AND relationships |
150
+ | `from` | `string` | Source node id |
151
+ | `to` | `string` | Target node id |
152
+ | `type` | `string` | Relationship type label |
153
+ | `width` | `number` | |
154
+ | `color` | `string` | |
155
+ | `caption` / `captions` / `captionSize` / `captionAlign` | (same as Node) | |
156
+ | `captionHtml` | `HTMLElement` | DOM overlay on caption |
157
+ | `selected` / `hovered` / `disabled` | `boolean` | |
158
+
159
+ ### Partial types
160
+
161
+ ```typescript
162
+ type PartialNode = Partial<Node> & { id: string }
163
+ type PartialRelationship = Partial<Relationship> & { id: string }
164
+ ```
165
+
166
+ ---
167
+
168
+ ## `NvlOptions`
169
+
170
+ | Field | Type | Default | Notes |
171
+ |---|---|---|---|
172
+ | `instanceId` | `string` | — | |
173
+ | `layout` | `Layout` | `'forceDirected'` | See Layout enum below |
174
+ | `layoutOptions` | `LayoutOptions` | — | Layout-specific |
175
+ | `layoutTimeLimit` | `number` | — | ms cap for layout iteration |
176
+ | `minFps` | `number` | `3` | Minimum presentation target while layout is active; capped to `1..120` |
177
+ | `maxFps` | `number` | `30` | Maximum presentation target while layout is active; capped to `1..120` |
178
+ | `minZoom` | `number` | `0.075` | |
179
+ | `maxZoom` | `number` | `10` | |
180
+ | `allowDynamicMinZoom` | `boolean` | `true` | Permits going below `minZoom` to fit |
181
+ | `initialZoom` | `number` | — | |
182
+ | `panX` / `panY` | `number` | — | |
183
+ | `renderer` | `'canvas' \| 'webgl'` | `'canvas'` | WebGL is WebGL2-only and does not render captions |
184
+ | `disableWebGL` | `boolean` | `false` | Force-off WebGL even if requested |
185
+ | `disableWebWorkers` | `boolean` | `false` | Use synchronous layout fallback |
186
+ | `disableTelemetry` | `boolean` | `false` | |
187
+ | `disableAria` | `boolean` | `false` | |
188
+ | `minimapContainer` | `HTMLElement \| null` | — | |
189
+ | `styling` | `StylingOptions` | — | |
190
+ | `callbacks` | `ExternalCallbacks` | — | (also passable as 5th constructor arg) |
191
+ | `logging` | `{ level: LogLevelDesc }` | — | |
192
+
193
+ ### `StylingOptions`
194
+
195
+ | Field | Type |
196
+ |---|---|
197
+ | `defaultNodeColor` | `string` |
198
+ | `defaultRelationshipColor` | `string` |
199
+ | `nodeDefaultBorderColor` | `string` |
200
+ | `selectedBorderColor` | `string` |
201
+ | `selectedInnerBorderColor` | `string` |
202
+ | `dropShadowColor` | `string` |
203
+ | `disabledItemColor` | `string` |
204
+ | `disabledItemFontColor` | `string` |
205
+ | `overlayLineColor` | `string` |
206
+ | `minimapViewportBoxColor` | `string` (deprecated; use `overlayLineColor`) |
207
+
208
+ ### Layout enum + constants
209
+
210
+ ```typescript
211
+ type Layout = 'forceDirected' | 'hierarchical' | 'grid' | 'free' | 'd3Force' | 'circular'
212
+
213
+ // Exported constants (string literals):
214
+ ForceDirectedLayoutType // 'forceDirected'
215
+ HierarchicalLayoutType // 'hierarchical'
216
+ GridLayoutType // 'grid'
217
+ FreeLayoutType // 'free'
218
+ d3ForceLayoutType // 'd3Force'
219
+ CircularLayoutType // 'circular'
220
+ ```
221
+
222
+ ### `LayoutOptions` union
223
+
224
+ ```typescript
225
+ type LayoutOptions = ForceDirectedOptions | HierarchicalOptions | CircularOptions
226
+
227
+ interface ForceDirectedOptions {
228
+ seedingMethod?: 'box' | 'circle'
229
+ clustering?: ClusteringOptions
230
+ }
231
+
232
+ type ClusterId = string | number
233
+ type ClusterByFn = (nodeId: string) => ClusterId | undefined
234
+
235
+ interface ClusteringOptions {
236
+ clusterBy?: ClusterByFn
237
+ drawOutline?: boolean
238
+ drawHalo?: boolean
239
+ crossClusterRelationshipMultiplier?: number // experimental, capped to 0..1
240
+ }
241
+
242
+ interface HierarchicalOptions {
243
+ direction?: 'up' | 'down' | 'left' | 'right'
244
+ packing?: 'bin' | 'stack'
245
+ clusterBy?: ClusterByFn // experimental
246
+ }
247
+
248
+ interface CircularOptions {
249
+ sortFunction?: (nodes: Node[]) => Node[]
250
+ }
251
+ ```
252
+
253
+ ### `ZoomOptions`
254
+
255
+ | Field | Type | Purpose |
256
+ |---|---|---|
257
+ | `noPan` | `boolean` | Zoom without changing pan |
258
+ | `outOnly` | `boolean` | Only zoom out to fit |
259
+ | `minZoom` | `number` | Override for this op |
260
+ | `maxZoom` | `number` | Override for this op |
261
+ | `animated` | `boolean` | Animate transition |
262
+
263
+ ### Renderer constants
264
+
265
+ ```typescript
266
+ type Renderer = 'webgl' | 'canvas'
267
+
268
+ WebGLRendererType // 'webgl'
269
+ CanvasRendererType // 'canvas'
270
+ ```
271
+
272
+ ### `StyledCaption`
273
+
274
+ ```typescript
275
+ type StyledCaption = {
276
+ styles: string[] // e.g. ['bold','italic']
277
+ value: string
278
+ key: string
279
+ }
280
+ ```
281
+
282
+ ### `Point`
283
+
284
+ ```typescript
285
+ type Point = { x: number; y: number }
286
+ ```
287
+
288
+ ---
289
+
290
+ ## `ExternalCallbacks`
291
+
292
+ | Callback | Signature |
293
+ |---|---|
294
+ | `onInitialization` | `() => void` |
295
+ | `onLayoutDone` | `() => void` |
296
+ | `onLayoutStep` | `(nodes: NodeWithClientPosition[]) => void` |
297
+ | `onLayoutComputing` | `(isComputing: boolean) => void` |
298
+ | `onError` | `(error: Error) => void` |
299
+ | `onWebGLContextLost` | `(event: WebGLContextEvent) => void` |
300
+ | `onZoomTransitionDone` | `() => void` |
301
+ | `restart` | `() => void` |
302
+
303
+ ---
304
+
305
+ ## Hit Testing Types
306
+
307
+ ```typescript
308
+ interface NvlMouseEvent extends MouseEvent {
309
+ nvlTargets: HitTargets
310
+ }
311
+
312
+ type HitTargets = {
313
+ nodes: HitTargetNode[]
314
+ relationships: HitTargetRelationship[]
315
+ clusters: HitTargetCluster[]
316
+ }
317
+
318
+ interface HitTargetNode {
319
+ data: Node
320
+ targetCoordinates: Point
321
+ pointerCoordinates: Point
322
+ distanceVector: Point
323
+ distance: number
324
+ insideNode: boolean
325
+ }
326
+
327
+ interface HitTargetRelationship {
328
+ data: Relationship
329
+ fromTargetCoordinates: Point
330
+ toTargetCoordinates: Point
331
+ pointerCoordinates: Point
332
+ distance: number
333
+ }
334
+
335
+ type Cluster = {
336
+ id: string | number
337
+ nodeIds: string[]
338
+ }
339
+
340
+ interface HitTargetCluster {
341
+ data: Cluster
342
+ pointerCoordinates: Point
343
+ hull: Point[]
344
+ }
345
+ ```
346
+
347
+ ---
348
+
349
+ ## `nvlResultTransformer`
350
+
351
+ ```typescript
352
+ import type { ResultTransformer, EagerResult } from 'neo4j-driver'
353
+
354
+ const nvlResultTransformer: ResultTransformer<
355
+ EagerResult,
356
+ { nodes: Node[]; relationships: Relationship[] }
357
+ >
358
+ ```
359
+
360
+ Usage: `driver.executeQuery(cypher, params, { database: 'neo4j', resultTransformer: nvlResultTransformer })`. Returns deduplicated `{ nodes, relationships }`.
361
+
362
+ ---
363
+
364
+ ## Named Exports — `@neo4j-nvl/base`
365
+
366
+ ```typescript
367
+ // values
368
+ export {
369
+ NVL, // also default export
370
+ nvlResultTransformer,
371
+ colorMapperFunctions,
372
+ CompatibilityError,
373
+ drawCircleBand,
374
+ getZoomTargetForNodePositions,
375
+ ForceDirectedLayoutType,
376
+ HierarchicalLayoutType,
377
+ GridLayoutType,
378
+ FreeLayoutType,
379
+ d3ForceLayoutType,
380
+ CircularLayoutType
381
+ }
382
+
383
+ // types
384
+ export type {
385
+ NvlOptions, Renderer, Node, NodeWithClientPosition, Relationship,
386
+ PartialNode, PartialRelationship,
387
+ Layout, LayoutOptions, ForceDirectedOptions, ClusteringOptions,
388
+ Cluster, ClusterByFn, ClusterId, HierarchicalOptions, CircularOptions,
389
+ ExternalCallbacks, HitTargets, HitTargetNode, HitTargetRelationship,
390
+ HitTargetCluster, HitTestTarget,
391
+ Point, NvlMouseEvent, ZoomOptions, StyledCaption,
392
+ WebGLRendererType, CanvasRendererType
393
+ }
394
+ ```
395
+
396
+ ---
397
+
398
+ ## Interaction Handlers
399
+
400
+ All extend `BaseInteraction<P>`:
401
+
402
+ ```typescript
403
+ class BaseInteraction<P> {
404
+ constructor(nvl: NVL, options?: P)
405
+ updateCallback(name: string, callback: ((...args: unknown[]) => void) | boolean): void
406
+ removeCallback(name: string): void
407
+ destroy(): void
408
+ readonly currentOptions: P
409
+ }
410
+ ```
411
+
412
+ Callback semantics: `function` = enable + invoke; `true` = enable as no-op; omitted/removed = disable.
413
+
414
+ ### `ZoomInteraction`
415
+
416
+ ```typescript
417
+ new ZoomInteraction(nvl, options?: { controlledZoom?: boolean })
418
+ ```
419
+
420
+ | Event | Signature |
421
+ |---|---|
422
+ | `onZoomAndPan` | `(zoomLevel: number, panX: number, panY: number, event: WheelEvent) => void` |
423
+
424
+ ### `PanInteraction`
425
+
426
+ ```typescript
427
+ new PanInteraction(nvl, options?: { excludeNodeMargin?: boolean; controlledPan?: boolean })
428
+ panInteraction.updateTargets(targets: ('node'|'relationship')[], excludeNodeMargin: boolean): void
429
+ ```
430
+
431
+ | Event | Signature |
432
+ |---|---|
433
+ | `onPan` | `(panning: { x: number; y: number }, event: MouseEvent) => void` |
434
+
435
+ ### `ClickInteraction`
436
+
437
+ ```typescript
438
+ new ClickInteraction(nvl, options?: { selectOnClick?: boolean })
439
+ ```
440
+
441
+ | Event | Signature |
442
+ |---|---|
443
+ | `onNodeClick` | `(node: Node, hits: HitTargets, event: MouseEvent) => void` |
444
+ | `onRelationshipClick` | `(rel: Relationship, hits: HitTargets, event: MouseEvent) => void` |
445
+ | `onClusterClick` | `(cluster: Cluster, hits: HitTargets, event: MouseEvent) => void` |
446
+ | `onCanvasClick` | `(event: MouseEvent) => void` |
447
+ | `onNodeDoubleClick` | `(node, hits, event) => void` |
448
+ | `onRelationshipDoubleClick` | `(rel, hits, event) => void` |
449
+ | `onClusterDoubleClick` | `(cluster, hits, event) => void` |
450
+ | `onCanvasDoubleClick` | `(event) => void` |
451
+ | `onNodeRightClick` | `(node, hits, event) => void` |
452
+ | `onRelationshipRightClick` | `(rel, hits, event) => void` |
453
+ | `onClusterRightClick` | `(cluster, hits, event) => void` |
454
+ | `onCanvasRightClick` | `(event) => void` |
455
+
456
+ ### `HoverInteraction`
457
+
458
+ ```typescript
459
+ new HoverInteraction(nvl, options?: { drawShadowOnHover?: boolean })
460
+ ```
461
+
462
+ | Event | Signature |
463
+ |---|---|
464
+ | `onHover` | `(element: Node \| Relationship \| undefined, hits: HitTargets, event: MouseEvent) => void` |
465
+
466
+ ### `DragNodeInteraction`
467
+
468
+ ```typescript
469
+ new DragNodeInteraction(nvl)
470
+ ```
471
+
472
+ | Event | Signature |
473
+ |---|---|
474
+ | `onDragStart` | `(nodes: Node[], event: MouseEvent) => void` |
475
+ | `onDrag` | `(nodes: Node[], event: MouseEvent) => void` |
476
+ | `onDragEnd` | `(nodes: Node[], event: MouseEvent) => void` |
477
+
478
+ ### `BoxSelectInteraction`
479
+
480
+ ```typescript
481
+ new BoxSelectInteraction(nvl, options?: { selectOnRelease?: boolean })
482
+ ```
483
+
484
+ | Event | Signature |
485
+ |---|---|
486
+ | `onBoxStarted` | `(event: MouseEvent) => void` |
487
+ | `onBoxSelect` | `(selection: { nodes: Node[]; rels: Relationship[] }, event: MouseEvent) => void` |
488
+
489
+ ### `LassoInteraction`
490
+
491
+ ```typescript
492
+ new LassoInteraction(nvl, options?: { selectOnRelease?: boolean })
493
+ ```
494
+
495
+ | Event | Signature |
496
+ |---|---|
497
+ | `onLassoStarted` | `(event: MouseEvent) => void` |
498
+ | `onLassoSelect` | `(selection: { nodes: Node[]; rels: Relationship[] }, event: MouseEvent) => void` |
499
+
500
+ ### `KeyboardInteraction`
501
+
502
+ ```typescript
503
+ new KeyboardInteraction(nvl, options?: {
504
+ enterGraphKey?: string[]
505
+ navigateForwardKey?: string[]
506
+ navigateBackwardKey?:string[]
507
+ exitGraphKey?: string[]
508
+ contextMenuKey?: string[]
509
+ })
510
+ keyboard.getFocused(): Node | Relationship | undefined
511
+ ```
512
+
513
+ | Event | Signature |
514
+ |---|---|
515
+ | `onKeyDown` | `(event: KeyboardEvent, focused?: Node \| Relationship) => void` |
516
+ | `onKeyUp` | `(event: KeyboardEvent, focused?: Node \| Relationship) => void` |
517
+ | `onNodeFocus` / `onNodeBlur` | `(node: Node, event: KeyboardEvent) => void` |
518
+ | `onRelationshipFocus` / `onRelationshipBlur` | `(rel: Relationship, event: KeyboardEvent) => void` |
519
+ | `onCanvasFocus` / `onCanvasBlur` | `(event: FocusEvent) => void` |
520
+ | `onContextMenu` | `(element: Node \| Relationship \| undefined, event: KeyboardEvent) => void` |
521
+
522
+ ---
523
+
524
+ ## React Components
525
+
526
+ ### `<InteractiveNvlWrapper>`
527
+
528
+ | Prop | Type | Notes |
529
+ |---|---|---|
530
+ | `nodes` | `Node[]` | |
531
+ | `rels` | `Relationship[]` | |
532
+ | `nvlOptions` | `NvlOptions` | |
533
+ | `nvlCallbacks` | `ExternalCallbacks` | |
534
+ | `positions` | `Node[]` | |
535
+ | `zoom` | `number` | |
536
+ | `pan` | `{ x: number; y: number }` | |
537
+ | `mouseEventCallbacks` | `MouseEventCallbacks` | See below |
538
+ | `keyboardEventCallbacks` | `KeyboardEventCallbacks` | See below |
539
+ | `interactionOptions` | `InteractionOptions` | Defaults: `{ selectOnClick: false, drawShadowOnHover: true, selectOnRelease: false, excludeNodeMargin: true }` |
540
+ | `onInitializationError` | `(error: unknown) => void` | |
541
+ | `ref` | `Ref<NVL>` | Underlying NVL instance |
542
+ | (plus `HTMLProps<HTMLDivElement>`) | | |
543
+
544
+ ### `<BasicNvlWrapper>`
545
+
546
+ Same prop set EXCEPT no `mouseEventCallbacks` / `keyboardEventCallbacks` / `interactionOptions`. `ref` resolves to `IncludeMethods<NVL>` — exposes all NVL public methods.
547
+
548
+ ### `<StaticPictureWrapper>`
549
+
550
+ | Prop | Type | Default |
551
+ |---|---|---|
552
+ | `nodes` | `Node[]` | — |
553
+ | `rels` | `Relationship[]` | — |
554
+ | `nvlOptions` | `NvlOptions` | — |
555
+ | `width` | `number` | `500` |
556
+ | `height` | `number` | `500` |
557
+ | `format` | `'png' \| 'svg'` | `'png'` |
558
+
559
+ Renders an ephemeral NVL, fits viewport, captures, destroys. Returns `<img />`.
560
+
561
+ ### `MouseEventCallbacks`
562
+
563
+ Union of all handler callbacks. Each value can be a function (with the signature above), `true` (enabled, no callback), or omitted / `false` (disabled):
564
+
565
+ ```
566
+ onNodeClick, onRelationshipClick, onCanvasClick,
567
+ onClusterClick,
568
+ onNodeDoubleClick, onRelationshipDoubleClick, onClusterDoubleClick, onCanvasDoubleClick,
569
+ onNodeRightClick, onRelationshipRightClick, onClusterRightClick, onCanvasRightClick,
570
+ onHover,
571
+ onPan, onZoomAndPan,
572
+ onDragStart, onDrag, onDragEnd,
573
+ onBoxStarted, onBoxSelect,
574
+ onLassoStarted, onLassoSelect,
575
+ onHoverNodeMargin, onDrawStarted, onDrawEnded
576
+ ```
577
+
578
+ ### `KeyboardEventCallbacks`
579
+
580
+ ```
581
+ onKeyDown, onKeyUp,
582
+ onNodeFocus, onNodeBlur,
583
+ onRelationshipFocus, onRelationshipBlur,
584
+ onCanvasFocus, onCanvasBlur,
585
+ onContextMenu
586
+ ```
587
+
588
+ ### `InteractionOptions`
589
+
590
+ Merged union of every handler's options:
591
+
592
+ ```
593
+ { selectOnClick?, drawShadowOnHover?, selectOnRelease?, excludeNodeMargin?, controlledZoom?,
594
+ controlledPan?, enterGraphKey?, navigateForwardKey?, navigateBackwardKey?, exitGraphKey?,
595
+ contextMenuKey?, ghostGraphStyling? }
596
+ ```