@ngx-km/graph 0.0.2 → 0.0.4
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 +139 -4
- package/fesm2022/ngx-km-graph.mjs +36 -13
- package/fesm2022/ngx-km-graph.mjs.map +1 -1
- package/index.d.ts +37 -17
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ Angular 19+ library for creating interactive graph visualizations with custom no
|
|
|
8
8
|
- Automatic graph layout (hierarchical, force-directed, stress)
|
|
9
9
|
- Obstacle-aware path routing between nodes
|
|
10
10
|
- Infinite canvas with pan and zoom
|
|
11
|
+
- Animated viewport transitions with configurable easing
|
|
11
12
|
- Draggable nodes with position tracking
|
|
12
13
|
- Custom labels on paths (pill components)
|
|
13
14
|
- Fully type-safe API
|
|
@@ -117,13 +118,13 @@ export class MyNodeComponent {
|
|
|
117
118
|
@ViewChild(GraphComponent) graph!: GraphComponent;
|
|
118
119
|
|
|
119
120
|
// Fit all content to viewport
|
|
120
|
-
this.graph.fitToView(fitZoom?: boolean, padding?: number);
|
|
121
|
+
this.graph.fitToView(fitZoom?: boolean, padding?: number, options?: ViewportAnimationOptions);
|
|
121
122
|
|
|
122
123
|
// Center viewport on a specific node
|
|
123
|
-
this.graph.centerOnNode(nodeId: string);
|
|
124
|
+
this.graph.centerOnNode(nodeId: string, options?: ViewportAnimationOptions);
|
|
124
125
|
|
|
125
126
|
// Scroll node into view with minimal pan
|
|
126
|
-
this.graph.scrollToNode(nodeId: string, padding?: number);
|
|
127
|
+
this.graph.scrollToNode(nodeId: string, padding?: number, options?: ViewportAnimationOptions);
|
|
127
128
|
|
|
128
129
|
// Check if node is visible in viewport
|
|
129
130
|
this.graph.isNodeVisible(nodeId: string, padding?: number): boolean;
|
|
@@ -132,6 +133,66 @@ this.graph.isNodeVisible(nodeId: string, padding?: number): boolean;
|
|
|
132
133
|
this.graph.recalculateLayout();
|
|
133
134
|
```
|
|
134
135
|
|
|
136
|
+
### Animated Viewport Transitions
|
|
137
|
+
|
|
138
|
+
All viewport methods support smooth animated transitions:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { ViewportAnimationOptions } from '@ngx-km/graph';
|
|
142
|
+
|
|
143
|
+
// Animate with default settings (300ms, ease-out)
|
|
144
|
+
this.graph.centerOnNode('node-1', { animated: true });
|
|
145
|
+
|
|
146
|
+
// Custom duration and easing
|
|
147
|
+
this.graph.fitToView(true, 40, {
|
|
148
|
+
animated: true,
|
|
149
|
+
duration: 500,
|
|
150
|
+
easing: 'ease-in-out',
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Instant (no animation)
|
|
154
|
+
this.graph.scrollToNode('node-2', 40, { animated: false });
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### ViewportAnimationOptions
|
|
158
|
+
|
|
159
|
+
| Property | Type | Default | Description |
|
|
160
|
+
|----------|------|---------|-------------|
|
|
161
|
+
| `animated` | `boolean` | `false` | Enable animated transition |
|
|
162
|
+
| `duration` | `number` | `300` | Animation duration in milliseconds |
|
|
163
|
+
| `easing` | `EasingName \| EasingFunction` | `'ease-out'` | Easing function |
|
|
164
|
+
|
|
165
|
+
#### Built-in Easing Functions
|
|
166
|
+
|
|
167
|
+
| Name | Description |
|
|
168
|
+
|------|-------------|
|
|
169
|
+
| `'linear'` | Constant speed |
|
|
170
|
+
| `'ease-out'` | Fast start, slow end (default) |
|
|
171
|
+
| `'ease-in'` | Slow start, fast end |
|
|
172
|
+
| `'ease-in-out'` | Slow start and end |
|
|
173
|
+
|
|
174
|
+
#### Custom Easing Functions
|
|
175
|
+
|
|
176
|
+
You can provide a custom easing function:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
// Custom bounce easing
|
|
180
|
+
this.graph.centerOnNode('node-1', {
|
|
181
|
+
animated: true,
|
|
182
|
+
duration: 600,
|
|
183
|
+
easing: (t: number) => {
|
|
184
|
+
const n1 = 7.5625;
|
|
185
|
+
const d1 = 2.75;
|
|
186
|
+
if (t < 1 / d1) return n1 * t * t;
|
|
187
|
+
if (t < 2 / d1) return n1 * (t -= 1.5 / d1) * t + 0.75;
|
|
188
|
+
if (t < 2.5 / d1) return n1 * (t -= 2.25 / d1) * t + 0.9375;
|
|
189
|
+
return n1 * (t -= 2.625 / d1) * t + 0.984375;
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Note:** Animations are automatically cancelled when the user starts panning or zooming.
|
|
195
|
+
|
|
135
196
|
## Interfaces
|
|
136
197
|
|
|
137
198
|
### GraphNode
|
|
@@ -153,13 +214,85 @@ interface GraphRelationship<T = unknown> {
|
|
|
153
214
|
id: string; // Unique identifier
|
|
154
215
|
sourceId: string; // Source node ID
|
|
155
216
|
targetId: string; // Target node ID
|
|
156
|
-
type?: 'one-way' | 'two-way'; // Arrow direction
|
|
217
|
+
type?: 'one-way' | 'two-way'; // Arrow direction (default: 'one-way')
|
|
157
218
|
data?: T; // Data passed to pill component
|
|
158
219
|
sourceAnchorSide?: 'top' | 'right' | 'bottom' | 'left';
|
|
159
220
|
targetAnchorSide?: 'top' | 'right' | 'bottom' | 'left';
|
|
160
221
|
}
|
|
161
222
|
```
|
|
162
223
|
|
|
224
|
+
## Relationship Types
|
|
225
|
+
|
|
226
|
+
Relationships support two arrow modes:
|
|
227
|
+
|
|
228
|
+
| Type | Description | Visual |
|
|
229
|
+
|------|-------------|--------|
|
|
230
|
+
| `'one-way'` | Arrow on target end only (default) | A ───→ B |
|
|
231
|
+
| `'two-way'` | Arrows on both ends (bidirectional) | A ←──→ B |
|
|
232
|
+
|
|
233
|
+
### One-Way Relationships (Default)
|
|
234
|
+
|
|
235
|
+
One-way relationships show a single arrow pointing from source to target. This is the default when `type` is omitted:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
const relationships: GraphRelationship[] = [
|
|
239
|
+
// Explicit one-way
|
|
240
|
+
{ id: 'e1', sourceId: 'A', targetId: 'B', type: 'one-way' },
|
|
241
|
+
|
|
242
|
+
// Implicit one-way (type defaults to 'one-way')
|
|
243
|
+
{ id: 'e2', sourceId: 'B', targetId: 'C' },
|
|
244
|
+
];
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Two-Way Relationships (Bidirectional)
|
|
248
|
+
|
|
249
|
+
Two-way relationships show arrows on both ends, indicating a bidirectional connection:
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
const relationships: GraphRelationship[] = [
|
|
253
|
+
// Bidirectional relationship
|
|
254
|
+
{ id: 'e1', sourceId: 'A', targetId: 'B', type: 'two-way' },
|
|
255
|
+
|
|
256
|
+
// Mixed: some one-way, some two-way
|
|
257
|
+
{ id: 'e2', sourceId: 'B', targetId: 'C', type: 'one-way' },
|
|
258
|
+
{ id: 'e3', sourceId: 'C', targetId: 'D', type: 'two-way' },
|
|
259
|
+
];
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Complete Example with Mixed Relationship Types
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
import { Component } from '@angular/core';
|
|
266
|
+
import { GraphComponent, GraphNode, GraphRelationship } from '@ngx-km/graph';
|
|
267
|
+
import { NodeComponent } from './node.component';
|
|
268
|
+
|
|
269
|
+
@Component({
|
|
270
|
+
selector: 'app-network',
|
|
271
|
+
standalone: true,
|
|
272
|
+
imports: [GraphComponent],
|
|
273
|
+
template: `
|
|
274
|
+
<ngx-graph [nodes]="nodes" [relationships]="relationships" />
|
|
275
|
+
`,
|
|
276
|
+
})
|
|
277
|
+
export class NetworkComponent {
|
|
278
|
+
nodes: GraphNode[] = [
|
|
279
|
+
{ id: 'server', component: NodeComponent, data: { label: 'Server' } },
|
|
280
|
+
{ id: 'client1', component: NodeComponent, data: { label: 'Client 1' } },
|
|
281
|
+
{ id: 'client2', component: NodeComponent, data: { label: 'Client 2' } },
|
|
282
|
+
{ id: 'database', component: NodeComponent, data: { label: 'Database' } },
|
|
283
|
+
];
|
|
284
|
+
|
|
285
|
+
relationships: GraphRelationship[] = [
|
|
286
|
+
// Bidirectional: Server communicates both ways with clients
|
|
287
|
+
{ id: 'r1', sourceId: 'server', targetId: 'client1', type: 'two-way' },
|
|
288
|
+
{ id: 'r2', sourceId: 'server', targetId: 'client2', type: 'two-way' },
|
|
289
|
+
|
|
290
|
+
// One-way: Server writes to database
|
|
291
|
+
{ id: 'r3', sourceId: 'server', targetId: 'database', type: 'one-way' },
|
|
292
|
+
];
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
163
296
|
## Configuration
|
|
164
297
|
|
|
165
298
|
### Full Configuration Example
|
|
@@ -213,6 +346,8 @@ const config: GraphConfig = {
|
|
|
213
346
|
| `layered` | Hierarchical structures, flowcharts, org charts |
|
|
214
347
|
| `force` | Networks, social graphs, unstructured data |
|
|
215
348
|
| `stress` | General purpose, good edge length consistency |
|
|
349
|
+
| `radial` | Radial tree structures, centered hierarchies |
|
|
350
|
+
| `tree` | Simple tree structures, file systems |
|
|
216
351
|
|
|
217
352
|
### Path Types
|
|
218
353
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, inject, Injector, viewChild, input, output, signal, computed, effect, Component } from '@angular/core';
|
|
3
|
-
import { NgComponentOutlet } from '@angular/common';
|
|
4
3
|
import { GridComponent } from '@ngx-km/grid';
|
|
4
|
+
export { DEFAULT_ANIMATION_DURATION, DEFAULT_EASING, EASING_FUNCTIONS } from '@ngx-km/grid';
|
|
5
|
+
import { NgComponentOutlet } from '@angular/common';
|
|
5
6
|
import { LayoutService } from '@ngx-km/layout';
|
|
6
7
|
import { PathFindingService } from '@ngx-km/path-finding';
|
|
7
8
|
|
|
@@ -36,12 +37,17 @@ const DEFAULT_GRAPH_PATH_CONFIG = {
|
|
|
36
37
|
*/
|
|
37
38
|
const DEFAULT_GRAPH_LAYOUT_CONFIG = {
|
|
38
39
|
algorithm: 'layered',
|
|
39
|
-
direction: 'DOWN',
|
|
40
40
|
nodeSpacing: 50,
|
|
41
|
-
layerSpacing: 100,
|
|
42
41
|
autoLayout: true,
|
|
43
42
|
preservePositions: true,
|
|
44
43
|
fitPadding: 40,
|
|
44
|
+
layered: {
|
|
45
|
+
direction: 'DOWN',
|
|
46
|
+
layerSpacing: 100,
|
|
47
|
+
},
|
|
48
|
+
tree: {
|
|
49
|
+
direction: 'DOWN',
|
|
50
|
+
},
|
|
45
51
|
};
|
|
46
52
|
/**
|
|
47
53
|
* Default graph configuration
|
|
@@ -200,9 +206,10 @@ class GraphComponent {
|
|
|
200
206
|
* Centers content in the viewport, optionally zooming out to fit everything
|
|
201
207
|
* @param fitZoom If true, zooms out if needed to fit all content (never zooms in beyond 1.0)
|
|
202
208
|
* @param padding Padding around content in pixels (default: 40)
|
|
209
|
+
* @param options Animation options
|
|
203
210
|
*/
|
|
204
|
-
fitToView(fitZoom = false, padding = 40) {
|
|
205
|
-
this.gridRef()?.fitToView(fitZoom, padding);
|
|
211
|
+
fitToView(fitZoom = false, padding = 40, options) {
|
|
212
|
+
this.gridRef()?.fitToView(fitZoom, padding, options);
|
|
206
213
|
}
|
|
207
214
|
/**
|
|
208
215
|
* Check if a node is fully visible in the viewport
|
|
@@ -216,18 +223,20 @@ class GraphComponent {
|
|
|
216
223
|
/**
|
|
217
224
|
* Center viewport on a specific node (no zoom change)
|
|
218
225
|
* @param nodeId The node ID to center on
|
|
226
|
+
* @param options Animation options
|
|
219
227
|
*/
|
|
220
|
-
centerOnNode(nodeId) {
|
|
221
|
-
this.gridRef()?.centerOnElement(nodeId);
|
|
228
|
+
centerOnNode(nodeId, options) {
|
|
229
|
+
this.gridRef()?.centerOnElement(nodeId, options);
|
|
222
230
|
}
|
|
223
231
|
/**
|
|
224
232
|
* Scroll node into view with minimal pan
|
|
225
233
|
* Only pans if node is not fully visible
|
|
226
234
|
* @param nodeId The node ID to scroll into view
|
|
227
235
|
* @param padding Padding from viewport edges (default: 40)
|
|
236
|
+
* @param options Animation options
|
|
228
237
|
*/
|
|
229
|
-
scrollToNode(nodeId, padding = 40) {
|
|
230
|
-
this.gridRef()?.scrollToElement(nodeId, padding);
|
|
238
|
+
scrollToNode(nodeId, padding = 40, options) {
|
|
239
|
+
this.gridRef()?.scrollToElement(nodeId, padding, options);
|
|
231
240
|
}
|
|
232
241
|
// Private methods
|
|
233
242
|
async runLayout() {
|
|
@@ -249,6 +258,10 @@ class GraphComponent {
|
|
|
249
258
|
id: rel.id,
|
|
250
259
|
sourceId: rel.sourceId,
|
|
251
260
|
targetId: rel.targetId,
|
|
261
|
+
type: rel.type === 'two-way' ? 'bidirectional' : 'directed',
|
|
262
|
+
// Pass algorithm-specific edge hints
|
|
263
|
+
layered: rel.layered,
|
|
264
|
+
force: rel.force,
|
|
252
265
|
}));
|
|
253
266
|
try {
|
|
254
267
|
const result = await this.layoutService.calculateLayout({
|
|
@@ -256,9 +269,12 @@ class GraphComponent {
|
|
|
256
269
|
edges: layoutEdges,
|
|
257
270
|
options: {
|
|
258
271
|
algorithm: layoutCfg.algorithm,
|
|
259
|
-
direction: layoutCfg.direction,
|
|
260
272
|
nodeSpacing: layoutCfg.nodeSpacing,
|
|
261
|
-
|
|
273
|
+
layered: layoutCfg.layered,
|
|
274
|
+
tree: layoutCfg.tree,
|
|
275
|
+
force: layoutCfg.force,
|
|
276
|
+
stress: layoutCfg.stress,
|
|
277
|
+
radial: layoutCfg.radial,
|
|
262
278
|
},
|
|
263
279
|
});
|
|
264
280
|
// Update all positions from layout result
|
|
@@ -324,6 +340,11 @@ class GraphComponent {
|
|
|
324
340
|
this.calculatedPaths.set(result.paths);
|
|
325
341
|
}
|
|
326
342
|
// Path rendering helpers
|
|
343
|
+
/** Check if a relationship is two-way/bidirectional */
|
|
344
|
+
isTwoWay(relationshipId) {
|
|
345
|
+
const rel = this.relationships().find(r => r.id === relationshipId);
|
|
346
|
+
return rel?.type === 'two-way';
|
|
347
|
+
}
|
|
327
348
|
getArrowPoints() {
|
|
328
349
|
const size = this.pathConfig().arrowSize;
|
|
329
350
|
return `0,0 ${size},${size / 2} 0,${size}`;
|
|
@@ -439,7 +460,7 @@ class GraphComponent {
|
|
|
439
460
|
[attr.id]="'arrow-' + path.relationshipId"
|
|
440
461
|
[attr.markerWidth]="pathConfig().arrowSize"
|
|
441
462
|
[attr.markerHeight]="pathConfig().arrowSize"
|
|
442
|
-
[attr.refX]="pathConfig().arrowSize"
|
|
463
|
+
[attr.refX]="pathConfig().arrowSize - 1"
|
|
443
464
|
[attr.refY]="pathConfig().arrowSize / 2"
|
|
444
465
|
orient="auto-start-reverse"
|
|
445
466
|
markerUnits="userSpaceOnUse"
|
|
@@ -460,6 +481,7 @@ class GraphComponent {
|
|
|
460
481
|
[attr.stroke-width]="pathConfig().strokeWidth"
|
|
461
482
|
[attr.stroke-dasharray]="getStrokeDasharray()"
|
|
462
483
|
[attr.marker-end]="'url(#arrow-' + path.relationshipId + ')'"
|
|
484
|
+
[attr.marker-start]="isTwoWay(path.relationshipId) ? 'url(#arrow-' + path.relationshipId + ')' : null"
|
|
463
485
|
stroke-linecap="round"
|
|
464
486
|
stroke-linejoin="round"
|
|
465
487
|
/>
|
|
@@ -508,7 +530,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
508
530
|
[attr.id]="'arrow-' + path.relationshipId"
|
|
509
531
|
[attr.markerWidth]="pathConfig().arrowSize"
|
|
510
532
|
[attr.markerHeight]="pathConfig().arrowSize"
|
|
511
|
-
[attr.refX]="pathConfig().arrowSize"
|
|
533
|
+
[attr.refX]="pathConfig().arrowSize - 1"
|
|
512
534
|
[attr.refY]="pathConfig().arrowSize / 2"
|
|
513
535
|
orient="auto-start-reverse"
|
|
514
536
|
markerUnits="userSpaceOnUse"
|
|
@@ -529,6 +551,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
529
551
|
[attr.stroke-width]="pathConfig().strokeWidth"
|
|
530
552
|
[attr.stroke-dasharray]="getStrokeDasharray()"
|
|
531
553
|
[attr.marker-end]="'url(#arrow-' + path.relationshipId + ')'"
|
|
554
|
+
[attr.marker-start]="isTwoWay(path.relationshipId) ? 'url(#arrow-' + path.relationshipId + ')' : null"
|
|
532
555
|
stroke-linecap="round"
|
|
533
556
|
stroke-linejoin="round"
|
|
534
557
|
/>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngx-km-graph.mjs","sources":["../../../../libs/ngx-km-graph/src/lib/models/graph.models.ts","../../../../libs/ngx-km-graph/src/lib/components/graph.component.ts","../../../../libs/ngx-km-graph/src/index.ts","../../../../libs/ngx-km-graph/src/ngx-km-graph.ts"],"sourcesContent":["import { Type, InjectionToken, Signal } from '@angular/core';\nimport type { GridConfig } from '@ngx-km/grid';\nimport type { LayoutAlgorithm, LayoutDirection } from '@ngx-km/layout';\nimport type { PathType } from '@ngx-km/path-finding';\nimport type { StrokePattern, ArrowStyle, ArrowPosition } from '@ngx-km/path-drawing';\n\n/**\n * Injection token for accessing node data in dynamically rendered node components.\n * The data can be either a plain value or a Signal for reactive updates.\n */\nexport const GRAPH_NODE_DATA = new InjectionToken<unknown>('GRAPH_NODE_DATA');\n\n/**\n * Injection token for accessing relationship data in dynamically rendered pill components.\n * The data can be either a plain value or a Signal for reactive updates.\n */\nexport const GRAPH_RELATIONSHIP_DATA = new InjectionToken<unknown>('GRAPH_RELATIONSHIP_DATA');\n\n/**\n * Type alias for data that can be either a plain value or a Signal.\n * Use Signal<T> when you need the component to reactively update based on data changes.\n */\nexport type ReactiveData<T> = T | Signal<T>;\n\n// ============================================================================\n// Node Definitions\n// ============================================================================\n\n/**\n * Definition for a node in the graph\n * @template T Type of the data passed to the node component\n */\nexport interface GraphNode<T = unknown> {\n /** Unique identifier for this node */\n id: string;\n /** Angular component class to render for this node */\n component: Type<unknown>;\n /**\n * Data to pass to the node component via GRAPH_NODE_DATA injection token.\n * Can be a plain value or a Signal for reactive updates.\n * When using Signal<T>, the component can reactively respond to data changes.\n */\n data?: ReactiveData<T>;\n /** Optional initial X position (used when preservePositions is true) */\n x?: number;\n /** Optional initial Y position (used when preservePositions is true) */\n y?: number;\n}\n\n/**\n * Internal node representation with resolved position\n */\nexport interface GraphNodeInternal<T = unknown> extends GraphNode<T> {\n /** Resolved X position in world space */\n x: number;\n /** Resolved Y position in world space */\n y: number;\n /** Rendered width (tracked after render) */\n width?: number;\n /** Rendered height (tracked after render) */\n height?: number;\n}\n\n// ============================================================================\n// Relationship Definitions\n// ============================================================================\n\n/**\n * Type of relationship (affects path drawing)\n * - 'one-way': Arrow on target end only\n * - 'two-way': Arrows on both ends\n */\nexport type RelationshipType = 'one-way' | 'two-way';\n\n/**\n * Definition for a relationship (edge) between nodes\n * @template T Type of the data passed to the pill component\n */\nexport interface GraphRelationship<T = unknown> {\n /** Unique identifier for this relationship */\n id: string;\n /** ID of the source node */\n sourceId: string;\n /** ID of the target node */\n targetId: string;\n /** Type of relationship (default: 'one-way') */\n type?: RelationshipType;\n /**\n * Data to pass to the pill component via GRAPH_RELATIONSHIP_DATA injection token.\n * Can be a plain value or a Signal for reactive updates.\n * When using Signal<T>, the component can reactively respond to data changes.\n */\n data?: ReactiveData<T>;\n /** Optional: Force specific source anchor side */\n sourceAnchorSide?: 'top' | 'right' | 'bottom' | 'left';\n /** Optional: Force specific target anchor side */\n targetAnchorSide?: 'top' | 'right' | 'bottom' | 'left';\n}\n\n// ============================================================================\n// Path Configuration\n// ============================================================================\n\n/**\n * Configuration for path rendering\n */\nexport interface GraphPathConfig {\n /** Path routing type (default: 'orthogonal') */\n pathType?: PathType;\n /** Stroke color for paths (default: '#6366f1') */\n strokeColor?: string;\n /** Stroke width in pixels (default: 2) */\n strokeWidth?: number;\n /** Stroke pattern (default: 'solid') */\n strokePattern?: StrokePattern;\n /** Stroke opacity 0-1 (default: 1) */\n strokeOpacity?: number;\n /** Corner radius for orthogonal paths (default: 0) */\n cornerRadius?: number;\n /** Arrow head style (default: 'filled') */\n arrowStyle?: ArrowStyle;\n /** Arrow head size in pixels (default: 10) */\n arrowSize?: number;\n /** Padding around nodes for obstacle avoidance (default: 20) */\n obstaclePadding?: number;\n /** Spacing between connection points on same side (default: 15) */\n anchorSpacing?: number;\n /** Whether to spread multiple anchors on same side (default: true) */\n spreadAnchors?: boolean;\n}\n\n/**\n * Default path configuration\n */\nexport const DEFAULT_GRAPH_PATH_CONFIG: Required<GraphPathConfig> = {\n pathType: 'orthogonal',\n strokeColor: '#6366f1',\n strokeWidth: 2,\n strokePattern: 'solid',\n strokeOpacity: 1,\n cornerRadius: 0,\n arrowStyle: 'filled',\n arrowSize: 10,\n obstaclePadding: 20,\n anchorSpacing: 15,\n spreadAnchors: true,\n};\n\n// ============================================================================\n// Layout Configuration\n// ============================================================================\n\n/**\n * Configuration for automatic layout\n */\nexport interface GraphLayoutConfig {\n /** Layout algorithm to use (default: 'layered') */\n algorithm?: LayoutAlgorithm;\n /** Layout direction (default: 'DOWN') */\n direction?: LayoutDirection;\n /** Spacing between nodes in pixels (default: 50) */\n nodeSpacing?: number;\n /** Spacing between layers in pixels (default: 100) */\n layerSpacing?: number;\n /** Whether to run layout automatically on init (default: true) */\n autoLayout?: boolean;\n /** Whether to preserve manually moved node positions on data update (default: true) */\n preservePositions?: boolean;\n /** Padding around content when fitting to view after layout (default: 40) */\n fitPadding?: number;\n}\n\n/**\n * Default layout configuration\n */\nexport const DEFAULT_GRAPH_LAYOUT_CONFIG: Required<GraphLayoutConfig> = {\n algorithm: 'layered',\n direction: 'DOWN',\n nodeSpacing: 50,\n layerSpacing: 100,\n autoLayout: true,\n preservePositions: true,\n fitPadding: 40,\n};\n\n// ============================================================================\n// Main Graph Configuration\n// ============================================================================\n\n/**\n * Main configuration for the graph component\n * Combines grid, layout, and path configurations\n */\nexport interface GraphConfig {\n /** Grid configuration (pan, zoom, background, etc.) */\n grid?: Partial<GridConfig>;\n /** Layout configuration (algorithm, spacing, etc.) */\n layout?: GraphLayoutConfig;\n /** Path rendering configuration (colors, arrows, etc.) */\n paths?: GraphPathConfig;\n /** Component to render at path midpoints (optional) */\n pillComponent?: Type<unknown>;\n}\n\n/**\n * Default graph configuration\n */\nexport const DEFAULT_GRAPH_CONFIG: GraphConfig = {\n grid: {\n dimensionMode: 'full',\n backgroundMode: 'dots',\n cellSize: 20,\n panEnabled: true,\n zoomEnabled: true,\n dragEnabled: true,\n },\n layout: DEFAULT_GRAPH_LAYOUT_CONFIG,\n paths: DEFAULT_GRAPH_PATH_CONFIG,\n};\n\n// ============================================================================\n// Events\n// ============================================================================\n\n/**\n * Event emitted when a node is selected\n */\nexport interface NodeSelectEvent<T = unknown> {\n /** The selected node */\n node: GraphNode<T>;\n}\n\n/**\n * Event emitted when a node position changes\n */\nexport interface NodePositionChangeEvent {\n /** Node ID */\n nodeId: string;\n /** New X position */\n x: number;\n /** New Y position */\n y: number;\n /** Previous X position */\n previousX: number;\n /** Previous Y position */\n previousY: number;\n}\n\n/**\n * Event emitted when a relationship is selected\n */\nexport interface RelationshipSelectEvent<T = unknown> {\n /** The selected relationship */\n relationship: GraphRelationship<T>;\n}\n","import {\n Component,\n input,\n output,\n computed,\n signal,\n effect,\n inject,\n Injector,\n viewChild,\n} from '@angular/core';\nimport { NgComponentOutlet } from '@angular/common';\nimport {\n GridComponent,\n GridConfig,\n GridElement,\n RenderedElement,\n ElementPositionChange,\n ViewportState,\n} from '@ngx-km/grid';\nimport { LayoutService, LayoutNode, LayoutEdge } from '@ngx-km/layout';\nimport {\n PathFindingService,\n PathNode,\n PathRelationship,\n CalculatedPath,\n PathFindingInput,\n} from '@ngx-km/path-finding';\nimport {\n GraphConfig,\n GraphNode,\n GraphRelationship,\n NodePositionChangeEvent,\n DEFAULT_GRAPH_CONFIG,\n DEFAULT_GRAPH_LAYOUT_CONFIG,\n DEFAULT_GRAPH_PATH_CONFIG,\n GRAPH_RELATIONSHIP_DATA,\n} from '../models/graph.models';\n\n/** Internal node with position */\ninterface InternalNode<T> {\n id: string;\n component: GraphNode<T>['component'];\n data: T | undefined;\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n@Component({\n selector: 'ngx-graph',\n standalone: true,\n imports: [GridComponent, NgComponentOutlet],\n template: `\n <div class=\"graph-wrapper\" [class.layout-ready]=\"layoutReady()\">\n <ngx-grid\n #gridRef\n [config]=\"gridConfig()\"\n [elements]=\"gridElements()\"\n (viewportChange)=\"onViewportChange($event)\"\n (elementsRendered)=\"onElementsRendered($event)\"\n (elementPositionChange)=\"onElementPositionChange($event)\"\n />\n <!-- SVG layer for paths -->\n <svg\n class=\"paths-layer\"\n xmlns=\"http://www.w3.org/2000/svg\"\n [style.transform]=\"pathsTransform()\"\n >\n <defs>\n @for (path of calculatedPaths(); track path.relationshipId) {\n <marker\n [attr.id]=\"'arrow-' + path.relationshipId\"\n [attr.markerWidth]=\"pathConfig().arrowSize\"\n [attr.markerHeight]=\"pathConfig().arrowSize\"\n [attr.refX]=\"pathConfig().arrowSize\"\n [attr.refY]=\"pathConfig().arrowSize / 2\"\n orient=\"auto-start-reverse\"\n markerUnits=\"userSpaceOnUse\"\n >\n <polygon\n [attr.points]=\"getArrowPoints()\"\n [attr.fill]=\"pathConfig().strokeColor\"\n />\n </marker>\n }\n </defs>\n\n @for (path of calculatedPaths(); track path.relationshipId) {\n <path\n [attr.d]=\"getPathD(path)\"\n fill=\"none\"\n [attr.stroke]=\"pathConfig().strokeColor\"\n [attr.stroke-width]=\"pathConfig().strokeWidth\"\n [attr.stroke-dasharray]=\"getStrokeDasharray()\"\n [attr.marker-end]=\"'url(#arrow-' + path.relationshipId + ')'\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n }\n </svg>\n <!-- Pills layer - rendered at path midpoints -->\n @if (pillComponent()) {\n <div class=\"pills-layer\" [style.transform]=\"pathsTransform()\">\n @for (path of calculatedPaths(); track path.relationshipId) {\n <div\n class=\"pill-wrapper\"\n [style.left.px]=\"path.midpoint.x\"\n [style.top.px]=\"path.midpoint.y\"\n >\n <ng-container\n *ngComponentOutlet=\"pillComponent()!; injector: createPillInjector(path.relationshipId)\"\n />\n </div>\n }\n </div>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n .graph-wrapper {\n position: relative;\n width: 100%;\n height: 100%;\n }\n /* Hide nodes and paths until layout is ready to prevent flash */\n .graph-wrapper:not(.layout-ready) ::ng-deep .grid-viewport,\n .graph-wrapper:not(.layout-ready) .paths-layer,\n .graph-wrapper:not(.layout-ready) .pills-layer {\n opacity: 0;\n }\n .paths-layer {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n overflow: visible;\n pointer-events: none;\n transform-origin: 0 0;\n }\n .pills-layer {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n overflow: visible;\n pointer-events: none;\n transform-origin: 0 0;\n }\n .pill-wrapper {\n position: absolute;\n transform: translate(-50%, -50%);\n pointer-events: auto;\n }\n `],\n})\nexport class GraphComponent<TNode = unknown, TRelationship = unknown> {\n private readonly layoutService = inject(LayoutService);\n private readonly pathFindingService = inject(PathFindingService);\n private readonly injector = inject(Injector);\n private readonly gridRef = viewChild<GridComponent>('gridRef');\n\n // Inputs\n nodes = input<GraphNode<TNode>[]>([]);\n relationships = input<GraphRelationship<TRelationship>[]>([]);\n config = input<GraphConfig>(DEFAULT_GRAPH_CONFIG);\n\n // Outputs\n nodePositionChange = output<NodePositionChangeEvent>();\n viewportChange = output<ViewportState>();\n\n // Internal state - single source of truth for positions\n private nodePositions = signal<Map<string, { x: number; y: number }>>(new Map());\n private nodeDimensions = signal<Map<string, { width: number; height: number }>>(new Map());\n private viewport = signal<ViewportState>({ x: 0, y: 0, zoom: 1 });\n calculatedPaths = signal<CalculatedPath[]>([]);\n\n /** Whether initial layout has completed - used to prevent flash of unstyled nodes */\n layoutReady = signal<boolean>(false);\n\n // Computed configs\n gridConfig = computed((): GridConfig => ({\n dimensionMode: 'full',\n backgroundMode: 'dots',\n cellSize: 20,\n panEnabled: true,\n zoomEnabled: true,\n dragEnabled: true,\n ...this.config().grid,\n }));\n\n layoutConfig = computed(() => ({\n ...DEFAULT_GRAPH_LAYOUT_CONFIG,\n ...this.config().layout,\n }));\n\n pathConfig = computed(() => ({\n ...DEFAULT_GRAPH_PATH_CONFIG,\n ...this.config().paths,\n }));\n\n /** Pill component to render at path midpoints */\n pillComponent = computed(() => this.config().pillComponent);\n\n // Grid elements - combines input nodes with their positions\n gridElements = computed((): GridElement<TNode>[] => {\n const inputNodes = this.nodes();\n const positions = this.nodePositions();\n\n return inputNodes.map((node, index) => {\n const pos = positions.get(node.id);\n // Default grid position if not set\n const cols = Math.ceil(Math.sqrt(inputNodes.length));\n const defaultX = (index % cols) * 200;\n const defaultY = Math.floor(index / cols) * 150;\n\n return {\n id: node.id,\n component: node.component,\n data: node.data,\n x: pos?.x ?? node.x ?? defaultX,\n y: pos?.y ?? node.y ?? defaultY,\n };\n });\n });\n\n pathsTransform = computed(() => {\n const vp = this.viewport();\n return `translate(${vp.x}px, ${vp.y}px) scale(${vp.zoom})`;\n });\n\n constructor() {\n // Run initial layout when nodes change\n effect(() => {\n const inputNodes = this.nodes();\n const layoutCfg = this.layoutConfig();\n\n if (inputNodes.length === 0) {\n // No nodes - mark as ready immediately\n this.layoutReady.set(true);\n return;\n }\n\n if (!layoutCfg.autoLayout) {\n // Auto-layout disabled - show nodes at their provided positions immediately\n this.layoutReady.set(true);\n return;\n }\n\n // Check if we have positions for all nodes\n const positions = this.nodePositions();\n const needsLayout = inputNodes.some(n => !positions.has(n.id));\n\n if (needsLayout) {\n // Reset layoutReady when new nodes need positioning\n this.layoutReady.set(false);\n this.runLayout();\n }\n });\n\n // Recalculate paths when relationships or positions change\n effect(() => {\n const relationships = this.relationships();\n const positions = this.nodePositions();\n const dimensions = this.nodeDimensions();\n\n if (relationships.length > 0 && positions.size > 0) {\n this.calculatePaths();\n }\n });\n }\n\n // Event handlers\n onViewportChange(viewport: ViewportState): void {\n this.viewport.set(viewport);\n this.viewportChange.emit(viewport);\n }\n\n onElementsRendered(elements: RenderedElement[]): void {\n const dims = new Map(this.nodeDimensions());\n let changed = false;\n\n elements.forEach(el => {\n const existing = dims.get(el.id);\n if (!existing || existing.width !== el.width || existing.height !== el.height) {\n dims.set(el.id, { width: el.width, height: el.height });\n changed = true;\n }\n });\n\n if (changed) {\n this.nodeDimensions.set(dims);\n this.calculatePaths();\n }\n }\n\n onElementPositionChange(change: ElementPositionChange): void {\n // Update position\n const positions = new Map(this.nodePositions());\n positions.set(change.id, { x: change.x, y: change.y });\n this.nodePositions.set(positions);\n\n // Emit event\n this.nodePositionChange.emit({\n nodeId: change.id,\n x: change.x,\n y: change.y,\n previousX: change.previousX,\n previousY: change.previousY,\n });\n\n // Recalculate paths\n this.calculatePaths();\n }\n\n // Public method to force re-layout\n recalculateLayout(): void {\n this.runLayout();\n }\n\n /**\n * Fit all graph content to view\n * Centers content in the viewport, optionally zooming out to fit everything\n * @param fitZoom If true, zooms out if needed to fit all content (never zooms in beyond 1.0)\n * @param padding Padding around content in pixels (default: 40)\n */\n fitToView(fitZoom = false, padding = 40): void {\n this.gridRef()?.fitToView(fitZoom, padding);\n }\n\n /**\n * Check if a node is fully visible in the viewport\n * @param nodeId The node ID to check\n * @param padding Padding from viewport edges (default: 0)\n * @returns true if node is fully visible, false otherwise\n */\n isNodeVisible(nodeId: string, padding = 0): boolean {\n return this.gridRef()?.isElementVisible(nodeId, padding) ?? false;\n }\n\n /**\n * Center viewport on a specific node (no zoom change)\n * @param nodeId The node ID to center on\n */\n centerOnNode(nodeId: string): void {\n this.gridRef()?.centerOnElement(nodeId);\n }\n\n /**\n * Scroll node into view with minimal pan\n * Only pans if node is not fully visible\n * @param nodeId The node ID to scroll into view\n * @param padding Padding from viewport edges (default: 40)\n */\n scrollToNode(nodeId: string, padding = 40): void {\n this.gridRef()?.scrollToElement(nodeId, padding);\n }\n\n // Private methods\n private async runLayout(): Promise<void> {\n const inputNodes = this.nodes();\n const relationships = this.relationships();\n const layoutCfg = this.layoutConfig();\n const dimensions = this.nodeDimensions();\n\n if (inputNodes.length === 0) return;\n\n const layoutNodes: LayoutNode[] = inputNodes.map(node => {\n const dim = dimensions.get(node.id);\n return {\n id: node.id,\n width: dim?.width ?? 150,\n height: dim?.height ?? 80,\n };\n });\n\n const layoutEdges: LayoutEdge[] = relationships.map(rel => ({\n id: rel.id,\n sourceId: rel.sourceId,\n targetId: rel.targetId,\n }));\n\n try {\n const result = await this.layoutService.calculateLayout({\n nodes: layoutNodes,\n edges: layoutEdges,\n options: {\n algorithm: layoutCfg.algorithm,\n direction: layoutCfg.direction,\n nodeSpacing: layoutCfg.nodeSpacing,\n layerSpacing: layoutCfg.layerSpacing,\n },\n });\n\n // Update all positions from layout result\n const positions = new Map<string, { x: number; y: number }>();\n result.nodes.forEach(n => {\n positions.set(n.id, { x: n.x, y: n.y });\n });\n this.nodePositions.set(positions);\n\n // Recalculate paths\n this.calculatePaths();\n\n // Fit to view and then show nodes (use requestAnimationFrame to ensure DOM is updated)\n requestAnimationFrame(() => {\n this.fitToView(true, layoutCfg.fitPadding ?? 40);\n // Mark layout as ready after fit (shows nodes and paths)\n this.layoutReady.set(true);\n });\n } catch (error) {\n console.error('Layout calculation failed:', error);\n // Still mark as ready on error so user can see something\n this.layoutReady.set(true);\n }\n }\n\n private calculatePaths(): void {\n const inputNodes = this.nodes();\n const relationships = this.relationships();\n const positions = this.nodePositions();\n const dimensions = this.nodeDimensions();\n const pathCfg = this.pathConfig();\n\n if (inputNodes.length === 0 || relationships.length === 0) {\n this.calculatedPaths.set([]);\n return;\n }\n\n const pfNodes: PathNode[] = inputNodes.map(node => {\n const pos = positions.get(node.id);\n const dim = dimensions.get(node.id);\n return {\n id: node.id,\n x: pos?.x ?? 0,\n y: pos?.y ?? 0,\n width: dim?.width ?? 150,\n height: dim?.height ?? 80,\n };\n });\n\n const pfRelationships: PathRelationship[] = relationships.map(rel => ({\n id: rel.id,\n sourceId: rel.sourceId,\n targetId: rel.targetId,\n sourceAnchor: rel.sourceAnchorSide,\n targetAnchor: rel.targetAnchorSide,\n }));\n\n const input: PathFindingInput = {\n nodes: pfNodes,\n relationships: pfRelationships,\n options: {\n pathType: pathCfg.pathType,\n obstaclePadding: pathCfg.obstaclePadding,\n anchorSpacing: pathCfg.anchorSpacing,\n spreadAnchors: pathCfg.spreadAnchors,\n },\n };\n\n const result = this.pathFindingService.calculatePaths(input);\n this.calculatedPaths.set(result.paths);\n }\n\n // Path rendering helpers\n getArrowPoints(): string {\n const size = this.pathConfig().arrowSize;\n return `0,0 ${size},${size / 2} 0,${size}`;\n }\n\n getStrokeDasharray(): string {\n const pattern = this.pathConfig().strokePattern;\n switch (pattern) {\n case 'dashed': return '8,4';\n case 'dotted': return '2,4';\n default: return '';\n }\n }\n\n getPathD(path: CalculatedPath): string {\n const waypoints = path.waypoints;\n if (!waypoints || waypoints.length === 0) return '';\n\n const cfg = this.pathConfig();\n\n if (cfg.pathType === 'bezier') {\n return this.generateBezierPath(waypoints);\n } else if (cfg.pathType === 'straight') {\n return this.generateStraightPath(waypoints);\n } else {\n return this.generateOrthogonalPath(waypoints, cfg.cornerRadius);\n }\n }\n\n private generateOrthogonalPath(\n waypoints: { x: number; y: number; isControlPoint?: boolean }[],\n cornerRadius: number\n ): string {\n const points = waypoints.filter(w => !w.isControlPoint);\n if (points.length === 0) return '';\n\n if (cornerRadius === 0 || points.length < 3) {\n return points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x} ${p.y}`).join(' ');\n }\n\n let path = `M ${points[0].x} ${points[0].y}`;\n\n for (let i = 1; i < points.length - 1; i++) {\n const prev = points[i - 1];\n const curr = points[i];\n const next = points[i + 1];\n\n const dx1 = curr.x - prev.x;\n const dy1 = curr.y - prev.y;\n const dx2 = next.x - curr.x;\n const dy2 = next.y - curr.y;\n\n const dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);\n const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);\n\n if (dist1 === 0 || dist2 === 0) {\n path += ` L ${curr.x} ${curr.y}`;\n continue;\n }\n\n const r = Math.min(cornerRadius, dist1 / 2, dist2 / 2);\n\n const startX = curr.x - (dx1 / dist1) * r;\n const startY = curr.y - (dy1 / dist1) * r;\n const endX = curr.x + (dx2 / dist2) * r;\n const endY = curr.y + (dy2 / dist2) * r;\n\n path += ` L ${startX} ${startY}`;\n path += ` Q ${curr.x} ${curr.y}, ${endX} ${endY}`;\n }\n\n const last = points[points.length - 1];\n path += ` L ${last.x} ${last.y}`;\n\n return path;\n }\n\n private generateBezierPath(waypoints: { x: number; y: number }[]): string {\n if (waypoints.length < 2) return '';\n if (waypoints.length === 4) {\n const [start, cp1, cp2, end] = waypoints;\n return `M ${start.x} ${start.y} C ${cp1.x} ${cp1.y}, ${cp2.x} ${cp2.y}, ${end.x} ${end.y}`;\n }\n if (waypoints.length === 3) {\n const [start, cp, end] = waypoints;\n return `M ${start.x} ${start.y} Q ${cp.x} ${cp.y}, ${end.x} ${end.y}`;\n }\n return this.generateStraightPath(waypoints);\n }\n\n private generateStraightPath(waypoints: { x: number; y: number }[]): string {\n if (waypoints.length < 2) return '';\n const start = waypoints[0];\n const end = waypoints[waypoints.length - 1];\n return `M ${start.x} ${start.y} L ${end.x} ${end.y}`;\n }\n\n // Pill rendering helpers\n\n /** Create an injector for a pill component, passing the relationship data */\n createPillInjector(relationshipId: string): Injector {\n const relationship = this.relationships().find(r => r.id === relationshipId);\n return Injector.create({\n providers: [\n { provide: GRAPH_RELATIONSHIP_DATA, useValue: relationship?.data },\n ],\n parent: this.injector,\n });\n }\n}\n","// Models - Types\nexport type {\n GraphNode,\n GraphNodeInternal,\n GraphRelationship,\n RelationshipType,\n ReactiveData,\n GraphPathConfig,\n GraphLayoutConfig,\n GraphConfig,\n NodeSelectEvent,\n NodePositionChangeEvent,\n RelationshipSelectEvent,\n} from './lib/models/graph.models';\n\n// Models - Values\nexport {\n GRAPH_NODE_DATA,\n GRAPH_RELATIONSHIP_DATA,\n DEFAULT_GRAPH_PATH_CONFIG,\n DEFAULT_GRAPH_LAYOUT_CONFIG,\n DEFAULT_GRAPH_CONFIG,\n} from './lib/models/graph.models';\n\n// Components\nexport { GraphComponent } from './lib/components/graph.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngx-km-graph.mjs","sources":["../../../../libs/ngx-km-graph/src/lib/models/graph.models.ts","../../../../libs/ngx-km-graph/src/lib/components/graph.component.ts","../../../../libs/ngx-km-graph/src/index.ts","../../../../libs/ngx-km-graph/src/ngx-km-graph.ts"],"sourcesContent":["import { Type, InjectionToken, Signal } from '@angular/core';\nimport type { GridConfig } from '@ngx-km/grid';\nimport type {\n LayoutAlgorithm,\n LayoutDirection,\n LayeredLayoutOptions,\n ForceLayoutOptions,\n StressLayoutOptions,\n RadialLayoutOptions,\n TreeLayoutOptions,\n LayeredEdgeHint,\n ForceEdgeHint,\n} from '@ngx-km/layout';\nimport type { PathType } from '@ngx-km/path-finding';\nimport type { StrokePattern, ArrowStyle, ArrowPosition } from '@ngx-km/path-drawing';\n\n/**\n * Injection token for accessing node data in dynamically rendered node components.\n * The data can be either a plain value or a Signal for reactive updates.\n */\nexport const GRAPH_NODE_DATA = new InjectionToken<unknown>('GRAPH_NODE_DATA');\n\n/**\n * Injection token for accessing relationship data in dynamically rendered pill components.\n * The data can be either a plain value or a Signal for reactive updates.\n */\nexport const GRAPH_RELATIONSHIP_DATA = new InjectionToken<unknown>('GRAPH_RELATIONSHIP_DATA');\n\n/**\n * Type alias for data that can be either a plain value or a Signal.\n * Use Signal<T> when you need the component to reactively update based on data changes.\n */\nexport type ReactiveData<T> = T | Signal<T>;\n\n// ============================================================================\n// Node Definitions\n// ============================================================================\n\n/**\n * Definition for a node in the graph\n * @template T Type of the data passed to the node component\n */\nexport interface GraphNode<T = unknown> {\n /** Unique identifier for this node */\n id: string;\n /** Angular component class to render for this node */\n component: Type<unknown>;\n /**\n * Data to pass to the node component via GRAPH_NODE_DATA injection token.\n * Can be a plain value or a Signal for reactive updates.\n * When using Signal<T>, the component can reactively respond to data changes.\n */\n data?: ReactiveData<T>;\n /** Optional initial X position (used when preservePositions is true) */\n x?: number;\n /** Optional initial Y position (used when preservePositions is true) */\n y?: number;\n}\n\n/**\n * Internal node representation with resolved position\n */\nexport interface GraphNodeInternal<T = unknown> extends GraphNode<T> {\n /** Resolved X position in world space */\n x: number;\n /** Resolved Y position in world space */\n y: number;\n /** Rendered width (tracked after render) */\n width?: number;\n /** Rendered height (tracked after render) */\n height?: number;\n}\n\n// ============================================================================\n// Relationship Definitions\n// ============================================================================\n\n/**\n * Type of relationship (affects path drawing)\n * - 'one-way': Arrow on target end only\n * - 'two-way': Arrows on both ends\n */\nexport type RelationshipType = 'one-way' | 'two-way';\n\n/**\n * Definition for a relationship (edge) between nodes\n * @template T Type of the data passed to the pill component\n */\nexport interface GraphRelationship<T = unknown> {\n /** Unique identifier for this relationship */\n id: string;\n /** ID of the source node */\n sourceId: string;\n /** ID of the target node */\n targetId: string;\n /** Type of relationship (default: 'one-way') */\n type?: RelationshipType;\n /**\n * Data to pass to the pill component via GRAPH_RELATIONSHIP_DATA injection token.\n * Can be a plain value or a Signal for reactive updates.\n * When using Signal<T>, the component can reactively respond to data changes.\n */\n data?: ReactiveData<T>;\n /** Optional: Force specific source anchor side */\n sourceAnchorSide?: 'top' | 'right' | 'bottom' | 'left';\n /** Optional: Force specific target anchor side */\n targetAnchorSide?: 'top' | 'right' | 'bottom' | 'left';\n\n // ---- Algorithm-specific layout hints ----\n\n /** Hints for layered layout algorithm (e.g., association for same-layer placement) */\n layered?: LayeredEdgeHint;\n /** Hints for force layout algorithm (e.g., edge strength, ideal length) */\n force?: ForceEdgeHint;\n}\n\n// ============================================================================\n// Path Configuration\n// ============================================================================\n\n/**\n * Configuration for path rendering\n */\nexport interface GraphPathConfig {\n /** Path routing type (default: 'orthogonal') */\n pathType?: PathType;\n /** Stroke color for paths (default: '#6366f1') */\n strokeColor?: string;\n /** Stroke width in pixels (default: 2) */\n strokeWidth?: number;\n /** Stroke pattern (default: 'solid') */\n strokePattern?: StrokePattern;\n /** Stroke opacity 0-1 (default: 1) */\n strokeOpacity?: number;\n /** Corner radius for orthogonal paths (default: 0) */\n cornerRadius?: number;\n /** Arrow head style (default: 'filled') */\n arrowStyle?: ArrowStyle;\n /** Arrow head size in pixels (default: 10) */\n arrowSize?: number;\n /** Padding around nodes for obstacle avoidance (default: 20) */\n obstaclePadding?: number;\n /** Spacing between connection points on same side (default: 15) */\n anchorSpacing?: number;\n /** Whether to spread multiple anchors on same side (default: true) */\n spreadAnchors?: boolean;\n}\n\n/**\n * Default path configuration\n */\nexport const DEFAULT_GRAPH_PATH_CONFIG: Required<GraphPathConfig> = {\n pathType: 'orthogonal',\n strokeColor: '#6366f1',\n strokeWidth: 2,\n strokePattern: 'solid',\n strokeOpacity: 1,\n cornerRadius: 0,\n arrowStyle: 'filled',\n arrowSize: 10,\n obstaclePadding: 20,\n anchorSpacing: 15,\n spreadAnchors: true,\n};\n\n// ============================================================================\n// Layout Configuration\n// ============================================================================\n\n/**\n * Configuration for automatic layout\n */\nexport interface GraphLayoutConfig {\n /** Layout algorithm to use (default: 'layered') */\n algorithm?: LayoutAlgorithm;\n\n // ---- Common options ----\n\n /** Spacing between nodes in pixels (default: 50) */\n nodeSpacing?: number;\n /** Whether to run layout automatically on init (default: true) */\n autoLayout?: boolean;\n /** Whether to preserve manually moved node positions on data update (default: true) */\n preservePositions?: boolean;\n /** Padding around content when fitting to view after layout (default: 40) */\n fitPadding?: number;\n\n // ---- Algorithm-specific options ----\n\n /** Options for layered (hierarchical) layout */\n layered?: LayeredLayoutOptions;\n /** Options for force-directed layout */\n force?: ForceLayoutOptions;\n /** Options for stress layout */\n stress?: StressLayoutOptions;\n /** Options for radial layout */\n radial?: RadialLayoutOptions;\n /** Options for tree layout */\n tree?: TreeLayoutOptions;\n}\n\n/**\n * Default layout configuration\n */\nexport const DEFAULT_GRAPH_LAYOUT_CONFIG: GraphLayoutConfig = {\n algorithm: 'layered',\n nodeSpacing: 50,\n autoLayout: true,\n preservePositions: true,\n fitPadding: 40,\n layered: {\n direction: 'DOWN',\n layerSpacing: 100,\n },\n tree: {\n direction: 'DOWN',\n },\n};\n\n// ============================================================================\n// Main Graph Configuration\n// ============================================================================\n\n/**\n * Main configuration for the graph component\n * Combines grid, layout, and path configurations\n */\nexport interface GraphConfig {\n /** Grid configuration (pan, zoom, background, etc.) */\n grid?: Partial<GridConfig>;\n /** Layout configuration (algorithm, spacing, etc.) */\n layout?: GraphLayoutConfig;\n /** Path rendering configuration (colors, arrows, etc.) */\n paths?: GraphPathConfig;\n /** Component to render at path midpoints (optional) */\n pillComponent?: Type<unknown>;\n}\n\n/**\n * Default graph configuration\n */\nexport const DEFAULT_GRAPH_CONFIG: GraphConfig = {\n grid: {\n dimensionMode: 'full',\n backgroundMode: 'dots',\n cellSize: 20,\n panEnabled: true,\n zoomEnabled: true,\n dragEnabled: true,\n },\n layout: DEFAULT_GRAPH_LAYOUT_CONFIG,\n paths: DEFAULT_GRAPH_PATH_CONFIG,\n};\n\n// ============================================================================\n// Events\n// ============================================================================\n\n/**\n * Event emitted when a node is selected\n */\nexport interface NodeSelectEvent<T = unknown> {\n /** The selected node */\n node: GraphNode<T>;\n}\n\n/**\n * Event emitted when a node position changes\n */\nexport interface NodePositionChangeEvent {\n /** Node ID */\n nodeId: string;\n /** New X position */\n x: number;\n /** New Y position */\n y: number;\n /** Previous X position */\n previousX: number;\n /** Previous Y position */\n previousY: number;\n}\n\n/**\n * Event emitted when a relationship is selected\n */\nexport interface RelationshipSelectEvent<T = unknown> {\n /** The selected relationship */\n relationship: GraphRelationship<T>;\n}\n","import {\n Component,\n input,\n output,\n computed,\n signal,\n effect,\n inject,\n Injector,\n viewChild,\n} from '@angular/core';\nimport { NgComponentOutlet } from '@angular/common';\nimport {\n GridComponent,\n GridConfig,\n GridElement,\n RenderedElement,\n ElementPositionChange,\n ViewportState,\n ViewportAnimationOptions,\n} from '@ngx-km/grid';\nimport { LayoutService, LayoutNode, LayoutEdge } from '@ngx-km/layout';\nimport {\n PathFindingService,\n PathNode,\n PathRelationship,\n CalculatedPath,\n PathFindingInput,\n} from '@ngx-km/path-finding';\nimport {\n GraphConfig,\n GraphNode,\n GraphRelationship,\n NodePositionChangeEvent,\n DEFAULT_GRAPH_CONFIG,\n DEFAULT_GRAPH_LAYOUT_CONFIG,\n DEFAULT_GRAPH_PATH_CONFIG,\n GRAPH_RELATIONSHIP_DATA,\n} from '../models/graph.models';\n\n/** Internal node with position */\ninterface InternalNode<T> {\n id: string;\n component: GraphNode<T>['component'];\n data: T | undefined;\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n@Component({\n selector: 'ngx-graph',\n standalone: true,\n imports: [GridComponent, NgComponentOutlet],\n template: `\n <div class=\"graph-wrapper\" [class.layout-ready]=\"layoutReady()\">\n <ngx-grid\n #gridRef\n [config]=\"gridConfig()\"\n [elements]=\"gridElements()\"\n (viewportChange)=\"onViewportChange($event)\"\n (elementsRendered)=\"onElementsRendered($event)\"\n (elementPositionChange)=\"onElementPositionChange($event)\"\n />\n <!-- SVG layer for paths -->\n <svg\n class=\"paths-layer\"\n xmlns=\"http://www.w3.org/2000/svg\"\n [style.transform]=\"pathsTransform()\"\n >\n <defs>\n @for (path of calculatedPaths(); track path.relationshipId) {\n <marker\n [attr.id]=\"'arrow-' + path.relationshipId\"\n [attr.markerWidth]=\"pathConfig().arrowSize\"\n [attr.markerHeight]=\"pathConfig().arrowSize\"\n [attr.refX]=\"pathConfig().arrowSize - 1\"\n [attr.refY]=\"pathConfig().arrowSize / 2\"\n orient=\"auto-start-reverse\"\n markerUnits=\"userSpaceOnUse\"\n >\n <polygon\n [attr.points]=\"getArrowPoints()\"\n [attr.fill]=\"pathConfig().strokeColor\"\n />\n </marker>\n }\n </defs>\n\n @for (path of calculatedPaths(); track path.relationshipId) {\n <path\n [attr.d]=\"getPathD(path)\"\n fill=\"none\"\n [attr.stroke]=\"pathConfig().strokeColor\"\n [attr.stroke-width]=\"pathConfig().strokeWidth\"\n [attr.stroke-dasharray]=\"getStrokeDasharray()\"\n [attr.marker-end]=\"'url(#arrow-' + path.relationshipId + ')'\"\n [attr.marker-start]=\"isTwoWay(path.relationshipId) ? 'url(#arrow-' + path.relationshipId + ')' : null\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n }\n </svg>\n <!-- Pills layer - rendered at path midpoints -->\n @if (pillComponent()) {\n <div class=\"pills-layer\" [style.transform]=\"pathsTransform()\">\n @for (path of calculatedPaths(); track path.relationshipId) {\n <div\n class=\"pill-wrapper\"\n [style.left.px]=\"path.midpoint.x\"\n [style.top.px]=\"path.midpoint.y\"\n >\n <ng-container\n *ngComponentOutlet=\"pillComponent()!; injector: createPillInjector(path.relationshipId)\"\n />\n </div>\n }\n </div>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n .graph-wrapper {\n position: relative;\n width: 100%;\n height: 100%;\n }\n /* Hide nodes and paths until layout is ready to prevent flash */\n .graph-wrapper:not(.layout-ready) ::ng-deep .grid-viewport,\n .graph-wrapper:not(.layout-ready) .paths-layer,\n .graph-wrapper:not(.layout-ready) .pills-layer {\n opacity: 0;\n }\n .paths-layer {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n overflow: visible;\n pointer-events: none;\n transform-origin: 0 0;\n }\n .pills-layer {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n overflow: visible;\n pointer-events: none;\n transform-origin: 0 0;\n }\n .pill-wrapper {\n position: absolute;\n transform: translate(-50%, -50%);\n pointer-events: auto;\n }\n `],\n})\nexport class GraphComponent<TNode = unknown, TRelationship = unknown> {\n private readonly layoutService = inject(LayoutService);\n private readonly pathFindingService = inject(PathFindingService);\n private readonly injector = inject(Injector);\n private readonly gridRef = viewChild<GridComponent>('gridRef');\n\n // Inputs\n nodes = input<GraphNode<TNode>[]>([]);\n relationships = input<GraphRelationship<TRelationship>[]>([]);\n config = input<GraphConfig>(DEFAULT_GRAPH_CONFIG);\n\n // Outputs\n nodePositionChange = output<NodePositionChangeEvent>();\n viewportChange = output<ViewportState>();\n\n // Internal state - single source of truth for positions\n private nodePositions = signal<Map<string, { x: number; y: number }>>(new Map());\n private nodeDimensions = signal<Map<string, { width: number; height: number }>>(new Map());\n private viewport = signal<ViewportState>({ x: 0, y: 0, zoom: 1 });\n calculatedPaths = signal<CalculatedPath[]>([]);\n\n /** Whether initial layout has completed - used to prevent flash of unstyled nodes */\n layoutReady = signal<boolean>(false);\n\n // Computed configs\n gridConfig = computed((): GridConfig => ({\n dimensionMode: 'full',\n backgroundMode: 'dots',\n cellSize: 20,\n panEnabled: true,\n zoomEnabled: true,\n dragEnabled: true,\n ...this.config().grid,\n }));\n\n layoutConfig = computed(() => ({\n ...DEFAULT_GRAPH_LAYOUT_CONFIG,\n ...this.config().layout,\n }));\n\n pathConfig = computed(() => ({\n ...DEFAULT_GRAPH_PATH_CONFIG,\n ...this.config().paths,\n }));\n\n /** Pill component to render at path midpoints */\n pillComponent = computed(() => this.config().pillComponent);\n\n // Grid elements - combines input nodes with their positions\n gridElements = computed((): GridElement<TNode>[] => {\n const inputNodes = this.nodes();\n const positions = this.nodePositions();\n\n return inputNodes.map((node, index) => {\n const pos = positions.get(node.id);\n // Default grid position if not set\n const cols = Math.ceil(Math.sqrt(inputNodes.length));\n const defaultX = (index % cols) * 200;\n const defaultY = Math.floor(index / cols) * 150;\n\n return {\n id: node.id,\n component: node.component,\n data: node.data,\n x: pos?.x ?? node.x ?? defaultX,\n y: pos?.y ?? node.y ?? defaultY,\n };\n });\n });\n\n pathsTransform = computed(() => {\n const vp = this.viewport();\n return `translate(${vp.x}px, ${vp.y}px) scale(${vp.zoom})`;\n });\n\n constructor() {\n // Run initial layout when nodes change\n effect(() => {\n const inputNodes = this.nodes();\n const layoutCfg = this.layoutConfig();\n\n if (inputNodes.length === 0) {\n // No nodes - mark as ready immediately\n this.layoutReady.set(true);\n return;\n }\n\n if (!layoutCfg.autoLayout) {\n // Auto-layout disabled - show nodes at their provided positions immediately\n this.layoutReady.set(true);\n return;\n }\n\n // Check if we have positions for all nodes\n const positions = this.nodePositions();\n const needsLayout = inputNodes.some(n => !positions.has(n.id));\n\n if (needsLayout) {\n // Reset layoutReady when new nodes need positioning\n this.layoutReady.set(false);\n this.runLayout();\n }\n });\n\n // Recalculate paths when relationships or positions change\n effect(() => {\n const relationships = this.relationships();\n const positions = this.nodePositions();\n const dimensions = this.nodeDimensions();\n\n if (relationships.length > 0 && positions.size > 0) {\n this.calculatePaths();\n }\n });\n }\n\n // Event handlers\n onViewportChange(viewport: ViewportState): void {\n this.viewport.set(viewport);\n this.viewportChange.emit(viewport);\n }\n\n onElementsRendered(elements: RenderedElement[]): void {\n const dims = new Map(this.nodeDimensions());\n let changed = false;\n\n elements.forEach(el => {\n const existing = dims.get(el.id);\n if (!existing || existing.width !== el.width || existing.height !== el.height) {\n dims.set(el.id, { width: el.width, height: el.height });\n changed = true;\n }\n });\n\n if (changed) {\n this.nodeDimensions.set(dims);\n this.calculatePaths();\n }\n }\n\n onElementPositionChange(change: ElementPositionChange): void {\n // Update position\n const positions = new Map(this.nodePositions());\n positions.set(change.id, { x: change.x, y: change.y });\n this.nodePositions.set(positions);\n\n // Emit event\n this.nodePositionChange.emit({\n nodeId: change.id,\n x: change.x,\n y: change.y,\n previousX: change.previousX,\n previousY: change.previousY,\n });\n\n // Recalculate paths\n this.calculatePaths();\n }\n\n // Public method to force re-layout\n recalculateLayout(): void {\n this.runLayout();\n }\n\n /**\n * Fit all graph content to view\n * Centers content in the viewport, optionally zooming out to fit everything\n * @param fitZoom If true, zooms out if needed to fit all content (never zooms in beyond 1.0)\n * @param padding Padding around content in pixels (default: 40)\n * @param options Animation options\n */\n fitToView(fitZoom = false, padding = 40, options?: ViewportAnimationOptions): void {\n this.gridRef()?.fitToView(fitZoom, padding, options);\n }\n\n /**\n * Check if a node is fully visible in the viewport\n * @param nodeId The node ID to check\n * @param padding Padding from viewport edges (default: 0)\n * @returns true if node is fully visible, false otherwise\n */\n isNodeVisible(nodeId: string, padding = 0): boolean {\n return this.gridRef()?.isElementVisible(nodeId, padding) ?? false;\n }\n\n /**\n * Center viewport on a specific node (no zoom change)\n * @param nodeId The node ID to center on\n * @param options Animation options\n */\n centerOnNode(nodeId: string, options?: ViewportAnimationOptions): void {\n this.gridRef()?.centerOnElement(nodeId, options);\n }\n\n /**\n * Scroll node into view with minimal pan\n * Only pans if node is not fully visible\n * @param nodeId The node ID to scroll into view\n * @param padding Padding from viewport edges (default: 40)\n * @param options Animation options\n */\n scrollToNode(nodeId: string, padding = 40, options?: ViewportAnimationOptions): void {\n this.gridRef()?.scrollToElement(nodeId, padding, options);\n }\n\n // Private methods\n private async runLayout(): Promise<void> {\n const inputNodes = this.nodes();\n const relationships = this.relationships();\n const layoutCfg = this.layoutConfig();\n const dimensions = this.nodeDimensions();\n\n if (inputNodes.length === 0) return;\n\n const layoutNodes: LayoutNode[] = inputNodes.map(node => {\n const dim = dimensions.get(node.id);\n return {\n id: node.id,\n width: dim?.width ?? 150,\n height: dim?.height ?? 80,\n };\n });\n\n const layoutEdges: LayoutEdge[] = relationships.map(rel => ({\n id: rel.id,\n sourceId: rel.sourceId,\n targetId: rel.targetId,\n type: rel.type === 'two-way' ? 'bidirectional' : 'directed',\n // Pass algorithm-specific edge hints\n layered: rel.layered,\n force: rel.force,\n }));\n\n try {\n const result = await this.layoutService.calculateLayout({\n nodes: layoutNodes,\n edges: layoutEdges,\n options: {\n algorithm: layoutCfg.algorithm,\n nodeSpacing: layoutCfg.nodeSpacing,\n layered: layoutCfg.layered,\n tree: layoutCfg.tree,\n force: layoutCfg.force,\n stress: layoutCfg.stress,\n radial: layoutCfg.radial,\n },\n });\n\n // Update all positions from layout result\n const positions = new Map<string, { x: number; y: number }>();\n result.nodes.forEach(n => {\n positions.set(n.id, { x: n.x, y: n.y });\n });\n this.nodePositions.set(positions);\n\n // Recalculate paths\n this.calculatePaths();\n\n // Fit to view and then show nodes (use requestAnimationFrame to ensure DOM is updated)\n requestAnimationFrame(() => {\n this.fitToView(true, layoutCfg.fitPadding ?? 40);\n // Mark layout as ready after fit (shows nodes and paths)\n this.layoutReady.set(true);\n });\n } catch (error) {\n console.error('Layout calculation failed:', error);\n // Still mark as ready on error so user can see something\n this.layoutReady.set(true);\n }\n }\n\n private calculatePaths(): void {\n const inputNodes = this.nodes();\n const relationships = this.relationships();\n const positions = this.nodePositions();\n const dimensions = this.nodeDimensions();\n const pathCfg = this.pathConfig();\n\n if (inputNodes.length === 0 || relationships.length === 0) {\n this.calculatedPaths.set([]);\n return;\n }\n\n const pfNodes: PathNode[] = inputNodes.map(node => {\n const pos = positions.get(node.id);\n const dim = dimensions.get(node.id);\n return {\n id: node.id,\n x: pos?.x ?? 0,\n y: pos?.y ?? 0,\n width: dim?.width ?? 150,\n height: dim?.height ?? 80,\n };\n });\n\n const pfRelationships: PathRelationship[] = relationships.map(rel => ({\n id: rel.id,\n sourceId: rel.sourceId,\n targetId: rel.targetId,\n sourceAnchor: rel.sourceAnchorSide,\n targetAnchor: rel.targetAnchorSide,\n }));\n\n const input: PathFindingInput = {\n nodes: pfNodes,\n relationships: pfRelationships,\n options: {\n pathType: pathCfg.pathType,\n obstaclePadding: pathCfg.obstaclePadding,\n anchorSpacing: pathCfg.anchorSpacing,\n spreadAnchors: pathCfg.spreadAnchors,\n },\n };\n\n const result = this.pathFindingService.calculatePaths(input);\n this.calculatedPaths.set(result.paths);\n }\n\n // Path rendering helpers\n /** Check if a relationship is two-way/bidirectional */\n isTwoWay(relationshipId: string): boolean {\n const rel = this.relationships().find(r => r.id === relationshipId);\n return rel?.type === 'two-way';\n }\n\n getArrowPoints(): string {\n const size = this.pathConfig().arrowSize;\n return `0,0 ${size},${size / 2} 0,${size}`;\n }\n\n getStrokeDasharray(): string {\n const pattern = this.pathConfig().strokePattern;\n switch (pattern) {\n case 'dashed': return '8,4';\n case 'dotted': return '2,4';\n default: return '';\n }\n }\n\n getPathD(path: CalculatedPath): string {\n const waypoints = path.waypoints;\n if (!waypoints || waypoints.length === 0) return '';\n\n const cfg = this.pathConfig();\n\n if (cfg.pathType === 'bezier') {\n return this.generateBezierPath(waypoints);\n } else if (cfg.pathType === 'straight') {\n return this.generateStraightPath(waypoints);\n } else {\n return this.generateOrthogonalPath(waypoints, cfg.cornerRadius);\n }\n }\n\n private generateOrthogonalPath(\n waypoints: { x: number; y: number; isControlPoint?: boolean }[],\n cornerRadius: number\n ): string {\n const points = waypoints.filter(w => !w.isControlPoint);\n if (points.length === 0) return '';\n\n if (cornerRadius === 0 || points.length < 3) {\n return points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x} ${p.y}`).join(' ');\n }\n\n let path = `M ${points[0].x} ${points[0].y}`;\n\n for (let i = 1; i < points.length - 1; i++) {\n const prev = points[i - 1];\n const curr = points[i];\n const next = points[i + 1];\n\n const dx1 = curr.x - prev.x;\n const dy1 = curr.y - prev.y;\n const dx2 = next.x - curr.x;\n const dy2 = next.y - curr.y;\n\n const dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);\n const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);\n\n if (dist1 === 0 || dist2 === 0) {\n path += ` L ${curr.x} ${curr.y}`;\n continue;\n }\n\n const r = Math.min(cornerRadius, dist1 / 2, dist2 / 2);\n\n const startX = curr.x - (dx1 / dist1) * r;\n const startY = curr.y - (dy1 / dist1) * r;\n const endX = curr.x + (dx2 / dist2) * r;\n const endY = curr.y + (dy2 / dist2) * r;\n\n path += ` L ${startX} ${startY}`;\n path += ` Q ${curr.x} ${curr.y}, ${endX} ${endY}`;\n }\n\n const last = points[points.length - 1];\n path += ` L ${last.x} ${last.y}`;\n\n return path;\n }\n\n private generateBezierPath(waypoints: { x: number; y: number }[]): string {\n if (waypoints.length < 2) return '';\n if (waypoints.length === 4) {\n const [start, cp1, cp2, end] = waypoints;\n return `M ${start.x} ${start.y} C ${cp1.x} ${cp1.y}, ${cp2.x} ${cp2.y}, ${end.x} ${end.y}`;\n }\n if (waypoints.length === 3) {\n const [start, cp, end] = waypoints;\n return `M ${start.x} ${start.y} Q ${cp.x} ${cp.y}, ${end.x} ${end.y}`;\n }\n return this.generateStraightPath(waypoints);\n }\n\n private generateStraightPath(waypoints: { x: number; y: number }[]): string {\n if (waypoints.length < 2) return '';\n const start = waypoints[0];\n const end = waypoints[waypoints.length - 1];\n return `M ${start.x} ${start.y} L ${end.x} ${end.y}`;\n }\n\n // Pill rendering helpers\n\n /** Create an injector for a pill component, passing the relationship data */\n createPillInjector(relationshipId: string): Injector {\n const relationship = this.relationships().find(r => r.id === relationshipId);\n return Injector.create({\n providers: [\n { provide: GRAPH_RELATIONSHIP_DATA, useValue: relationship?.data },\n ],\n parent: this.injector,\n });\n }\n}\n","// Models - Types\nexport type {\n GraphNode,\n GraphNodeInternal,\n GraphRelationship,\n RelationshipType,\n ReactiveData,\n GraphPathConfig,\n GraphLayoutConfig,\n GraphConfig,\n NodeSelectEvent,\n NodePositionChangeEvent,\n RelationshipSelectEvent,\n} from './lib/models/graph.models';\n\n// Models - Values\nexport {\n GRAPH_NODE_DATA,\n GRAPH_RELATIONSHIP_DATA,\n DEFAULT_GRAPH_PATH_CONFIG,\n DEFAULT_GRAPH_LAYOUT_CONFIG,\n DEFAULT_GRAPH_CONFIG,\n} from './lib/models/graph.models';\n\n// Re-export animation types from grid for convenience\nexport type {\n ViewportAnimationOptions,\n EasingFunction,\n EasingName,\n} from '@ngx-km/grid';\nexport {\n EASING_FUNCTIONS,\n DEFAULT_ANIMATION_DURATION,\n DEFAULT_EASING,\n} from '@ngx-km/grid';\n\n// Re-export layout types for convenience\nexport type {\n LayoutAlgorithm,\n LayoutDirection,\n LayeredLayoutOptions,\n ForceLayoutOptions,\n StressLayoutOptions,\n RadialLayoutOptions,\n TreeLayoutOptions,\n LayeredEdgeType,\n LayeredEdgeHint,\n ForceEdgeHint,\n} from '@ngx-km/layout';\n\n// Components\nexport { GraphComponent } from './lib/components/graph.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
2
|
import { Type, Signal, InjectionToken, Injector } from '@angular/core';
|
|
3
|
-
import { GridConfig, ViewportState, GridElement, RenderedElement, ElementPositionChange } from '@ngx-km/grid';
|
|
3
|
+
import { GridConfig, ViewportState, GridElement, RenderedElement, ElementPositionChange, ViewportAnimationOptions } from '@ngx-km/grid';
|
|
4
|
+
export { DEFAULT_ANIMATION_DURATION, DEFAULT_EASING, EASING_FUNCTIONS, EasingFunction, EasingName, ViewportAnimationOptions } from '@ngx-km/grid';
|
|
4
5
|
import * as _ngx_km_layout from '@ngx-km/layout';
|
|
5
|
-
import { LayoutAlgorithm,
|
|
6
|
+
import { LayeredEdgeHint, ForceEdgeHint, LayoutAlgorithm, LayeredLayoutOptions, ForceLayoutOptions, StressLayoutOptions, RadialLayoutOptions, TreeLayoutOptions } from '@ngx-km/layout';
|
|
7
|
+
export { ForceEdgeHint, ForceLayoutOptions, LayeredEdgeHint, LayeredEdgeType, LayeredLayoutOptions, LayoutAlgorithm, LayoutDirection, RadialLayoutOptions, StressLayoutOptions, TreeLayoutOptions } from '@ngx-km/layout';
|
|
6
8
|
import * as _ngx_km_path_finding from '@ngx-km/path-finding';
|
|
7
9
|
import { PathType, CalculatedPath } from '@ngx-km/path-finding';
|
|
8
10
|
import * as _ngx_km_path_drawing from '@ngx-km/path-drawing';
|
|
@@ -85,6 +87,10 @@ interface GraphRelationship<T = unknown> {
|
|
|
85
87
|
sourceAnchorSide?: 'top' | 'right' | 'bottom' | 'left';
|
|
86
88
|
/** Optional: Force specific target anchor side */
|
|
87
89
|
targetAnchorSide?: 'top' | 'right' | 'bottom' | 'left';
|
|
90
|
+
/** Hints for layered layout algorithm (e.g., association for same-layer placement) */
|
|
91
|
+
layered?: LayeredEdgeHint;
|
|
92
|
+
/** Hints for force layout algorithm (e.g., edge strength, ideal length) */
|
|
93
|
+
force?: ForceEdgeHint;
|
|
88
94
|
}
|
|
89
95
|
/**
|
|
90
96
|
* Configuration for path rendering
|
|
@@ -123,23 +129,29 @@ declare const DEFAULT_GRAPH_PATH_CONFIG: Required<GraphPathConfig>;
|
|
|
123
129
|
interface GraphLayoutConfig {
|
|
124
130
|
/** Layout algorithm to use (default: 'layered') */
|
|
125
131
|
algorithm?: LayoutAlgorithm;
|
|
126
|
-
/** Layout direction (default: 'DOWN') */
|
|
127
|
-
direction?: LayoutDirection;
|
|
128
132
|
/** Spacing between nodes in pixels (default: 50) */
|
|
129
133
|
nodeSpacing?: number;
|
|
130
|
-
/** Spacing between layers in pixels (default: 100) */
|
|
131
|
-
layerSpacing?: number;
|
|
132
134
|
/** Whether to run layout automatically on init (default: true) */
|
|
133
135
|
autoLayout?: boolean;
|
|
134
136
|
/** Whether to preserve manually moved node positions on data update (default: true) */
|
|
135
137
|
preservePositions?: boolean;
|
|
136
138
|
/** Padding around content when fitting to view after layout (default: 40) */
|
|
137
139
|
fitPadding?: number;
|
|
140
|
+
/** Options for layered (hierarchical) layout */
|
|
141
|
+
layered?: LayeredLayoutOptions;
|
|
142
|
+
/** Options for force-directed layout */
|
|
143
|
+
force?: ForceLayoutOptions;
|
|
144
|
+
/** Options for stress layout */
|
|
145
|
+
stress?: StressLayoutOptions;
|
|
146
|
+
/** Options for radial layout */
|
|
147
|
+
radial?: RadialLayoutOptions;
|
|
148
|
+
/** Options for tree layout */
|
|
149
|
+
tree?: TreeLayoutOptions;
|
|
138
150
|
}
|
|
139
151
|
/**
|
|
140
152
|
* Default layout configuration
|
|
141
153
|
*/
|
|
142
|
-
declare const DEFAULT_GRAPH_LAYOUT_CONFIG:
|
|
154
|
+
declare const DEFAULT_GRAPH_LAYOUT_CONFIG: GraphLayoutConfig;
|
|
143
155
|
/**
|
|
144
156
|
* Main configuration for the graph component
|
|
145
157
|
* Combines grid, layout, and path configurations
|
|
@@ -206,13 +218,16 @@ declare class GraphComponent<TNode = unknown, TRelationship = unknown> {
|
|
|
206
218
|
layoutReady: _angular_core.WritableSignal<boolean>;
|
|
207
219
|
gridConfig: _angular_core.Signal<GridConfig>;
|
|
208
220
|
layoutConfig: _angular_core.Signal<{
|
|
209
|
-
algorithm
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
221
|
+
algorithm?: _ngx_km_layout.LayoutAlgorithm;
|
|
222
|
+
nodeSpacing?: number;
|
|
223
|
+
autoLayout?: boolean;
|
|
224
|
+
preservePositions?: boolean;
|
|
225
|
+
fitPadding?: number;
|
|
226
|
+
layered?: _ngx_km_layout.LayeredLayoutOptions;
|
|
227
|
+
force?: _ngx_km_layout.ForceLayoutOptions;
|
|
228
|
+
stress?: _ngx_km_layout.StressLayoutOptions;
|
|
229
|
+
radial?: _ngx_km_layout.RadialLayoutOptions;
|
|
230
|
+
tree?: _ngx_km_layout.TreeLayoutOptions;
|
|
216
231
|
}>;
|
|
217
232
|
pathConfig: _angular_core.Signal<{
|
|
218
233
|
pathType: _ngx_km_path_finding.PathType;
|
|
@@ -241,8 +256,9 @@ declare class GraphComponent<TNode = unknown, TRelationship = unknown> {
|
|
|
241
256
|
* Centers content in the viewport, optionally zooming out to fit everything
|
|
242
257
|
* @param fitZoom If true, zooms out if needed to fit all content (never zooms in beyond 1.0)
|
|
243
258
|
* @param padding Padding around content in pixels (default: 40)
|
|
259
|
+
* @param options Animation options
|
|
244
260
|
*/
|
|
245
|
-
fitToView(fitZoom?: boolean, padding?: number): void;
|
|
261
|
+
fitToView(fitZoom?: boolean, padding?: number, options?: ViewportAnimationOptions): void;
|
|
246
262
|
/**
|
|
247
263
|
* Check if a node is fully visible in the viewport
|
|
248
264
|
* @param nodeId The node ID to check
|
|
@@ -253,17 +269,21 @@ declare class GraphComponent<TNode = unknown, TRelationship = unknown> {
|
|
|
253
269
|
/**
|
|
254
270
|
* Center viewport on a specific node (no zoom change)
|
|
255
271
|
* @param nodeId The node ID to center on
|
|
272
|
+
* @param options Animation options
|
|
256
273
|
*/
|
|
257
|
-
centerOnNode(nodeId: string): void;
|
|
274
|
+
centerOnNode(nodeId: string, options?: ViewportAnimationOptions): void;
|
|
258
275
|
/**
|
|
259
276
|
* Scroll node into view with minimal pan
|
|
260
277
|
* Only pans if node is not fully visible
|
|
261
278
|
* @param nodeId The node ID to scroll into view
|
|
262
279
|
* @param padding Padding from viewport edges (default: 40)
|
|
280
|
+
* @param options Animation options
|
|
263
281
|
*/
|
|
264
|
-
scrollToNode(nodeId: string, padding?: number): void;
|
|
282
|
+
scrollToNode(nodeId: string, padding?: number, options?: ViewportAnimationOptions): void;
|
|
265
283
|
private runLayout;
|
|
266
284
|
private calculatePaths;
|
|
285
|
+
/** Check if a relationship is two-way/bidirectional */
|
|
286
|
+
isTwoWay(relationshipId: string): boolean;
|
|
267
287
|
getArrowPoints(): string;
|
|
268
288
|
getStrokeDasharray(): string;
|
|
269
289
|
getPathD(path: CalculatedPath): string;
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngx-km/graph",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"dependencies": {
|
|
5
|
-
"@ngx-km/grid": "^0.0.
|
|
6
|
-
"@ngx-km/layout": "^0.0.
|
|
5
|
+
"@ngx-km/grid": "^0.0.3",
|
|
6
|
+
"@ngx-km/layout": "^0.0.3",
|
|
7
7
|
"@ngx-km/path-finding": "^0.0.2",
|
|
8
8
|
"@ngx-km/path-drawing": "^0.0.2",
|
|
9
9
|
"tslib": "^2.3.0"
|