@memberjunction/ng-entity-relationship-diagram 5.30.1 → 5.32.0

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.
Files changed (40) hide show
  1. package/dist/__tests__/compute-erd-layout.test.d.ts +2 -0
  2. package/dist/__tests__/compute-erd-layout.test.d.ts.map +1 -0
  3. package/dist/__tests__/compute-erd-layout.test.js +207 -0
  4. package/dist/__tests__/compute-erd-layout.test.js.map +1 -0
  5. package/dist/lib/components/entity-details/entity-details.component.d.ts +2 -1
  6. package/dist/lib/components/entity-details/entity-details.component.d.ts.map +1 -1
  7. package/dist/lib/components/entity-details/entity-details.component.js +7 -7
  8. package/dist/lib/components/entity-details/entity-details.component.js.map +1 -1
  9. package/dist/lib/components/entity-filter-panel/entity-filter-panel.component.d.ts +10 -4
  10. package/dist/lib/components/entity-filter-panel/entity-filter-panel.component.d.ts.map +1 -1
  11. package/dist/lib/components/entity-filter-panel/entity-filter-panel.component.js +60 -72
  12. package/dist/lib/components/entity-filter-panel/entity-filter-panel.component.js.map +1 -1
  13. package/dist/lib/components/erd-composite/erd-composite.component.d.ts +4 -1
  14. package/dist/lib/components/erd-composite/erd-composite.component.d.ts.map +1 -1
  15. package/dist/lib/components/erd-composite/erd-composite.component.js +22 -8
  16. package/dist/lib/components/erd-composite/erd-composite.component.js.map +1 -1
  17. package/dist/lib/components/erd-diagram.component.d.ts +169 -443
  18. package/dist/lib/components/erd-diagram.component.d.ts.map +1 -1
  19. package/dist/lib/components/erd-diagram.component.js +916 -1777
  20. package/dist/lib/components/erd-diagram.component.js.map +1 -1
  21. package/dist/lib/components/mj-entity-erd.component.d.ts +3 -2
  22. package/dist/lib/components/mj-entity-erd.component.d.ts.map +1 -1
  23. package/dist/lib/components/mj-entity-erd.component.js +6 -6
  24. package/dist/lib/components/mj-entity-erd.component.js.map +1 -1
  25. package/dist/lib/entity-relationship-diagram.module.d.ts +2 -1
  26. package/dist/lib/entity-relationship-diagram.module.d.ts.map +1 -1
  27. package/dist/lib/entity-relationship-diagram.module.js +9 -3
  28. package/dist/lib/entity-relationship-diagram.module.js.map +1 -1
  29. package/dist/lib/interfaces/erd-types.d.ts +38 -7
  30. package/dist/lib/interfaces/erd-types.d.ts.map +1 -1
  31. package/dist/lib/interfaces/erd-types.js.map +1 -1
  32. package/dist/lib/layout/compute-dagre-layout.d.ts +32 -0
  33. package/dist/lib/layout/compute-dagre-layout.d.ts.map +1 -0
  34. package/dist/lib/layout/compute-dagre-layout.js +168 -0
  35. package/dist/lib/layout/compute-dagre-layout.js.map +1 -0
  36. package/dist/lib/layout/compute-erd-layout.d.ts +103 -0
  37. package/dist/lib/layout/compute-erd-layout.d.ts.map +1 -0
  38. package/dist/lib/layout/compute-erd-layout.js +254 -0
  39. package/dist/lib/layout/compute-erd-layout.js.map +1 -0
  40. package/package.json +6 -5
@@ -1,488 +1,214 @@
1
- import { EventEmitter, ElementRef, AfterViewInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
2
- import { ERDNode, ERDLink, ERDConfig, ERDNodeClickEvent, ERDNodeDoubleClickEvent, ERDLinkClickEvent, ERDZoomEvent, ERDState, ERDNodeHoverEvent, ERDLinkHoverEvent, ERDNodeContextMenuEvent, ERDLinkContextMenuEvent, ERDDiagramContextMenuEvent, ERDNodeDragEvent, ERDRelationshipInfo } from '../interfaces/erd-types';
3
- import * as i0 from "@angular/core";
4
1
  /**
5
- * Entity Relationship Diagram component using D3.js force-directed graph.
6
- *
7
- * This is a **generic, reusable Angular component** that can visualize any data
8
- * that conforms to the `ERDNode` interface. It is completely decoupled from
9
- * MemberJunction-specific types and can be used in any Angular project.
10
- *
11
- * ## Features
12
- *
13
- * - **Interactive Force-Directed Layout**: Nodes automatically arrange themselves
14
- * using physics-based simulation with customizable forces
15
- * - **Zoom and Pan**: Mouse wheel zoom and drag-to-pan with configurable limits
16
- * - **Node Selection**: Click to select nodes with visual highlighting
17
- * - **Focus Mode**: Show a single node with its N-hop related entities
18
- * - **Relationship Visualization**: Arrows show foreign key relationships
19
- * - **Customizable Styling**: Full control over colors, sizes, and appearance
20
- * - **Rich Event System**: Comprehensive events for integration with parent components
21
- * - **State Persistence**: Save and restore diagram state (zoom, pan, selection, positions)
22
- *
23
- * ## Basic Usage
24
- *
25
- * ```html
26
- * <mj-erd-diagram
27
- * [nodes]="entityNodes"
28
- * [selectedNodeId]="selectedId"
29
- * [config]="erdConfig"
30
- * (nodeClick)="onNodeClick($event)"
31
- * (nodeSelected)="onNodeSelected($event)"
32
- * (zoomChange)="onZoomChange($event)">
33
- * </mj-erd-diagram>
34
- * ```
35
- *
36
- * ## Focus Mode Example
37
- *
38
- * Show a single entity with its immediate relationships:
39
- *
40
- * ```html
41
- * <mj-erd-diagram
42
- * [nodes]="allNodes"
43
- * [focusNodeId]="'user-entity-id'"
44
- * [focusDepth]="1"
45
- * (nodeSelected)="onNodeSelected($event)">
46
- * </mj-erd-diagram>
47
- * ```
48
- *
49
- * ## State Persistence Example
2
+ * @module erd-diagram.component
3
+ * @description
4
+ * Schema-grouped Entity Relationship Diagram. Each schema becomes a rounded
5
+ * rectangular band; entities tile in a grid within the band. Click a node to
6
+ * enter focus mode (neighbours highlighted, everything else dimmed) and see a
7
+ * floating details card with its inbound and outbound FKs.
50
8
  *
51
- * ```typescript
52
- * // Save state
53
- * const state = this.erdDiagram.getState();
54
- * localStorage.setItem('erd-state', JSON.stringify(state));
9
+ * The component is pure Angular + SVG (no D3, no Dagre). Layout is computed
10
+ * by a pure function in `../layout/compute-erd-layout.ts` that is easily
11
+ * unit-tested.
55
12
  *
56
- * // Restore state
57
- * const savedState = JSON.parse(localStorage.getItem('erd-state'));
58
- * this.erdDiagram.setState(savedState);
59
- * ```
60
- *
61
- * @see ERDNode for the node data structure
62
- * @see ERDConfig for configuration options
63
- * @see ERDState for state persistence
13
+ * Public API is preserved from the previous D3-based implementation so
14
+ * existing consumers (Database Designer wizard preview, admin ERD dashboard,
15
+ * Entity Record view) continue to work without changes.
64
16
  */
17
+ import { EventEmitter, AfterViewInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
18
+ import { ERDNode, ERDField, ERDLink, ERDConfig, ERDNodeClickEvent, ERDNodeDoubleClickEvent, ERDLinkClickEvent, ERDZoomEvent, ERDState, ERDNodeHoverEvent, ERDLinkHoverEvent, ERDNodeContextMenuEvent, ERDLinkContextMenuEvent, ERDDiagramContextMenuEvent, ERDNodeDragEvent } from '../interfaces/erd-types';
19
+ import { type ErdLayout, type LaidOutNode, type LaidOutEdge, type LaidOutBand } from '../layout/compute-erd-layout';
20
+ import * as i0 from "@angular/core";
21
+ interface SchemaChip {
22
+ name: string;
23
+ count: number;
24
+ active: boolean;
25
+ }
26
+ /** 2D transform (pan x/y + zoom scale) for the SVG stage. */
27
+ interface Transform {
28
+ x: number;
29
+ y: number;
30
+ k: number;
31
+ }
65
32
  export declare class ERDDiagramComponent implements AfterViewInit, OnDestroy, OnChanges {
66
- erdContainer: ElementRef;
67
- /**
68
- * The nodes (entities) to display in the diagram.
69
- * Each node should conform to the `ERDNode` interface.
70
- *
71
- * @example
72
- * ```typescript
73
- * nodes: ERDNode[] = [
74
- * {
75
- * id: 'user-1',
76
- * name: 'Users',
77
- * fields: [
78
- * { id: 'id', name: 'ID', isPrimaryKey: true },
79
- * { id: 'email', name: 'Email', isPrimaryKey: false }
80
- * ]
81
- * }
82
- * ];
83
- * ```
84
- */
33
+ private readonly cdr;
34
+ private readonly host;
85
35
  nodes: ERDNode[];
86
- /**
87
- * ID of the currently selected node.
88
- * Use this for external control of selection state.
89
- * The component will highlight this node and emit selection events accordingly.
90
- *
91
- * @example `[selectedNodeId]="'entity-123'"`
92
- */
93
36
  selectedNodeId: string | null;
94
- /**
95
- * IDs of nodes to highlight (in addition to selected node).
96
- * Highlighted nodes receive a distinct visual style (orange border by default).
97
- * Useful for showing search results or related items.
98
- *
99
- * @example `[highlightedNodeIds]="['entity-1', 'entity-2']"`
100
- */
101
37
  highlightedNodeIds: string[];
102
- /**
103
- * ID of the node to focus on.
104
- * When set, the diagram will only show this node and its related nodes
105
- * up to `focusDepth` hops away. This is useful for entity-centric views.
106
- *
107
- * Set to `null` to show all nodes.
108
- *
109
- * @example `[focusNodeId]="'user-entity-id'"`
110
- */
111
38
  focusNodeId: string | null;
112
- /**
113
- * Number of relationship hops to include when in focus mode.
114
- * - `0`: Show only the focus node
115
- * - `1`: Show focus node + directly related nodes
116
- * - `2`: Show focus node + nodes within 2 relationship hops
117
- *
118
- * Only applies when `focusNodeId` is set.
119
- *
120
- * @default 1
121
- * @example `[focusDepth]="2"`
122
- */
123
39
  focusDepth: number;
124
- /**
125
- * Whether the diagram is currently refreshing/loading.
126
- * When `true`, displays a loading overlay on the diagram.
127
- *
128
- * @example `[isRefreshing]="isLoadingData"`
129
- */
130
40
  isRefreshing: boolean;
131
- /**
132
- * Whether the diagram is in read-only mode.
133
- * When `true`, disables dragging and selection (zoom/pan still work).
134
- *
135
- * @default false
136
- */
137
41
  readOnly: boolean;
138
- /**
139
- * Configuration options for the diagram.
140
- * All options are optional with sensible defaults.
141
- *
142
- * @see ERDConfig for all available options
143
- * @example
144
- * ```typescript
145
- * config: ERDConfig = {
146
- * nodeWidth: 200,
147
- * chargeStrength: -1000,
148
- * colors: {
149
- * nodeHeader: '#0066cc'
150
- * }
151
- * };
152
- * ```
153
- */
154
42
  config: ERDConfig;
155
- /**
156
- * Whether to show the header bar with zoom controls.
157
- * Set to `false` to hide the header and use programmatic control instead.
158
- *
159
- * @default true
160
- */
161
43
  showHeader: boolean;
162
- /**
163
- * Title to display in the header bar.
164
- * Only visible when `showHeader` is `true`.
165
- *
166
- * @default 'Entity Relationship Diagram'
167
- */
168
44
  headerTitle: string;
169
- /**
170
- * Emitted when a node is clicked.
171
- * Set `event.cancel = true` to prevent the default selection behavior.
172
- *
173
- * @example
174
- * ```typescript
175
- * onNodeClick(event: ERDNodeClickEvent) {
176
- * console.log('Clicked:', event.node.name);
177
- * // Prevent selection for certain nodes
178
- * if (event.node.customData?.['locked']) {
179
- * event.cancel = true;
180
- * }
181
- * }
182
- * ```
183
- */
184
45
  nodeClick: EventEmitter<ERDNodeClickEvent>;
185
- /**
186
- * Emitted when a node is double-clicked.
187
- * Useful for opening detail views or triggering actions.
188
- *
189
- * @example
190
- * ```typescript
191
- * onNodeDoubleClick(event: ERDNodeDoubleClickEvent) {
192
- * this.openEntityDetail(event.node.id);
193
- * }
194
- * ```
195
- */
196
46
  nodeDoubleClick: EventEmitter<ERDNodeDoubleClickEvent>;
197
- /**
198
- * Emitted when a node is selected (after click, unless cancelled).
199
- * The node parameter contains the full `ERDNode` data.
200
- */
201
47
  nodeSelected: EventEmitter<ERDNode>;
202
- /**
203
- * Emitted when the current node is deselected.
204
- * This happens when clicking the background or selecting a different node.
205
- */
206
48
  nodeDeselected: EventEmitter<void>;
207
- /**
208
- * Emitted when a relationship link is clicked.
209
- * The event includes both source and target nodes for context.
210
- */
211
49
  linkClick: EventEmitter<ERDLinkClickEvent>;
212
- /**
213
- * Emitted when the mouse enters a node.
214
- * Includes related nodes and position for tooltip display.
215
- *
216
- * @example
217
- * ```typescript
218
- * onNodeHover(event: ERDNodeHoverEvent) {
219
- * this.showTooltip(event.node, event.position);
220
- * }
221
- * ```
222
- */
223
50
  nodeHover: EventEmitter<ERDNodeHoverEvent>;
224
- /**
225
- * Emitted when the mouse leaves a node.
226
- */
227
51
  nodeHoverEnd: EventEmitter<ERDNode>;
228
- /**
229
- * Emitted when the mouse enters a relationship link.
230
- */
231
52
  linkHover: EventEmitter<ERDLinkHoverEvent>;
232
- /**
233
- * Emitted when the mouse leaves a relationship link.
234
- */
235
53
  linkHoverEnd: EventEmitter<ERDLink>;
236
- /**
237
- * Emitted when a node is right-clicked.
238
- * Set `event.cancel = true` to prevent the default browser context menu.
239
- *
240
- * @example
241
- * ```typescript
242
- * onNodeContextMenu(event: ERDNodeContextMenuEvent) {
243
- * event.cancel = true;
244
- * this.showContextMenu(event.node, event.position);
245
- * }
246
- * ```
247
- */
248
54
  nodeContextMenu: EventEmitter<ERDNodeContextMenuEvent>;
249
- /**
250
- * Emitted when a relationship link is right-clicked.
251
- */
252
55
  linkContextMenu: EventEmitter<ERDLinkContextMenuEvent>;
253
- /**
254
- * Emitted when the diagram background is right-clicked.
255
- * Includes diagram coordinates for adding new nodes at click position.
256
- */
257
56
  diagramContextMenu: EventEmitter<ERDDiagramContextMenuEvent>;
258
- /**
259
- * Emitted when a node drag operation starts.
260
- * Set `event.cancel = true` to prevent the drag.
261
- */
262
57
  nodeDragStart: EventEmitter<ERDNodeDragEvent>;
263
- /**
264
- * Emitted when a node drag operation ends.
265
- */
266
58
  nodeDragEnd: EventEmitter<ERDNodeDragEvent>;
267
- /**
268
- * Emitted when zoom level or pan position changes.
269
- * Useful for synchronizing zoom controls or saving view state.
270
- */
271
59
  zoomChange: EventEmitter<ERDZoomEvent>;
272
- /**
273
- * Emitted when the diagram requests a refresh.
274
- * Triggered by the refresh button in the header.
275
- */
276
60
  refreshRequested: EventEmitter<void>;
277
- /**
278
- * Emitted when the force simulation completes initial layout.
279
- * Useful for performing actions after nodes have settled.
280
- */
281
61
  layoutComplete: EventEmitter<void>;
282
- /**
283
- * Emitted when diagram state changes (selection, zoom, highlights).
284
- * Useful for auto-saving state or syncing with other components.
285
- */
286
62
  stateChange: EventEmitter<ERDState>;
287
- private svg;
288
- private simulation;
289
- private internalNodes;
290
- private internalLinks;
291
- private visibleNodes;
292
- private visibleLinks;
293
- private zoom;
63
+ private canvasRef?;
64
+ /** Current pan + zoom. */
65
+ transform: Transform;
66
+ /** Set of schema names the user has filtered IN. Null means "all". */
67
+ activeSchemas: Set<string> | null;
68
+ /** Search query string. */
69
+ searchQuery: string;
70
+ /** Node IDs the user has clicked "+N more fields" on. */
71
+ expandedNodeIds: Set<string>;
72
+ /** Node currently being hovered (for highlight preview). */
73
+ hoverNodeId: string | null;
74
+ /** Cached layout — recomputed when nodes, filter, search or expansion changes. */
75
+ layout: ErdLayout;
76
+ /**
77
+ * Active layout algorithm. Starts from `config.layoutAlgorithm` (default
78
+ * `schema-grid`) but can be toggled at runtime via `setLayoutAlgorithm`.
79
+ * Exposed so the chrome toggle + saved user state can drive it.
80
+ */
81
+ activeLayout: 'schema-grid' | 'dagre';
82
+ /** Derived schema summary for the chip row. */
83
+ schemaChips: SchemaChip[];
84
+ /** Derived — number of entities currently visible. */
85
+ visibleCount: number;
86
+ /** Derived — total entities in the input, before any filtering. */
87
+ totalCount: number;
88
+ /** Derived — the Set of IDs in the focus/hover neighbourhood (null when no highlight active). */
89
+ highlightSet: Set<string> | null;
90
+ /** Derived — the single selected entity, if any. */
91
+ selectedEntity: ERDNode | null;
92
+ panning: boolean;
93
+ private panStart;
94
+ /** Raw mousedown coords — used to compute drag distance for the
95
+ * pan-vs-click threshold. */
96
+ private dragOrigin;
97
+ /** True once movement crossed the drag threshold — used to suppress
98
+ * the synthetic click that follows the mouseup. */
99
+ private dragMoved;
100
+ /** Pixels of movement before mousedown is treated as a drag. */
101
+ private static readonly DRAG_THRESHOLD;
102
+ /** Bound window listeners — kept on the instance so we can detach. */
103
+ private boundWindowMove?;
104
+ private boundWindowUp?;
294
105
  private resizeObserver?;
295
- private lastKnownSize;
296
- private resizeTimeout?;
297
- private mergedConfig;
298
- private layoutCompleted;
299
- private isLayoutFrozen;
300
- ngAfterViewInit(): void;
106
+ readonly rootClass = true;
301
107
  ngOnChanges(changes: SimpleChanges): void;
108
+ /** True iff any config field that influences the cached layout changed. */
109
+ private configAffectsLayout;
110
+ ngAfterViewInit(): void;
302
111
  ngOnDestroy(): void;
303
- /**
304
- * Zoom in on the diagram by a fixed factor (1.2x).
305
- * Uses smooth animation transition.
306
- */
112
+ /** Rebuild the layout + derived view-model from current inputs/state. */
113
+ private recompute;
114
+ /**
115
+ * Switch between the schema-grid and dagre hierarchical layouts at
116
+ * runtime. Emits a state change so the consumer can persist the
117
+ * user's preference (via `userStateChange` on `mj-erd-composite`).
118
+ *
119
+ * Also clears the current focus/selection — switching layouts moves
120
+ * cards to entirely new positions, so the previously-selected entity
121
+ * would otherwise stay highlighted in a different spot with the side
122
+ * panel still open, which is jarring. A clean slate is better.
123
+ */
124
+ setLayoutAlgorithm(algo: 'schema-grid' | 'dagre'): void;
125
+ private buildSchemaChips;
126
+ private updateHighlightSet;
127
+ private updateSelectedEntity;
128
+ private watchResize;
129
+ /**
130
+ * Mousedown anywhere on the SVG (background OR a node card). We
131
+ * arm a potential pan and attach window-level move/up listeners so
132
+ * the drag continues even if the cursor leaves the canvas (passes
133
+ * over the focus card, scrollbars, the chrome, etc.).
134
+ *
135
+ * The actual `panning = true` flip happens in the move handler once
136
+ * the cursor crosses `DRAG_THRESHOLD` — that way short clicks still
137
+ * register as clicks on cards (no accidental selection-toggle from
138
+ * a tiny mouse jitter).
139
+ */
140
+ onBackgroundMouseDown(e: MouseEvent): void;
141
+ private onWindowMouseMove;
142
+ private onWindowMouseUp;
143
+ onWheel(e: WheelEvent): void;
144
+ zoomBy(factor: number): void;
145
+ fitToView(): void;
146
+ private centerOn;
147
+ private emitZoom;
148
+ onNodeClick(node: LaidOutNode, e: MouseEvent): void;
149
+ onNodeMouseEnter(node: LaidOutNode, e: MouseEvent): void;
150
+ onNodeMouseLeave(node: LaidOutNode): void;
151
+ onToggleExpand(nodeId: string, e: Event): void;
152
+ onSearchChange(value: string): void;
153
+ onClearSearch(): void;
154
+ onSchemaChipToggle(schemaName: string): void;
155
+ onRequestRefresh(): void;
156
+ /** Path string for an edge — uses the orthogonal polyline from layout. */
157
+ edgePath(edge: LaidOutEdge): string;
158
+ /**
159
+ * Whether to render FK field labels along edges. Defaults to ON in
160
+ * both layouts — the zoom-gate (>=0.55x) keeps the labels off when
161
+ * the user is zoomed out far enough to see hundreds of entities, so
162
+ * "noise on dense views" isn't a real concern. Consumers can still
163
+ * force off via `config.showRelationshipLabels: false`.
164
+ */
165
+ get showEdgeLabels(): boolean;
166
+ /**
167
+ * Pick a point along the edge polyline for a label and approximate
168
+ * its width. Returns null for self-loops (no good place to put text).
169
+ * Uses the longest horizontal segment when one exists; falls back to
170
+ * the segment midpoint otherwise.
171
+ */
172
+ edgeLabelPosition(edge: LaidOutEdge): {
173
+ x: number;
174
+ y: number;
175
+ w: number;
176
+ } | null;
177
+ /** Whether a node should appear dimmed (highlight mode active, node not in set). */
178
+ isDimmed(nodeId: string): boolean;
179
+ /** Whether a node is the current focus (strong border). */
180
+ isFocus(nodeId: string): boolean;
181
+ /** Whether a node is a 1-hop neighbour of the focus (medium border). */
182
+ isNeighbour(nodeId: string): boolean;
183
+ /** Whether an edge is part of the active highlight subgraph. */
184
+ isEdgeActive(edge: LaidOutEdge): boolean;
185
+ /** Whether an edge should appear dimmed. */
186
+ isEdgeDimmed(edge: LaidOutEdge): boolean;
187
+ /** Zoom percentage string for the toolbar readout. */
188
+ get zoomPercent(): string;
189
+ /** Short friendly row-count string (e.g. 1248 → "1.2k"). */
190
+ formatCount(n: number | undefined): string;
191
+ /** Number of PK fields — handy aggregate (kept for external API parity). */
192
+ pkCount(entity: ERDNode): number;
193
+ /** Number of FK fields — handy aggregate (kept for external API parity). */
194
+ fkCount(entity: ERDNode): number;
307
195
  zoomIn(): void;
308
- /**
309
- * Zoom out on the diagram by a fixed factor (0.83x).
310
- * Uses smooth animation transition.
311
- */
312
196
  zoomOut(): void;
313
- /**
314
- * Reset zoom to default level (1x) and center the diagram.
315
- * Uses smooth animation transition.
316
- */
317
197
  resetZoom(): void;
318
- /**
319
- * Zoom and pan to center on a specific node.
320
- *
321
- * @param nodeId - ID of the node to center on
322
- * @param scale - Optional zoom scale (default: 1.5)
323
- *
324
- * @example
325
- * ```typescript
326
- * // Center on node with default zoom
327
- * this.erdDiagram.zoomToNode('user-entity-id');
328
- *
329
- * // Center with custom zoom level
330
- * this.erdDiagram.zoomToNode('user-entity-id', 2.0);
331
- * ```
332
- */
333
- zoomToNode(nodeId: string, scale?: number): void;
334
- /**
335
- * Fit all visible nodes within the viewport.
336
- * Calculates optimal zoom level and position to show all nodes.
337
- *
338
- * @param padding - Padding around nodes (default: 50px)
339
- */
340
- zoomToFit(padding?: number): void;
341
- /**
342
- * Programmatically select a node by ID.
343
- *
344
- * @param nodeId - ID of the node to select
345
- * @returns `true` if node was found and selected, `false` otherwise
346
- */
347
- selectNode(nodeId: string): boolean;
348
- /**
349
- * Clear all selections.
350
- */
351
- deselectAll(): void;
352
- /**
353
- * Highlight a specific node.
354
- *
355
- * @param nodeId - ID of the node to highlight
356
- */
357
- highlightNode(nodeId: string): void;
358
- /**
359
- * Clear all highlights.
360
- */
361
- clearHighlights(): void;
362
- /**
363
- * Highlight a node and all its directly related nodes.
364
- *
365
- * @param nodeId - ID of the center node
366
- * @param depth - Number of relationship hops to highlight (default: 1)
367
- */
368
- highlightRelated(nodeId: string, depth?: number): void;
369
- /**
370
- * Get nodes that are related to a specific node.
371
- *
372
- * @param nodeId - ID of the node to find relationships for
373
- * @param depth - Number of relationship hops (default: 1)
374
- * @returns Array of relationship information
375
- */
376
- getRelatedNodes(nodeId: string, depth?: number): ERDRelationshipInfo[];
377
- /**
378
- * Get the current state of the diagram for persistence.
379
- * Includes selection, highlights, zoom, pan, and node positions.
380
- *
381
- * @returns Current diagram state
382
- *
383
- * @example
384
- * ```typescript
385
- * // Save to localStorage
386
- * const state = erdDiagram.getState();
387
- * localStorage.setItem('erd-state', JSON.stringify(state));
388
- * ```
389
- */
390
- getState(): ERDState;
391
- /**
392
- * Restore a previously saved diagram state.
393
- *
394
- * @param state - State object from `getState()`
395
- * @param restorePositions - Whether to restore node positions (default: true)
396
- *
397
- * @example
398
- * ```typescript
399
- * // Restore from localStorage
400
- * const savedState = JSON.parse(localStorage.getItem('erd-state'));
401
- * if (savedState) {
402
- * erdDiagram.setState(savedState);
403
- * }
404
- * ```
405
- */
406
- setState(state: Partial<ERDState>, restorePositions?: boolean): void;
407
- /**
408
- * Freeze the layout simulation.
409
- * Nodes will stay in their current positions and won't move.
410
- */
411
- freezeLayout(): void;
412
- /**
413
- * Unfreeze the layout simulation.
414
- * Nodes will resume natural movement based on forces.
415
- */
416
- unfreezeLayout(): void;
417
- /**
418
- * Center the diagram without changing zoom level.
419
- */
420
- centerDiagram(): void;
421
- /**
422
- * Rebuild the entire ERD visualization.
423
- */
424
- refresh(): void;
425
- /**
426
- * Trigger a resize recalculation.
427
- * Call this when the container size changes.
428
- */
198
+ zoomToFit(_padding?: number): void;
199
+ zoomToNode(nodeId: string, _scale?: number): void;
429
200
  triggerResize(): void;
430
- /**
431
- * Get current zoom state.
432
- *
433
- * @returns Current zoom level and translation
434
- */
435
- getZoomState(): ERDZoomEvent;
436
- /**
437
- * Export the diagram as an SVG string.
438
- *
439
- * @returns SVG markup string
440
- */
201
+ refresh(): void;
202
+ getState(): ERDState;
203
+ setState(state: Partial<ERDState>, _restorePositions?: boolean): void;
441
204
  exportAsSVG(): string;
442
- private setupERD;
443
- private mergeConfig;
444
- private resizeSVG;
445
- private setupResizeObserver;
446
- private clearVisualization;
447
- private applyFocusMode;
448
- private getRelatedNodeIds;
449
- private createInternalNodes;
450
- private createInternalLinks;
451
- /**
452
- * Applies dagre hierarchical layout to position nodes and compute edge paths.
453
- * This provides clean, orthogonal edge routing.
454
- */
455
- private applyDagreLayout;
456
- /**
457
- * Checks if the current layout algorithm uses dagre.
458
- */
459
- private usesDagreLayout;
460
- private createVisualization;
461
- private renderNodeFields;
462
- /** Truncate an SVG text element to fit within maxWidth, adding "…" if needed */
463
- private truncateTextElement;
464
- private attachNodeEventHandlers;
465
- private attachLinkEventHandlers;
466
- private updatePositions;
467
- private getSourceConnectionPoint;
468
- private getTargetConnectionPoint;
469
- private createOrthogonalPath;
470
- /**
471
- * Creates an SVG path string from dagre's edge points.
472
- * Dagre provides an array of points for each edge that forms a clean orthogonal path.
473
- * @param points Array of {x, y} coordinates from dagre layout
474
- * @returns SVG path string
475
- */
476
- private createPathFromDagrePoints;
477
- private screenToDiagramCoords;
478
- private clearAllHighlighting;
479
- private updateSelectionHighlighting;
480
- private updateHighlighting;
481
- private emitStateChange;
482
- private dragstarted;
483
- private dragged;
484
- private dragended;
205
+ trackByBand: (_: number, b: LaidOutBand) => string;
206
+ trackByEdge: (_: number, e: LaidOutEdge) => string;
207
+ trackByNode: (_: number, n: LaidOutNode) => string;
208
+ trackByField: (_: number, f: ERDField) => string;
209
+ trackByChip: (_: number, c: SchemaChip) => string;
485
210
  static ɵfac: i0.ɵɵFactoryDeclaration<ERDDiagramComponent, never>;
486
211
  static ɵcmp: i0.ɵɵComponentDeclaration<ERDDiagramComponent, "mj-erd-diagram", never, { "nodes": { "alias": "nodes"; "required": false; }; "selectedNodeId": { "alias": "selectedNodeId"; "required": false; }; "highlightedNodeIds": { "alias": "highlightedNodeIds"; "required": false; }; "focusNodeId": { "alias": "focusNodeId"; "required": false; }; "focusDepth": { "alias": "focusDepth"; "required": false; }; "isRefreshing": { "alias": "isRefreshing"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; "config": { "alias": "config"; "required": false; }; "showHeader": { "alias": "showHeader"; "required": false; }; "headerTitle": { "alias": "headerTitle"; "required": false; }; }, { "nodeClick": "nodeClick"; "nodeDoubleClick": "nodeDoubleClick"; "nodeSelected": "nodeSelected"; "nodeDeselected": "nodeDeselected"; "linkClick": "linkClick"; "nodeHover": "nodeHover"; "nodeHoverEnd": "nodeHoverEnd"; "linkHover": "linkHover"; "linkHoverEnd": "linkHoverEnd"; "nodeContextMenu": "nodeContextMenu"; "linkContextMenu": "linkContextMenu"; "diagramContextMenu": "diagramContextMenu"; "nodeDragStart": "nodeDragStart"; "nodeDragEnd": "nodeDragEnd"; "zoomChange": "zoomChange"; "refreshRequested": "refreshRequested"; "layoutComplete": "layoutComplete"; "stateChange": "stateChange"; }, never, never, false, never>;
487
212
  }
213
+ export {};
488
214
  //# sourceMappingURL=erd-diagram.component.d.ts.map