@memberjunction/ng-graph-view 6.2.0-edge.0 → 6.2.0-edge.2

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.
@@ -53,10 +53,10 @@ export declare class GraphViewComponent implements OnInit, OnChanges, OnDestroy
53
53
  ngOnInit(): void;
54
54
  ngOnChanges(changes: SimpleChanges): void;
55
55
  ngOnDestroy(): void;
56
- private InitializePositions;
56
+ private initializePositions;
57
57
  SimulatePhysics(): void;
58
- private SyncCoordinates;
59
- private ApplyCircularLayout;
58
+ private syncCoordinates;
59
+ private applyCircularLayout;
60
60
  ZoomIn(): void;
61
61
  ZoomOut(): void;
62
62
  FitToView(): void;
@@ -75,10 +75,10 @@ export declare class GraphViewComponent implements OnInit, OnChanges, OnDestroy
75
75
  OnCanvasMouseUp(_event: MouseEvent): void;
76
76
  OnCanvasWheel(event: WheelEvent): void;
77
77
  OnNodeMouseDown(node: GraphNode, event: MouseEvent): void;
78
- private EmitViewport;
79
- private GetCanvasRelativeCoords;
80
- private GetContainerWidth;
81
- private GetContainerHeight;
78
+ private emitViewport;
79
+ private getCanvasRelativeCoords;
80
+ private getContainerWidth;
81
+ private getContainerHeight;
82
82
  ApplyFilters(): void;
83
83
  GetNodeX(id: string): number;
84
84
  GetNodeY(id: string): number;
@@ -551,13 +551,13 @@ export class GraphViewComponent {
551
551
  draggedNode = null;
552
552
  simulation = null;
553
553
  ngOnInit() {
554
- this.InitializePositions();
554
+ this.initializePositions();
555
555
  this.ApplyFilters();
556
556
  this.SimulatePhysics();
557
557
  }
558
558
  ngOnChanges(changes) {
559
559
  if (changes['Nodes'] || changes['Edges']) {
560
- this.InitializePositions();
560
+ this.initializePositions();
561
561
  this.ApplyFilters();
562
562
  this.SimulatePhysics();
563
563
  }
@@ -575,9 +575,9 @@ export class GraphViewComponent {
575
575
  }
576
576
  }
577
577
  // ── Positioning & D3 Physics Engine ──────────────────────────────────
578
- InitializePositions() {
579
- const cx = this.GetContainerWidth() / 2 || 400;
580
- const cy = this.GetContainerHeight() / 2 || 250;
578
+ initializePositions() {
579
+ const cx = this.getContainerWidth() / 2 || 400;
580
+ const cy = this.getContainerHeight() / 2 || 250;
581
581
  const count = this.Nodes.length || 1;
582
582
  this.Nodes.forEach((node, idx) => {
583
583
  if (node.x === undefined || node.y === undefined) {
@@ -602,7 +602,7 @@ export class GraphViewComponent {
602
602
  }
603
603
  SimulatePhysics() {
604
604
  if (this.LayoutMode === 'circular') {
605
- this.ApplyCircularLayout();
605
+ this.applyCircularLayout();
606
606
  if (this.AutoFitOnLoad) {
607
607
  this.AutoFitToView();
608
608
  }
@@ -613,8 +613,8 @@ export class GraphViewComponent {
613
613
  this.simulation.stop();
614
614
  this.simulation = null;
615
615
  }
616
- const cx = this.GetContainerWidth() / 2 || 400;
617
- const cy = this.GetContainerHeight() / 2 || 250;
616
+ const cx = this.getContainerWidth() / 2 || 400;
617
+ const cy = this.getContainerHeight() / 2 || 250;
618
618
  // Resolve endpoints to node objects so a case-skewed UUID or dangling
619
619
  // edge cannot throw "node not found" out of ngOnInit. Raw-string
620
620
  // .id(d => d.ID) compared with ===, which UUIDsEqual elsewhere
@@ -647,19 +647,19 @@ export class GraphViewComponent {
647
647
  for (let i = 0; i < 90; ++i) {
648
648
  this.simulation.tick();
649
649
  }
650
- this.SyncCoordinates();
650
+ this.syncCoordinates();
651
651
  // Auto-center & fit into view
652
652
  if (this.AutoFitOnLoad) {
653
653
  this.AutoFitToView();
654
654
  }
655
655
  // Attach live tick handler for interactive drag & drop
656
656
  this.simulation.on('tick', () => {
657
- this.SyncCoordinates();
657
+ this.syncCoordinates();
658
658
  this.cdr.markForCheck();
659
659
  });
660
660
  this.cdr.markForCheck();
661
661
  }
662
- SyncCoordinates() {
662
+ syncCoordinates() {
663
663
  for (const n of this.Nodes) {
664
664
  n.X = n.x;
665
665
  n.Y = n.y;
@@ -667,9 +667,9 @@ export class GraphViewComponent {
667
667
  n.VY = n.vy;
668
668
  }
669
669
  }
670
- ApplyCircularLayout() {
671
- const cx = this.GetContainerWidth() / 2 || 400;
672
- const cy = this.GetContainerHeight() / 2 || 250;
670
+ applyCircularLayout() {
671
+ const cx = this.getContainerWidth() / 2 || 400;
672
+ const cy = this.getContainerHeight() / 2 || 250;
673
673
  const r = Math.min(cx, cy) * 0.7 || 160;
674
674
  const count = this.Nodes.length || 1;
675
675
  this.Nodes.forEach((node, idx) => {
@@ -683,11 +683,11 @@ export class GraphViewComponent {
683
683
  // ── Public Programmatic Methods ───────────────────────────────────
684
684
  ZoomIn() {
685
685
  this.Scale = Math.min(this.Scale * 1.2, 3.0);
686
- this.EmitViewport();
686
+ this.emitViewport();
687
687
  }
688
688
  ZoomOut() {
689
689
  this.Scale = Math.max(this.Scale / 1.2, 0.3);
690
- this.EmitViewport();
690
+ this.emitViewport();
691
691
  }
692
692
  FitToView() {
693
693
  this.AutoFitToView(40);
@@ -695,8 +695,8 @@ export class GraphViewComponent {
695
695
  AutoFitToView(padding = 40) {
696
696
  if (!this.Nodes || this.Nodes.length === 0)
697
697
  return;
698
- const width = this.GetContainerWidth() || 800;
699
- const height = this.GetContainerHeight() || 420;
698
+ const width = this.getContainerWidth() || 800;
699
+ const height = this.getContainerHeight() || 420;
700
700
  let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
701
701
  for (const n of this.Nodes) {
702
702
  const nx = n.x ?? n.X ?? 0;
@@ -721,11 +721,11 @@ export class GraphViewComponent {
721
721
  this.Scale = targetScale;
722
722
  this.PanX = (width - (minX + maxX) * this.Scale) / 2;
723
723
  this.PanY = (height - (minY + maxY) * this.Scale) / 2;
724
- this.EmitViewport();
724
+ this.emitViewport();
725
725
  this.cdr.markForCheck();
726
726
  }
727
727
  Rearrange() {
728
- this.InitializePositions();
728
+ this.initializePositions();
729
729
  this.SimulatePhysics();
730
730
  }
731
731
  SetLayoutMode(mode) {
@@ -817,11 +817,11 @@ export class GraphViewComponent {
817
817
  if (this.IsPanning) {
818
818
  this.PanX = event.clientX - this.panStartX;
819
819
  this.PanY = event.clientY - this.panStartY;
820
- this.EmitViewport();
820
+ this.emitViewport();
821
821
  this.cdr.markForCheck();
822
822
  }
823
823
  else if (this.draggedNode) {
824
- const coords = this.GetCanvasRelativeCoords(event);
824
+ const coords = this.getCanvasRelativeCoords(event);
825
825
  this.draggedNode.fx = coords.x;
826
826
  this.draggedNode.fy = coords.y;
827
827
  this.draggedNode.x = coords.x;
@@ -846,7 +846,7 @@ export class GraphViewComponent {
846
846
  event.preventDefault();
847
847
  const delta = event.deltaY > 0 ? 0.9 : 1.1;
848
848
  this.Scale = Math.min(Math.max(this.Scale * delta, 0.3), 3.0);
849
- this.EmitViewport();
849
+ this.emitViewport();
850
850
  this.cdr.markForCheck();
851
851
  }
852
852
  OnNodeMouseDown(node, event) {
@@ -858,11 +858,11 @@ export class GraphViewComponent {
858
858
  this.simulation.alphaTarget(0.3).restart();
859
859
  }
860
860
  }
861
- EmitViewport() {
861
+ emitViewport() {
862
862
  this.ViewportTransform.emit(new ViewportTransformEventArgs({ Scale: this.Scale, PanX: this.PanX, PanY: this.PanY }));
863
863
  this.cdr.markForCheck();
864
864
  }
865
- GetCanvasRelativeCoords(event) {
865
+ getCanvasRelativeCoords(event) {
866
866
  const canvas = this.CanvasRef?.nativeElement;
867
867
  if (!canvas) {
868
868
  return {
@@ -878,10 +878,10 @@ export class GraphViewComponent {
878
878
  y: (mouseY - this.PanY) / this.Scale
879
879
  };
880
880
  }
881
- GetContainerWidth() {
881
+ getContainerWidth() {
882
882
  return this.CanvasRef?.nativeElement?.clientWidth || this.WrapperRef?.nativeElement?.clientWidth || 800;
883
883
  }
884
- GetContainerHeight() {
884
+ getContainerHeight() {
885
885
  return this.CanvasRef?.nativeElement?.clientHeight || this.WrapperRef?.nativeElement?.clientHeight || 420;
886
886
  }
887
887
  // ── Helpers ───────────────────────────────────────────────────────
@@ -1 +1 @@
1
- {"version":3,"file":"graph-view.component.js","sourceRoot":"","sources":["../../../src/lib/components/graph-view.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit,\n OnChanges,\n OnDestroy,\n SimpleChanges,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n ElementRef,\n ViewChild,\n inject\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { NormalizeUUID, UUIDsEqual } from '@memberjunction/global';\nimport * as d3 from 'd3';\nimport type {\n GraphNode,\n GraphEdge,\n GraphLayoutMode,\n GraphNodeCategory,\n GraphCategoryConfig,\n GraphViewportTransform,\n GraphPhysicsConfig\n} from '../models/graph-models';\nimport {\n BeforeNodeSelectEventArgs,\n NodeSelectedEventArgs,\n BeforeEdgeSelectEventArgs,\n EdgeSelectedEventArgs,\n BeforeHopExpandEventArgs,\n HopExpandedEventArgs,\n BeforeLayoutChangeEventArgs,\n LayoutChangedEventArgs,\n BeforeNodeNavigateEventArgs,\n NodeNavigatedEventArgs,\n ViewportTransformEventArgs\n} from '../events/graph-events';\n\nexport const DEFAULT_GRAPH_CATEGORIES: GraphCategoryConfig[] = [\n { Category: 'person', Label: 'Person', Color: '#10b981', IconClass: 'fa-solid fa-user' },\n { Category: 'organization', Label: 'Organization', Color: '#38bdf8', IconClass: 'fa-solid fa-building' },\n { Category: 'committee', Label: 'Committee', Color: '#8b5cf6', IconClass: 'fa-solid fa-landmark' },\n { Category: 'account', Label: 'Holding / Account', Color: '#f59e0b', IconClass: 'fa-solid fa-building-flag' },\n { Category: 'asset', Label: 'Asset', Color: '#ec4899', IconClass: 'fa-solid fa-gem' },\n { Category: 'group', Label: 'Group', Color: '#06b6d4', IconClass: 'fa-solid fa-users' },\n { Category: 'custom', Label: 'Custom', Color: '#64748b', IconClass: 'fa-solid fa-circle-nodes' }\n];\n\nconst DYNAMIC_CATEGORY_PALETTE = [\n '#10b981', '#38bdf8', '#8b5cf6', '#f59e0b', '#ec4899',\n '#06b6d4', '#84cc16', '#f43f5e', '#a855f7', '#14b8a6'\n];\n\nconst GRAPH_VIEW_CSS = `\n:host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n background: var(--mj-bg-surface-sunken, #0b1220);\n border-radius: var(--mj-radius-lg, 12px);\n border: 1px solid var(--mj-border-default, #223254);\n user-select: none;\n}\n\n.mj-graph-wrapper {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.mj-graph-svg-canvas {\n width: 100%;\n height: 100%;\n cursor: grab;\n}\n\n.mj-graph-svg-canvas.is-panning {\n cursor: grabbing;\n}\n\n/* Floating Toolbar */\n.mj-graph-toolbar {\n position: absolute;\n top: 14px;\n left: 14px;\n z-index: 20;\n display: flex;\n align-items: center;\n gap: 8px;\n background: rgba(20, 31, 54, 0.88);\n backdrop-filter: blur(10px);\n border: 1px solid var(--mj-border-default, #223254);\n padding: 6px 12px;\n border-radius: var(--mj-radius-lg, 10px);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);\n}\n\n.mj-graph-tool-btn {\n background: var(--mj-bg-surface-elevated, #1a2744);\n border: 1px solid var(--mj-border-default, #223254);\n color: var(--mj-text-primary, #f8fafc);\n border-radius: 6px;\n padding: 5px 10px;\n font-size: 11.5px;\n font-weight: 600;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.15s ease;\n}\n\n.mj-graph-tool-btn:hover {\n border-color: var(--mj-brand-primary, #38bdf8);\n background: var(--mj-border-hover, #334876);\n}\n\n.mj-graph-tool-btn.active {\n background: var(--mj-brand-primary, #38bdf8);\n color: #090e1a;\n border-color: var(--mj-brand-primary, #38bdf8);\n}\n\n.mj-graph-separator {\n width: 1px;\n height: 18px;\n background: var(--mj-border-default, #223254);\n}\n\n.mj-graph-search-input {\n background: var(--mj-bg-surface-sunken, #090e1a);\n border: 1px solid var(--mj-border-default, #223254);\n border-radius: 6px;\n color: var(--mj-text-primary, #f8fafc);\n padding: 4px 8px 4px 24px;\n font-size: 11.5px;\n width: 150px;\n}\n\n.mj-graph-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary, #38bdf8);\n width: 190px;\n}\n\n/* Floating Legend */\n.mj-graph-legend {\n position: absolute;\n bottom: 14px;\n left: 14px;\n z-index: 20;\n display: flex;\n align-items: center;\n gap: 12px;\n background: rgba(20, 31, 54, 0.88);\n backdrop-filter: blur(10px);\n border: 1px solid var(--mj-border-default, #223254);\n padding: 6px 14px;\n border-radius: var(--mj-radius-lg, 10px);\n font-size: 11.5px;\n color: var(--mj-text-secondary, #94a3b8);\n}\n\n.mj-graph-legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.mj-graph-legend-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n}\n\n/* Inspector Drawer */\n.mj-graph-inspector {\n position: absolute;\n top: 14px;\n right: 14px;\n width: 300px;\n max-height: calc(100% - 28px);\n background: rgba(20, 31, 54, 0.95);\n backdrop-filter: blur(14px);\n border: 1px solid var(--mj-border-default, #223254);\n border-radius: var(--mj-radius-lg, 12px);\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n z-index: 25;\n box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);\n overflow-y: auto;\n scrollbar-width: thin;\n animation: mjGraphSlide 0.2s ease;\n}\n\n.mj-graph-inspector-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.mj-graph-inspector-title {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--mj-text-muted, #64748b);\n}\n\n.mj-graph-inspector-close {\n background: none;\n border: none;\n color: var(--mj-text-muted, #64748b);\n cursor: pointer;\n font-size: 14px;\n}\n\n.mj-graph-inspector-card {\n display: flex;\n align-items: center;\n gap: 12px;\n background: var(--mj-bg-surface, #111a2e);\n border: 1px solid var(--mj-border-default, #223254);\n border-radius: 8px;\n padding: 10px 12px;\n}\n\n.mj-graph-inspector-avatar {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n color: #fff;\n flex-shrink: 0;\n}\n\n.mj-graph-inspector-actions {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-top: 4px;\n}\n\n/* SVG Rendering Elements */\n.mj-edge-path {\n stroke: var(--mj-border-hover, #2d416b);\n stroke-width: 2;\n fill: none;\n transition: stroke 0.2s ease;\n}\n\n.mj-edge-path.is-highlighted {\n stroke: var(--mj-brand-primary, #38bdf8);\n stroke-width: 3;\n}\n\n.mj-edge-text {\n font-size: 10px;\n font-weight: 500;\n fill: var(--mj-text-muted, #64748b);\n text-anchor: middle;\n pointer-events: none;\n paint-order: stroke;\n stroke: var(--mj-bg-surface-sunken, #0b1220);\n stroke-width: 3px;\n stroke-linecap: butt;\n stroke-linejoin: miter;\n}\n\n.mj-node-group {\n cursor: pointer;\n transition: transform 0.1s ease;\n}\n\n.mj-node-group:hover .mj-node-circle {\n filter: drop-shadow(0 0 10px var(--mj-brand-primary, #38bdf8));\n}\n\n.mj-node-circle {\n transition: all 0.2s ease;\n}\n\n.mj-node-label {\n font-size: 11px;\n font-weight: 700;\n fill: var(--mj-text-primary, #f8fafc);\n text-anchor: middle;\n pointer-events: none;\n}\n\n.mj-node-sublabel {\n font-size: 9.5px;\n font-weight: 500;\n fill: var(--mj-text-secondary, #94a3b8);\n text-anchor: middle;\n pointer-events: none;\n}\n\n@keyframes mjGraphSlide {\n from { opacity: 0; transform: translateX(20px); }\n to { opacity: 1; transform: translateX(0); }\n}\n`;\n\n/**\n * `<mj-graph-view>` — Interactive network and entity relationship graph visualization.\n *\n * Supports force-directed dynamic layout, multi-category entity badges, hop-expansion,\n * zoom/pan controls, inspector drawer, search filters, and cancelable Before/After event pairs.\n */\n@Component({\n selector: 'mj-graph-view',\n standalone: true,\n imports: [CommonModule, FormsModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"mj-graph-wrapper\" #wrapper>\n <!-- 1. Floating Action Toolbar -->\n @if (ShowToolbar) {\n <div class=\"mj-graph-toolbar\">\n <span style=\"font-size: 12px; font-weight: 700; color: #fff; display: flex; align-items: center; gap: 6px;\">\n <i class=\"fa-solid fa-circle-nodes\" style=\"color: var(--mj-brand-primary);\"></i>\n Network Graph\n </span>\n\n <div class=\"mj-graph-separator\"></div>\n\n <!-- Layout Mode Selector -->\n <button\n type=\"button\"\n class=\"mj-graph-tool-btn\"\n [class.active]=\"LayoutMode === 'force'\"\n (click)=\"SetLayoutMode('force')\"\n title=\"Force-Directed Physics\">\n <i class=\"fa-solid fa-atom\"></i> Force\n </button>\n <button\n type=\"button\"\n class=\"mj-graph-tool-btn\"\n [class.active]=\"LayoutMode === 'circular'\"\n (click)=\"SetLayoutMode('circular')\"\n title=\"Circular Layout\">\n <i class=\"fa-solid fa-circle-notch\"></i> Circular\n </button>\n\n <div class=\"mj-graph-separator\"></div>\n\n <!-- Zoom Controls -->\n <button type=\"button\" class=\"mj-graph-tool-btn\" (click)=\"ZoomIn()\" title=\"Zoom In\">\n <i class=\"fa-solid fa-magnifying-glass-plus\"></i>\n </button>\n <button type=\"button\" class=\"mj-graph-tool-btn\" (click)=\"ZoomOut()\" title=\"Zoom Out\">\n <i class=\"fa-solid fa-magnifying-glass-minus\"></i>\n </button>\n <button type=\"button\" class=\"mj-graph-tool-btn\" (click)=\"FitToView()\" title=\"Fit View\">\n <i class=\"fa-solid fa-expand\"></i>\n </button>\n <button type=\"button\" class=\"mj-graph-tool-btn\" (click)=\"Rearrange()\" title=\"Re-simulate Physics\">\n <i class=\"fa-solid fa-arrows-rotate\"></i>\n </button>\n\n @if (Searchable) {\n <div class=\"mj-graph-separator\"></div>\n <div style=\"position: relative;\">\n <i class=\"fa-solid fa-magnifying-glass\" style=\"position: absolute; left: 8px; top: 50%; transform: translateY(-50%); font-size: 10px; color: var(--mj-text-muted);\"></i>\n <input\n class=\"mj-graph-search-input\"\n [(ngModel)]=\"SearchQuery\"\n (ngModelChange)=\"SearchNodes($event)\"\n placeholder=\"Search graph nodes...\" />\n </div>\n }\n </div>\n }\n\n <!-- 2. Floating Dynamic Category Legend -->\n @if (ShowLegend && ActiveCategories.length > 0) {\n <div class=\"mj-graph-legend\">\n @for (cat of ActiveCategories; track cat.Category) {\n <div class=\"mj-graph-legend-item\">\n <div class=\"mj-graph-legend-dot\" [style.background]=\"cat.Color\"></div>\n {{ cat.Label }}\n </div>\n }\n </div>\n }\n\n <!-- 3. Selected Node Inspector Drawer -->\n @if (ShowInspector && SelectedNode) {\n <div class=\"mj-graph-inspector\">\n <div class=\"mj-graph-inspector-header\">\n <span class=\"mj-graph-inspector-title\">Node Inspector</span>\n <button class=\"mj-graph-inspector-close\" type=\"button\" (click)=\"ClearSelection()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <div class=\"mj-graph-inspector-card\">\n <div class=\"mj-graph-inspector-avatar\" [style.background]=\"GetNodeColor(SelectedNode)\">\n <i [class]=\"GetNodeIcon(SelectedNode)\"></i>\n </div>\n <div style=\"overflow: hidden; flex: 1;\">\n <div style=\"font-size: 13px; font-weight: 700; color: #fff; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;\">\n {{ SelectedNode.Label }}\n </div>\n <div style=\"display: flex; align-items: center; gap: 6px; margin-top: 3px;\">\n <span style=\"font-size: 11px; color: var(--mj-text-secondary);\">\n {{ SelectedNode.Sublabel || SelectedNode.Category }}\n </span>\n @if (IsFocalNode(SelectedNode)) {\n <span style=\"font-size: 10px; padding: 1px 6px; border-radius: 9999px; background: rgba(56, 189, 248, 0.15); color: #38bdf8; font-weight: 600; border: 1px solid rgba(56, 189, 248, 0.3);\">Current Record</span>\n }\n </div>\n </div>\n </div>\n\n <div style=\"font-size: 11.5px; color: var(--mj-text-secondary); line-height: 1.45;\">\n Direct Connected Edges: <strong>{{ GetNodeEdgeCount(SelectedNode.ID) }}</strong>\n </div>\n\n <div class=\"mj-graph-inspector-actions\">\n @if (!IsFocalNode(SelectedNode)) {\n <button\n type=\"button\"\n class=\"mj-graph-tool-btn active\"\n style=\"justify-content: center; width: 100%;\"\n (click)=\"NavigateToEntity(SelectedNode)\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Open Entity Form\n </button>\n }\n <button\n type=\"button\"\n class=\"mj-graph-tool-btn\"\n style=\"justify-content: center; width: 100%;\"\n (click)=\"ExpandHops(SelectedNode.ID, 1)\">\n <i class=\"fa-solid fa-circle-nodes\"></i> Expand 1-Hop Neighbors\n </button>\n </div>\n </div>\n }\n\n <!-- 4. Interactive SVG Graph Canvas -->\n <svg\n #svgCanvas\n class=\"mj-graph-svg-canvas\"\n [class.is-panning]=\"IsPanning\"\n (mousedown)=\"OnCanvasMouseDown($event)\"\n (mousemove)=\"OnCanvasMouseMove($event)\"\n (mouseup)=\"OnCanvasMouseUp($event)\"\n (mouseleave)=\"OnCanvasMouseUp($event)\"\n (wheel)=\"OnCanvasWheel($event)\">\n\n <g [attr.transform]=\"'translate(' + PanX + ',' + PanY + ') scale(' + Scale + ')'\">\n <!-- Edges Layer -->\n @for (edge of Edges; track edge.ID) {\n <g>\n <line\n class=\"mj-edge-path\"\n [class.is-highlighted]=\"IsEdgeHighlighted(edge)\"\n [attr.x1]=\"GetNodeX(edge.SourceID)\"\n [attr.y1]=\"GetNodeY(edge.SourceID)\"\n [attr.x2]=\"GetNodeX(edge.TargetID)\"\n [attr.y2]=\"GetNodeY(edge.TargetID)\"\n (click)=\"OnEdgeClick(edge, $event)\">\n </line>\n <text\n class=\"mj-edge-text\"\n [attr.x]=\"(GetNodeX(edge.SourceID) + GetNodeX(edge.TargetID)) / 2\"\n [attr.y]=\"(GetNodeY(edge.SourceID) + GetNodeY(edge.TargetID)) / 2 - 4\">\n {{ edge.Label }}\n </text>\n </g>\n }\n\n <!-- Nodes Layer -->\n @for (node of FilteredNodes; track node.ID) {\n <g\n class=\"mj-node-group\"\n [attr.transform]=\"'translate(' + (node.X || 0) + ',' + (node.Y || 0) + ')'\"\n (mousedown)=\"OnNodeMouseDown(node, $event)\"\n (click)=\"OnNodeClick(node, $event)\"\n (dblclick)=\"NavigateToEntity(node)\">\n\n <!-- Outer Selection / Focal Halo -->\n @if (IsNodeSelected(node)) {\n <circle r=\"36\" fill=\"rgba(56, 189, 248, 0.2)\" stroke=\"#38bdf8\" stroke-width=\"2\"></circle>\n } @else if (IsFocalNode(node)) {\n <circle r=\"34\" fill=\"none\" stroke=\"rgba(56, 189, 248, 0.45)\" stroke-width=\"2\" stroke-dasharray=\"4 3\"></circle>\n }\n\n <!-- Node Body Circle -->\n <circle\n class=\"mj-node-circle\"\n [attr.r]=\"node.Radius || 26\"\n fill=\"#141f36\"\n [attr.stroke]=\"GetNodeColor(node)\"\n stroke-width=\"3\">\n </circle>\n\n <!-- Node Icon Center -->\n <circle [attr.r]=\"(node.Radius || 26) - 8\" [attr.fill]=\"GetNodeColor(node)\"></circle>\n\n <!-- Labels -->\n <text class=\"mj-node-label\" [attr.y]=\"(node.Radius || 26) + 16\">\n {{ TruncateLabel(node.Label, 18) }}\n </text>\n @if (node.Sublabel) {\n <text class=\"mj-node-sublabel\" [attr.y]=\"(node.Radius || 26) + 28\">\n {{ TruncateLabel(node.Sublabel, 20) }}\n </text>\n }\n </g>\n }\n </g>\n </svg>\n </div>\n `,\n styles: [GRAPH_VIEW_CSS]\n})\nexport class GraphViewComponent implements OnInit, OnChanges, OnDestroy {\n private cdr = inject(ChangeDetectorRef);\n\n @ViewChild('wrapper', { static: true }) public WrapperRef!: ElementRef<HTMLDivElement>;\n @ViewChild('svgCanvas', { static: true }) public CanvasRef!: ElementRef<SVGSVGElement>;\n\n // ── Inputs ────────────────────────────────────────────────────────\n @Input() public Nodes: GraphNode[] = [];\n @Input() public Edges: GraphEdge[] = [];\n @Input() public Categories: GraphCategoryConfig[] = DEFAULT_GRAPH_CATEGORIES;\n @Input() public LayoutMode: GraphLayoutMode = 'force';\n @Input() public MaxHopDistance = 2;\n @Input() public SelectedNodeId?: string;\n @Input() public FocalNodeId?: string;\n @Input() public AutoOpenInspector = false;\n @Input() public ShowToolbar = true;\n @Input() public ShowLegend = true;\n @Input() public ShowInspector = true;\n @Input() public Searchable = true;\n @Input() public AutoFitOnLoad = true;\n @Input() public Physics: GraphPhysicsConfig = {\n Repulsion: -500,\n LinkDistance: 130,\n Gravity: 0.05,\n Damping: 0.88,\n MaxIterations: 200\n };\n\n // ── Cancelable Before/After Outputs ────────────────────────────────\n @Output() public BeforeNodeSelect = new EventEmitter<BeforeNodeSelectEventArgs>();\n @Output() public NodeSelected = new EventEmitter<NodeSelectedEventArgs>();\n\n @Output() public BeforeEdgeSelect = new EventEmitter<BeforeEdgeSelectEventArgs>();\n @Output() public EdgeSelected = new EventEmitter<EdgeSelectedEventArgs>();\n\n @Output() public BeforeHopExpand = new EventEmitter<BeforeHopExpandEventArgs>();\n @Output() public HopExpanded = new EventEmitter<HopExpandedEventArgs>();\n\n @Output() public BeforeLayoutChange = new EventEmitter<BeforeLayoutChangeEventArgs>();\n @Output() public LayoutChanged = new EventEmitter<LayoutChangedEventArgs>();\n\n @Output() public BeforeNodeNavigate = new EventEmitter<BeforeNodeNavigateEventArgs>();\n @Output() public NodeNavigated = new EventEmitter<NodeNavigatedEventArgs>();\n\n @Output() public ViewportTransform = new EventEmitter<ViewportTransformEventArgs>();\n\n // ── Internal State ────────────────────────────────────────────────\n public FilteredNodes: GraphNode[] = [];\n public SelectedNode: GraphNode | null = null;\n public SelectedEdge: GraphEdge | null = null;\n public SearchQuery = '';\n\n public Scale = 1.0;\n public PanX = 200;\n public PanY = 150;\n public IsPanning = false;\n private panStartX = 0;\n private panStartY = 0;\n\n private draggedNode: GraphNode | null = null;\n private simulation: d3.Simulation<GraphNode, d3.SimulationLinkDatum<GraphNode>> | null = null;\n\n public ngOnInit(): void {\n this.InitializePositions();\n this.ApplyFilters();\n this.SimulatePhysics();\n }\n\n public ngOnChanges(changes: SimpleChanges): void {\n if (changes['Nodes'] || changes['Edges']) {\n this.InitializePositions();\n this.ApplyFilters();\n this.SimulatePhysics();\n }\n if (changes['SelectedNodeId'] && this.SelectedNodeId) {\n const found = this.Nodes.find(n => UUIDsEqual(n.ID, this.SelectedNodeId));\n if (found && this.AutoOpenInspector) {\n this.SelectedNode = found;\n }\n }\n }\n\n public ngOnDestroy(): void {\n if (this.simulation) {\n this.simulation.stop();\n this.simulation = null;\n }\n }\n\n // ── Positioning & D3 Physics Engine ──────────────────────────────────\n private InitializePositions(): void {\n const cx = this.GetContainerWidth() / 2 || 400;\n const cy = this.GetContainerHeight() / 2 || 250;\n const count = this.Nodes.length || 1;\n\n this.Nodes.forEach((node, idx) => {\n if (node.x === undefined || node.y === undefined) {\n if (node.X !== undefined && node.Y !== undefined) {\n node.x = node.X;\n node.y = node.Y;\n } else {\n const angle = (idx / count) * 2 * Math.PI;\n const r = 100 + Math.random() * 60;\n node.x = cx + r * Math.cos(angle);\n node.y = cy + r * Math.sin(angle);\n node.X = node.x;\n node.Y = node.y;\n }\n node.vx = 0;\n node.vy = 0;\n node.VX = 0;\n node.VY = 0;\n }\n });\n }\n\n public SimulatePhysics(): void {\n if (this.LayoutMode === 'circular') {\n this.ApplyCircularLayout();\n if (this.AutoFitOnLoad) {\n this.AutoFitToView();\n }\n this.cdr.markForCheck();\n return;\n }\n\n if (this.simulation) {\n this.simulation.stop();\n this.simulation = null;\n }\n\n const cx = this.GetContainerWidth() / 2 || 400;\n const cy = this.GetContainerHeight() / 2 || 250;\n\n // Resolve endpoints to node objects so a case-skewed UUID or dangling\n // edge cannot throw \"node not found\" out of ngOnInit. Raw-string\n // .id(d => d.ID) compared with ===, which UUIDsEqual elsewhere\n // deliberately does not.\n const nodeById = new Map<string, GraphNode>();\n for (const node of this.Nodes) {\n const key = NormalizeUUID(node.ID);\n if (key) {\n nodeById.set(key, node);\n }\n }\n const links: d3.SimulationLinkDatum<GraphNode>[] = [];\n for (const edge of this.Edges) {\n const source = nodeById.get(NormalizeUUID(edge.SourceID));\n const target = nodeById.get(NormalizeUUID(edge.TargetID));\n if (source && target) {\n links.push({ source, target });\n }\n }\n\n this.simulation = d3.forceSimulation<GraphNode>(this.Nodes)\n .force('link', d3.forceLink<GraphNode, d3.SimulationLinkDatum<GraphNode>>(links)\n .distance(this.Physics.LinkDistance || 120))\n .force('charge', d3.forceManyBody<GraphNode>()\n .strength(this.Physics.Repulsion || -450)\n .distanceMax(700))\n .force('collide', d3.forceCollide<GraphNode>((d: GraphNode) => (d.Radius || 26) + 16).iterations(2))\n .force('center', d3.forceCenter<GraphNode>(cx, cy));\n\n // Headless Pre-Warming: run 80 ticks synchronously in memory so the SVG renders resting immediately\n this.simulation.stop();\n for (let i = 0; i < 90; ++i) {\n this.simulation.tick();\n }\n\n this.SyncCoordinates();\n\n // Auto-center & fit into view\n if (this.AutoFitOnLoad) {\n this.AutoFitToView();\n }\n\n // Attach live tick handler for interactive drag & drop\n this.simulation.on('tick', () => {\n this.SyncCoordinates();\n this.cdr.markForCheck();\n });\n\n this.cdr.markForCheck();\n }\n\n private SyncCoordinates(): void {\n for (const n of this.Nodes) {\n n.X = n.x;\n n.Y = n.y;\n n.VX = n.vx;\n n.VY = n.vy;\n }\n }\n\n private ApplyCircularLayout(): void {\n const cx = this.GetContainerWidth() / 2 || 400;\n const cy = this.GetContainerHeight() / 2 || 250;\n const r = Math.min(cx, cy) * 0.7 || 160;\n const count = this.Nodes.length || 1;\n\n this.Nodes.forEach((node, idx) => {\n const angle = (idx / count) * 2 * Math.PI;\n node.x = cx + r * Math.cos(angle);\n node.y = cy + r * Math.sin(angle);\n node.X = node.x;\n node.Y = node.y;\n });\n }\n\n // ── Public Programmatic Methods ───────────────────────────────────\n public ZoomIn(): void {\n this.Scale = Math.min(this.Scale * 1.2, 3.0);\n this.EmitViewport();\n }\n\n public ZoomOut(): void {\n this.Scale = Math.max(this.Scale / 1.2, 0.3);\n this.EmitViewport();\n }\n\n public FitToView(): void {\n this.AutoFitToView(40);\n }\n\n public AutoFitToView(padding = 40): void {\n if (!this.Nodes || this.Nodes.length === 0) return;\n\n const width = this.GetContainerWidth() || 800;\n const height = this.GetContainerHeight() || 420;\n\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const n of this.Nodes) {\n const nx = n.x ?? n.X ?? 0;\n const ny = n.y ?? n.Y ?? 0;\n const r = (n.Radius || 26) + 20; // include badge & labels\n if (nx - r < minX) minX = nx - r;\n if (nx + r > maxX) maxX = nx + r;\n if (ny - r < minY) minY = ny - r;\n if (ny + r > maxY) maxY = ny + r;\n }\n\n if (!isFinite(minX) || !isFinite(maxX) || !isFinite(minY) || !isFinite(maxY)) return;\n\n const bboxW = Math.max(maxX - minX, 100);\n const bboxH = Math.max(maxY - minY, 100);\n\n const scaleX = (width - padding * 2) / bboxW;\n const scaleY = (height - padding * 2) / bboxH;\n const targetScale = Math.min(Math.max(Math.min(scaleX, scaleY), 0.4), 1.25);\n\n this.Scale = targetScale;\n this.PanX = (width - (minX + maxX) * this.Scale) / 2;\n this.PanY = (height - (minY + maxY) * this.Scale) / 2;\n\n this.EmitViewport();\n this.cdr.markForCheck();\n }\n\n public Rearrange(): void {\n this.InitializePositions();\n this.SimulatePhysics();\n }\n\n public SetLayoutMode(mode: GraphLayoutMode): void {\n const beforeEvent = new BeforeLayoutChangeEventArgs(mode, this.LayoutMode);\n this.BeforeLayoutChange.emit(beforeEvent);\n if (beforeEvent.Cancel) return;\n\n const prev = this.LayoutMode;\n this.LayoutMode = mode;\n this.SimulatePhysics();\n this.LayoutChanged.emit(new LayoutChangedEventArgs(mode, prev));\n }\n\n public SelectNode(id: string): void {\n const node = this.Nodes.find(n => UUIDsEqual(n.ID, id));\n if (node) this.OnNodeClick(node, new MouseEvent('click'));\n }\n\n public ClearSelection(): void {\n this.SelectedNode = null;\n this.SelectedEdge = null;\n this.cdr.markForCheck();\n }\n\n public SearchNodes(query: string): void {\n this.SearchQuery = query;\n this.ApplyFilters();\n }\n\n public ExpandHops(nodeId: string, depth: number): void {\n const node = this.Nodes.find(n => UUIDsEqual(n.ID, nodeId));\n if (!node) return;\n\n const beforeEvent = new BeforeHopExpandEventArgs(node, (node.HopDistance || 0) + depth, node.HopDistance || 0);\n this.BeforeHopExpand.emit(beforeEvent);\n if (beforeEvent.Cancel) return;\n\n // Fire after event for host listener to fetch incremental relations\n this.HopExpanded.emit(new HopExpandedEventArgs(node, [], [], (node.HopDistance || 0) + depth));\n }\n\n // ── Event Handlers ────────────────────────────────────────────────\n public OnNodeClick(node: GraphNode, event: MouseEvent): void {\n event.stopPropagation();\n const beforeEvent = new BeforeNodeSelectEventArgs(node, this.SelectedNode);\n this.BeforeNodeSelect.emit(beforeEvent);\n if (beforeEvent.Cancel) return;\n\n const prev = this.SelectedNode;\n this.SelectedNode = node;\n this.SelectedEdge = null;\n this.NodeSelected.emit(new NodeSelectedEventArgs(node, prev));\n this.cdr.markForCheck();\n }\n\n public OnEdgeClick(edge: GraphEdge, event: MouseEvent): void {\n event.stopPropagation();\n const src = this.Nodes.find(n => UUIDsEqual(n.ID, edge.SourceID)) || null;\n const tgt = this.Nodes.find(n => UUIDsEqual(n.ID, edge.TargetID)) || null;\n\n const beforeEvent = new BeforeEdgeSelectEventArgs(edge, src, tgt);\n this.BeforeEdgeSelect.emit(beforeEvent);\n if (beforeEvent.Cancel) return;\n\n this.SelectedEdge = edge;\n this.EdgeSelected.emit(new EdgeSelectedEventArgs(edge, src, tgt));\n this.cdr.markForCheck();\n }\n\n public NavigateToEntity(node: GraphNode): void {\n // Focal-node dblclick must not navigate away from the record this\n // graph is illustrating — the inspector already hides the navigate\n // button for the same reason.\n if (this.IsFocalNode(node)) {\n return;\n }\n const rawId = this.stripCategoryPrefix(String(node.Data?.['ID'] || node.ID));\n const entityName = String(node.Data?.['EntityName'] || (node.Category === 'person' ? 'MJ_BizApps_Common: People' : 'MJ_BizApps_Common: Organizations'));\n const beforeEvent = new BeforeNodeNavigateEventArgs(node, entityName, rawId);\n this.BeforeNodeNavigate.emit(beforeEvent);\n if (beforeEvent.Cancel) return;\n\n // Hosts navigate. This widget is L1 and must not import Explorer's\n // NavigationService — emit the intent and let the surface open the record.\n this.NodeNavigated.emit(new NodeNavigatedEventArgs(node, entityName, rawId));\n }\n\n // ── Mouse Drag & Pan Handlers ─────────────────────────────────────\n public OnCanvasMouseDown(event: MouseEvent): void {\n if (event.target === this.CanvasRef.nativeElement || (event.target as HTMLElement).tagName === 'svg') {\n this.IsPanning = true;\n this.panStartX = event.clientX - this.PanX;\n this.panStartY = event.clientY - this.PanY;\n }\n }\n\n public OnCanvasMouseMove(event: MouseEvent): void {\n if (this.IsPanning) {\n this.PanX = event.clientX - this.panStartX;\n this.PanY = event.clientY - this.panStartY;\n this.EmitViewport();\n this.cdr.markForCheck();\n } else if (this.draggedNode) {\n const coords = this.GetCanvasRelativeCoords(event);\n this.draggedNode.fx = coords.x;\n this.draggedNode.fy = coords.y;\n this.draggedNode.x = coords.x;\n this.draggedNode.y = coords.y;\n this.draggedNode.X = coords.x;\n this.draggedNode.Y = coords.y;\n this.cdr.markForCheck();\n }\n }\n\n public OnCanvasMouseUp(_event: MouseEvent): void {\n this.IsPanning = false;\n if (this.draggedNode) {\n this.draggedNode.fx = null;\n this.draggedNode.fy = null;\n this.draggedNode = null;\n if (this.simulation) {\n this.simulation.alphaTarget(0);\n }\n }\n }\n\n public OnCanvasWheel(event: WheelEvent): void {\n event.preventDefault();\n const delta = event.deltaY > 0 ? 0.9 : 1.1;\n this.Scale = Math.min(Math.max(this.Scale * delta, 0.3), 3.0);\n this.EmitViewport();\n this.cdr.markForCheck();\n }\n\n public OnNodeMouseDown(node: GraphNode, event: MouseEvent): void {\n event.stopPropagation();\n this.draggedNode = node;\n node.fx = node.x ?? node.X;\n node.fy = node.y ?? node.Y;\n if (this.simulation) {\n this.simulation.alphaTarget(0.3).restart();\n }\n }\n\n private EmitViewport(): void {\n this.ViewportTransform.emit(new ViewportTransformEventArgs({ Scale: this.Scale, PanX: this.PanX, PanY: this.PanY }));\n this.cdr.markForCheck();\n }\n\n private GetCanvasRelativeCoords(event: MouseEvent): { x: number; y: number } {\n const canvas = this.CanvasRef?.nativeElement;\n if (!canvas) {\n return {\n x: (event.clientX - this.PanX) / this.Scale,\n y: (event.clientY - this.PanY) / this.Scale\n };\n }\n const rect = canvas.getBoundingClientRect();\n const mouseX = event.clientX - rect.left;\n const mouseY = event.clientY - rect.top;\n return {\n x: (mouseX - this.PanX) / this.Scale,\n y: (mouseY - this.PanY) / this.Scale\n };\n }\n\n private GetContainerWidth(): number {\n return this.CanvasRef?.nativeElement?.clientWidth || this.WrapperRef?.nativeElement?.clientWidth || 800;\n }\n\n private GetContainerHeight(): number {\n return this.CanvasRef?.nativeElement?.clientHeight || this.WrapperRef?.nativeElement?.clientHeight || 420;\n }\n\n // ── Helpers ───────────────────────────────────────────────────────\n public ApplyFilters(): void {\n const q = this.SearchQuery.trim().toLowerCase();\n this.FilteredNodes = this.Nodes.filter(n => {\n return !q || n.Label.toLowerCase().includes(q) || (n.Sublabel && n.Sublabel.toLowerCase().includes(q));\n });\n this.cdr.markForCheck();\n }\n\n public GetNodeX(id: string): number {\n const node = this.Nodes.find(n => UUIDsEqual(n.ID, id));\n return node ? (node.X ?? node.x ?? 0) : 0;\n }\n\n public GetNodeY(id: string): number {\n const node = this.Nodes.find(n => UUIDsEqual(n.ID, id));\n return node ? (node.Y ?? node.y ?? 0) : 0;\n }\n\n public GetCategoryConfig(category?: string): GraphCategoryConfig {\n const key = String(category || '').toLowerCase();\n const found = this.Categories?.find(c => c.Category.toLowerCase() === key);\n if (found) return found;\n\n const builtin = DEFAULT_GRAPH_CATEGORIES.find(c => c.Category.toLowerCase() === key);\n if (builtin) return builtin;\n\n // Deterministic palette hash for arbitrary consumer-defined categories\n const hash = Math.abs(key.split('').reduce((acc, ch) => ((acc << 5) - acc) + ch.charCodeAt(0), 0));\n const fallbackColor = DYNAMIC_CATEGORY_PALETTE[hash % DYNAMIC_CATEGORY_PALETTE.length];\n const formattedLabel = category ? category.charAt(0).toUpperCase() + category.slice(1) : 'Item';\n return {\n Category: category || 'custom',\n Label: formattedLabel,\n Color: fallbackColor,\n IconClass: 'fa-solid fa-circle-dot'\n };\n }\n\n public get ActiveCategories(): GraphCategoryConfig[] {\n const present = new Set<string>();\n for (const n of this.Nodes) {\n if (n.Category) present.add(n.Category.toLowerCase());\n }\n const result: GraphCategoryConfig[] = [];\n for (const catKey of present) {\n result.push(this.GetCategoryConfig(catKey));\n }\n return result;\n }\n\n public GetCategoryLabel(category?: string): string {\n return this.GetCategoryConfig(category).Label;\n }\n\n public GetNodeColor(node: GraphNode): string {\n return node.Color ?? this.GetCategoryConfig(node.Category).Color;\n }\n\n public GetNodeIcon(node: GraphNode): string {\n return node.IconClass ?? this.GetCategoryConfig(node.Category).IconClass ?? 'fa-solid fa-circle-dot';\n }\n\n public GetNodeEdgeCount(id: string): number {\n return this.Edges.filter(e => UUIDsEqual(e.SourceID, id) || UUIDsEqual(e.TargetID, id)).length;\n }\n\n public IsEdgeHighlighted(edge: GraphEdge): boolean {\n return UUIDsEqual(this.SelectedEdge?.ID, edge.ID) ||\n UUIDsEqual(this.SelectedNode?.ID, edge.SourceID) ||\n UUIDsEqual(this.SelectedNode?.ID, edge.TargetID);\n }\n\n /**\n * Whether this node is the selected one. Exists as a method because the template cannot call\n * an imported function directly, and the comparison must go through UUIDsEqual rather than ===.\n */\n public IsNodeSelected(node: GraphNode): boolean {\n return UUIDsEqual(this.SelectedNode?.ID, node.ID);\n }\n\n public TruncateLabel(text: string, maxLen: number): string {\n if (!text) return '';\n return text.length > maxLen ? text.substring(0, maxLen - 1) + '…' : text;\n }\n\n public IsFocalNode(node: GraphNode): boolean {\n if (!node || !this.FocalNodeId) return false;\n const focalClean = this.stripCategoryPrefix(this.FocalNodeId).toLowerCase();\n const nodeClean = this.stripCategoryPrefix(node.ID).toLowerCase();\n const dataClean = node.Data?.['ID'] ? String(node.Data['ID']).toLowerCase() : '';\n return UUIDsEqual(node.ID, this.FocalNodeId) || nodeClean === focalClean || dataClean === focalClean;\n }\n\n /**\n * Hosts prefix node IDs with `{category}:`. Categories are dynamic\n * (`organization`, `asset`, `group`, plus caller keys), so strip any\n * known-category prefix rather than a hardcoded subset.\n */\n private stripCategoryPrefix(id: string): string {\n const idx = id.indexOf(':');\n if (idx <= 0) {\n return id;\n }\n const prefix = id.slice(0, idx).toLowerCase();\n const known =\n this.Categories?.some(c => c.Category.toLowerCase() === prefix) ||\n DEFAULT_GRAPH_CATEGORIES.some(c => c.Category.toLowerCase() === prefix);\n return known ? id.slice(idx + 1) : id;\n }\n}\n"]}
1
+ {"version":3,"file":"graph-view.component.js","sourceRoot":"","sources":["../../../src/lib/components/graph-view.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit,\n OnChanges,\n OnDestroy,\n SimpleChanges,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n ElementRef,\n ViewChild,\n inject\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { NormalizeUUID, UUIDsEqual } from '@memberjunction/global';\nimport * as d3 from 'd3';\nimport type {\n GraphNode,\n GraphEdge,\n GraphLayoutMode,\n GraphNodeCategory,\n GraphCategoryConfig,\n GraphViewportTransform,\n GraphPhysicsConfig\n} from '../models/graph-models';\nimport {\n BeforeNodeSelectEventArgs,\n NodeSelectedEventArgs,\n BeforeEdgeSelectEventArgs,\n EdgeSelectedEventArgs,\n BeforeHopExpandEventArgs,\n HopExpandedEventArgs,\n BeforeLayoutChangeEventArgs,\n LayoutChangedEventArgs,\n BeforeNodeNavigateEventArgs,\n NodeNavigatedEventArgs,\n ViewportTransformEventArgs\n} from '../events/graph-events';\n\nexport const DEFAULT_GRAPH_CATEGORIES: GraphCategoryConfig[] = [\n { Category: 'person', Label: 'Person', Color: '#10b981', IconClass: 'fa-solid fa-user' },\n { Category: 'organization', Label: 'Organization', Color: '#38bdf8', IconClass: 'fa-solid fa-building' },\n { Category: 'committee', Label: 'Committee', Color: '#8b5cf6', IconClass: 'fa-solid fa-landmark' },\n { Category: 'account', Label: 'Holding / Account', Color: '#f59e0b', IconClass: 'fa-solid fa-building-flag' },\n { Category: 'asset', Label: 'Asset', Color: '#ec4899', IconClass: 'fa-solid fa-gem' },\n { Category: 'group', Label: 'Group', Color: '#06b6d4', IconClass: 'fa-solid fa-users' },\n { Category: 'custom', Label: 'Custom', Color: '#64748b', IconClass: 'fa-solid fa-circle-nodes' }\n];\n\nconst DYNAMIC_CATEGORY_PALETTE = [\n '#10b981', '#38bdf8', '#8b5cf6', '#f59e0b', '#ec4899',\n '#06b6d4', '#84cc16', '#f43f5e', '#a855f7', '#14b8a6'\n];\n\nconst GRAPH_VIEW_CSS = `\n:host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n background: var(--mj-bg-surface-sunken, #0b1220);\n border-radius: var(--mj-radius-lg, 12px);\n border: 1px solid var(--mj-border-default, #223254);\n user-select: none;\n}\n\n.mj-graph-wrapper {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.mj-graph-svg-canvas {\n width: 100%;\n height: 100%;\n cursor: grab;\n}\n\n.mj-graph-svg-canvas.is-panning {\n cursor: grabbing;\n}\n\n/* Floating Toolbar */\n.mj-graph-toolbar {\n position: absolute;\n top: 14px;\n left: 14px;\n z-index: 20;\n display: flex;\n align-items: center;\n gap: 8px;\n background: rgba(20, 31, 54, 0.88);\n backdrop-filter: blur(10px);\n border: 1px solid var(--mj-border-default, #223254);\n padding: 6px 12px;\n border-radius: var(--mj-radius-lg, 10px);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);\n}\n\n.mj-graph-tool-btn {\n background: var(--mj-bg-surface-elevated, #1a2744);\n border: 1px solid var(--mj-border-default, #223254);\n color: var(--mj-text-primary, #f8fafc);\n border-radius: 6px;\n padding: 5px 10px;\n font-size: 11.5px;\n font-weight: 600;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.15s ease;\n}\n\n.mj-graph-tool-btn:hover {\n border-color: var(--mj-brand-primary, #38bdf8);\n background: var(--mj-border-hover, #334876);\n}\n\n.mj-graph-tool-btn.active {\n background: var(--mj-brand-primary, #38bdf8);\n color: #090e1a;\n border-color: var(--mj-brand-primary, #38bdf8);\n}\n\n.mj-graph-separator {\n width: 1px;\n height: 18px;\n background: var(--mj-border-default, #223254);\n}\n\n.mj-graph-search-input {\n background: var(--mj-bg-surface-sunken, #090e1a);\n border: 1px solid var(--mj-border-default, #223254);\n border-radius: 6px;\n color: var(--mj-text-primary, #f8fafc);\n padding: 4px 8px 4px 24px;\n font-size: 11.5px;\n width: 150px;\n}\n\n.mj-graph-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary, #38bdf8);\n width: 190px;\n}\n\n/* Floating Legend */\n.mj-graph-legend {\n position: absolute;\n bottom: 14px;\n left: 14px;\n z-index: 20;\n display: flex;\n align-items: center;\n gap: 12px;\n background: rgba(20, 31, 54, 0.88);\n backdrop-filter: blur(10px);\n border: 1px solid var(--mj-border-default, #223254);\n padding: 6px 14px;\n border-radius: var(--mj-radius-lg, 10px);\n font-size: 11.5px;\n color: var(--mj-text-secondary, #94a3b8);\n}\n\n.mj-graph-legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.mj-graph-legend-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n}\n\n/* Inspector Drawer */\n.mj-graph-inspector {\n position: absolute;\n top: 14px;\n right: 14px;\n width: 300px;\n max-height: calc(100% - 28px);\n background: rgba(20, 31, 54, 0.95);\n backdrop-filter: blur(14px);\n border: 1px solid var(--mj-border-default, #223254);\n border-radius: var(--mj-radius-lg, 12px);\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n z-index: 25;\n box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);\n overflow-y: auto;\n scrollbar-width: thin;\n animation: mjGraphSlide 0.2s ease;\n}\n\n.mj-graph-inspector-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.mj-graph-inspector-title {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--mj-text-muted, #64748b);\n}\n\n.mj-graph-inspector-close {\n background: none;\n border: none;\n color: var(--mj-text-muted, #64748b);\n cursor: pointer;\n font-size: 14px;\n}\n\n.mj-graph-inspector-card {\n display: flex;\n align-items: center;\n gap: 12px;\n background: var(--mj-bg-surface, #111a2e);\n border: 1px solid var(--mj-border-default, #223254);\n border-radius: 8px;\n padding: 10px 12px;\n}\n\n.mj-graph-inspector-avatar {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n color: #fff;\n flex-shrink: 0;\n}\n\n.mj-graph-inspector-actions {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-top: 4px;\n}\n\n/* SVG Rendering Elements */\n.mj-edge-path {\n stroke: var(--mj-border-hover, #2d416b);\n stroke-width: 2;\n fill: none;\n transition: stroke 0.2s ease;\n}\n\n.mj-edge-path.is-highlighted {\n stroke: var(--mj-brand-primary, #38bdf8);\n stroke-width: 3;\n}\n\n.mj-edge-text {\n font-size: 10px;\n font-weight: 500;\n fill: var(--mj-text-muted, #64748b);\n text-anchor: middle;\n pointer-events: none;\n paint-order: stroke;\n stroke: var(--mj-bg-surface-sunken, #0b1220);\n stroke-width: 3px;\n stroke-linecap: butt;\n stroke-linejoin: miter;\n}\n\n.mj-node-group {\n cursor: pointer;\n transition: transform 0.1s ease;\n}\n\n.mj-node-group:hover .mj-node-circle {\n filter: drop-shadow(0 0 10px var(--mj-brand-primary, #38bdf8));\n}\n\n.mj-node-circle {\n transition: all 0.2s ease;\n}\n\n.mj-node-label {\n font-size: 11px;\n font-weight: 700;\n fill: var(--mj-text-primary, #f8fafc);\n text-anchor: middle;\n pointer-events: none;\n}\n\n.mj-node-sublabel {\n font-size: 9.5px;\n font-weight: 500;\n fill: var(--mj-text-secondary, #94a3b8);\n text-anchor: middle;\n pointer-events: none;\n}\n\n@keyframes mjGraphSlide {\n from { opacity: 0; transform: translateX(20px); }\n to { opacity: 1; transform: translateX(0); }\n}\n`;\n\n/**\n * `<mj-graph-view>` — Interactive network and entity relationship graph visualization.\n *\n * Supports force-directed dynamic layout, multi-category entity badges, hop-expansion,\n * zoom/pan controls, inspector drawer, search filters, and cancelable Before/After event pairs.\n */\n@Component({\n selector: 'mj-graph-view',\n standalone: true,\n imports: [CommonModule, FormsModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"mj-graph-wrapper\" #wrapper>\n <!-- 1. Floating Action Toolbar -->\n @if (ShowToolbar) {\n <div class=\"mj-graph-toolbar\">\n <span style=\"font-size: 12px; font-weight: 700; color: #fff; display: flex; align-items: center; gap: 6px;\">\n <i class=\"fa-solid fa-circle-nodes\" style=\"color: var(--mj-brand-primary);\"></i>\n Network Graph\n </span>\n\n <div class=\"mj-graph-separator\"></div>\n\n <!-- Layout Mode Selector -->\n <button\n type=\"button\"\n class=\"mj-graph-tool-btn\"\n [class.active]=\"LayoutMode === 'force'\"\n (click)=\"SetLayoutMode('force')\"\n title=\"Force-Directed Physics\">\n <i class=\"fa-solid fa-atom\"></i> Force\n </button>\n <button\n type=\"button\"\n class=\"mj-graph-tool-btn\"\n [class.active]=\"LayoutMode === 'circular'\"\n (click)=\"SetLayoutMode('circular')\"\n title=\"Circular Layout\">\n <i class=\"fa-solid fa-circle-notch\"></i> Circular\n </button>\n\n <div class=\"mj-graph-separator\"></div>\n\n <!-- Zoom Controls -->\n <button type=\"button\" class=\"mj-graph-tool-btn\" (click)=\"ZoomIn()\" title=\"Zoom In\">\n <i class=\"fa-solid fa-magnifying-glass-plus\"></i>\n </button>\n <button type=\"button\" class=\"mj-graph-tool-btn\" (click)=\"ZoomOut()\" title=\"Zoom Out\">\n <i class=\"fa-solid fa-magnifying-glass-minus\"></i>\n </button>\n <button type=\"button\" class=\"mj-graph-tool-btn\" (click)=\"FitToView()\" title=\"Fit View\">\n <i class=\"fa-solid fa-expand\"></i>\n </button>\n <button type=\"button\" class=\"mj-graph-tool-btn\" (click)=\"Rearrange()\" title=\"Re-simulate Physics\">\n <i class=\"fa-solid fa-arrows-rotate\"></i>\n </button>\n\n @if (Searchable) {\n <div class=\"mj-graph-separator\"></div>\n <div style=\"position: relative;\">\n <i class=\"fa-solid fa-magnifying-glass\" style=\"position: absolute; left: 8px; top: 50%; transform: translateY(-50%); font-size: 10px; color: var(--mj-text-muted);\"></i>\n <input\n class=\"mj-graph-search-input\"\n [(ngModel)]=\"SearchQuery\"\n (ngModelChange)=\"SearchNodes($event)\"\n placeholder=\"Search graph nodes...\" />\n </div>\n }\n </div>\n }\n\n <!-- 2. Floating Dynamic Category Legend -->\n @if (ShowLegend && ActiveCategories.length > 0) {\n <div class=\"mj-graph-legend\">\n @for (cat of ActiveCategories; track cat.Category) {\n <div class=\"mj-graph-legend-item\">\n <div class=\"mj-graph-legend-dot\" [style.background]=\"cat.Color\"></div>\n {{ cat.Label }}\n </div>\n }\n </div>\n }\n\n <!-- 3. Selected Node Inspector Drawer -->\n @if (ShowInspector && SelectedNode) {\n <div class=\"mj-graph-inspector\">\n <div class=\"mj-graph-inspector-header\">\n <span class=\"mj-graph-inspector-title\">Node Inspector</span>\n <button class=\"mj-graph-inspector-close\" type=\"button\" (click)=\"ClearSelection()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <div class=\"mj-graph-inspector-card\">\n <div class=\"mj-graph-inspector-avatar\" [style.background]=\"GetNodeColor(SelectedNode)\">\n <i [class]=\"GetNodeIcon(SelectedNode)\"></i>\n </div>\n <div style=\"overflow: hidden; flex: 1;\">\n <div style=\"font-size: 13px; font-weight: 700; color: #fff; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;\">\n {{ SelectedNode.Label }}\n </div>\n <div style=\"display: flex; align-items: center; gap: 6px; margin-top: 3px;\">\n <span style=\"font-size: 11px; color: var(--mj-text-secondary);\">\n {{ SelectedNode.Sublabel || SelectedNode.Category }}\n </span>\n @if (IsFocalNode(SelectedNode)) {\n <span style=\"font-size: 10px; padding: 1px 6px; border-radius: 9999px; background: rgba(56, 189, 248, 0.15); color: #38bdf8; font-weight: 600; border: 1px solid rgba(56, 189, 248, 0.3);\">Current Record</span>\n }\n </div>\n </div>\n </div>\n\n <div style=\"font-size: 11.5px; color: var(--mj-text-secondary); line-height: 1.45;\">\n Direct Connected Edges: <strong>{{ GetNodeEdgeCount(SelectedNode.ID) }}</strong>\n </div>\n\n <div class=\"mj-graph-inspector-actions\">\n @if (!IsFocalNode(SelectedNode)) {\n <button\n type=\"button\"\n class=\"mj-graph-tool-btn active\"\n style=\"justify-content: center; width: 100%;\"\n (click)=\"NavigateToEntity(SelectedNode)\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Open Entity Form\n </button>\n }\n <button\n type=\"button\"\n class=\"mj-graph-tool-btn\"\n style=\"justify-content: center; width: 100%;\"\n (click)=\"ExpandHops(SelectedNode.ID, 1)\">\n <i class=\"fa-solid fa-circle-nodes\"></i> Expand 1-Hop Neighbors\n </button>\n </div>\n </div>\n }\n\n <!-- 4. Interactive SVG Graph Canvas -->\n <svg\n #svgCanvas\n class=\"mj-graph-svg-canvas\"\n [class.is-panning]=\"IsPanning\"\n (mousedown)=\"OnCanvasMouseDown($event)\"\n (mousemove)=\"OnCanvasMouseMove($event)\"\n (mouseup)=\"OnCanvasMouseUp($event)\"\n (mouseleave)=\"OnCanvasMouseUp($event)\"\n (wheel)=\"OnCanvasWheel($event)\">\n\n <g [attr.transform]=\"'translate(' + PanX + ',' + PanY + ') scale(' + Scale + ')'\">\n <!-- Edges Layer -->\n @for (edge of Edges; track edge.ID) {\n <g>\n <line\n class=\"mj-edge-path\"\n [class.is-highlighted]=\"IsEdgeHighlighted(edge)\"\n [attr.x1]=\"GetNodeX(edge.SourceID)\"\n [attr.y1]=\"GetNodeY(edge.SourceID)\"\n [attr.x2]=\"GetNodeX(edge.TargetID)\"\n [attr.y2]=\"GetNodeY(edge.TargetID)\"\n (click)=\"OnEdgeClick(edge, $event)\">\n </line>\n <text\n class=\"mj-edge-text\"\n [attr.x]=\"(GetNodeX(edge.SourceID) + GetNodeX(edge.TargetID)) / 2\"\n [attr.y]=\"(GetNodeY(edge.SourceID) + GetNodeY(edge.TargetID)) / 2 - 4\">\n {{ edge.Label }}\n </text>\n </g>\n }\n\n <!-- Nodes Layer -->\n @for (node of FilteredNodes; track node.ID) {\n <g\n class=\"mj-node-group\"\n [attr.transform]=\"'translate(' + (node.X || 0) + ',' + (node.Y || 0) + ')'\"\n (mousedown)=\"OnNodeMouseDown(node, $event)\"\n (click)=\"OnNodeClick(node, $event)\"\n (dblclick)=\"NavigateToEntity(node)\">\n\n <!-- Outer Selection / Focal Halo -->\n @if (IsNodeSelected(node)) {\n <circle r=\"36\" fill=\"rgba(56, 189, 248, 0.2)\" stroke=\"#38bdf8\" stroke-width=\"2\"></circle>\n } @else if (IsFocalNode(node)) {\n <circle r=\"34\" fill=\"none\" stroke=\"rgba(56, 189, 248, 0.45)\" stroke-width=\"2\" stroke-dasharray=\"4 3\"></circle>\n }\n\n <!-- Node Body Circle -->\n <circle\n class=\"mj-node-circle\"\n [attr.r]=\"node.Radius || 26\"\n fill=\"#141f36\"\n [attr.stroke]=\"GetNodeColor(node)\"\n stroke-width=\"3\">\n </circle>\n\n <!-- Node Icon Center -->\n <circle [attr.r]=\"(node.Radius || 26) - 8\" [attr.fill]=\"GetNodeColor(node)\"></circle>\n\n <!-- Labels -->\n <text class=\"mj-node-label\" [attr.y]=\"(node.Radius || 26) + 16\">\n {{ TruncateLabel(node.Label, 18) }}\n </text>\n @if (node.Sublabel) {\n <text class=\"mj-node-sublabel\" [attr.y]=\"(node.Radius || 26) + 28\">\n {{ TruncateLabel(node.Sublabel, 20) }}\n </text>\n }\n </g>\n }\n </g>\n </svg>\n </div>\n `,\n styles: [GRAPH_VIEW_CSS]\n})\nexport class GraphViewComponent implements OnInit, OnChanges, OnDestroy {\n private cdr = inject(ChangeDetectorRef);\n\n @ViewChild('wrapper', { static: true }) public WrapperRef!: ElementRef<HTMLDivElement>;\n @ViewChild('svgCanvas', { static: true }) public CanvasRef!: ElementRef<SVGSVGElement>;\n\n // ── Inputs ────────────────────────────────────────────────────────\n @Input() public Nodes: GraphNode[] = [];\n @Input() public Edges: GraphEdge[] = [];\n @Input() public Categories: GraphCategoryConfig[] = DEFAULT_GRAPH_CATEGORIES;\n @Input() public LayoutMode: GraphLayoutMode = 'force';\n @Input() public MaxHopDistance = 2;\n @Input() public SelectedNodeId?: string;\n @Input() public FocalNodeId?: string;\n @Input() public AutoOpenInspector = false;\n @Input() public ShowToolbar = true;\n @Input() public ShowLegend = true;\n @Input() public ShowInspector = true;\n @Input() public Searchable = true;\n @Input() public AutoFitOnLoad = true;\n @Input() public Physics: GraphPhysicsConfig = {\n Repulsion: -500,\n LinkDistance: 130,\n Gravity: 0.05,\n Damping: 0.88,\n MaxIterations: 200\n };\n\n // ── Cancelable Before/After Outputs ────────────────────────────────\n @Output() public BeforeNodeSelect = new EventEmitter<BeforeNodeSelectEventArgs>();\n @Output() public NodeSelected = new EventEmitter<NodeSelectedEventArgs>();\n\n @Output() public BeforeEdgeSelect = new EventEmitter<BeforeEdgeSelectEventArgs>();\n @Output() public EdgeSelected = new EventEmitter<EdgeSelectedEventArgs>();\n\n @Output() public BeforeHopExpand = new EventEmitter<BeforeHopExpandEventArgs>();\n @Output() public HopExpanded = new EventEmitter<HopExpandedEventArgs>();\n\n @Output() public BeforeLayoutChange = new EventEmitter<BeforeLayoutChangeEventArgs>();\n @Output() public LayoutChanged = new EventEmitter<LayoutChangedEventArgs>();\n\n @Output() public BeforeNodeNavigate = new EventEmitter<BeforeNodeNavigateEventArgs>();\n @Output() public NodeNavigated = new EventEmitter<NodeNavigatedEventArgs>();\n\n @Output() public ViewportTransform = new EventEmitter<ViewportTransformEventArgs>();\n\n // ── Internal State ────────────────────────────────────────────────\n public FilteredNodes: GraphNode[] = [];\n public SelectedNode: GraphNode | null = null;\n public SelectedEdge: GraphEdge | null = null;\n public SearchQuery = '';\n\n public Scale = 1.0;\n public PanX = 200;\n public PanY = 150;\n public IsPanning = false;\n private panStartX = 0;\n private panStartY = 0;\n\n private draggedNode: GraphNode | null = null;\n private simulation: d3.Simulation<GraphNode, d3.SimulationLinkDatum<GraphNode>> | null = null;\n\n public ngOnInit(): void {\n this.initializePositions();\n this.ApplyFilters();\n this.SimulatePhysics();\n }\n\n public ngOnChanges(changes: SimpleChanges): void {\n if (changes['Nodes'] || changes['Edges']) {\n this.initializePositions();\n this.ApplyFilters();\n this.SimulatePhysics();\n }\n if (changes['SelectedNodeId'] && this.SelectedNodeId) {\n const found = this.Nodes.find(n => UUIDsEqual(n.ID, this.SelectedNodeId));\n if (found && this.AutoOpenInspector) {\n this.SelectedNode = found;\n }\n }\n }\n\n public ngOnDestroy(): void {\n if (this.simulation) {\n this.simulation.stop();\n this.simulation = null;\n }\n }\n\n // ── Positioning & D3 Physics Engine ──────────────────────────────────\n private initializePositions(): void {\n const cx = this.getContainerWidth() / 2 || 400;\n const cy = this.getContainerHeight() / 2 || 250;\n const count = this.Nodes.length || 1;\n\n this.Nodes.forEach((node, idx) => {\n if (node.x === undefined || node.y === undefined) {\n if (node.X !== undefined && node.Y !== undefined) {\n node.x = node.X;\n node.y = node.Y;\n } else {\n const angle = (idx / count) * 2 * Math.PI;\n const r = 100 + Math.random() * 60;\n node.x = cx + r * Math.cos(angle);\n node.y = cy + r * Math.sin(angle);\n node.X = node.x;\n node.Y = node.y;\n }\n node.vx = 0;\n node.vy = 0;\n node.VX = 0;\n node.VY = 0;\n }\n });\n }\n\n public SimulatePhysics(): void {\n if (this.LayoutMode === 'circular') {\n this.applyCircularLayout();\n if (this.AutoFitOnLoad) {\n this.AutoFitToView();\n }\n this.cdr.markForCheck();\n return;\n }\n\n if (this.simulation) {\n this.simulation.stop();\n this.simulation = null;\n }\n\n const cx = this.getContainerWidth() / 2 || 400;\n const cy = this.getContainerHeight() / 2 || 250;\n\n // Resolve endpoints to node objects so a case-skewed UUID or dangling\n // edge cannot throw \"node not found\" out of ngOnInit. Raw-string\n // .id(d => d.ID) compared with ===, which UUIDsEqual elsewhere\n // deliberately does not.\n const nodeById = new Map<string, GraphNode>();\n for (const node of this.Nodes) {\n const key = NormalizeUUID(node.ID);\n if (key) {\n nodeById.set(key, node);\n }\n }\n const links: d3.SimulationLinkDatum<GraphNode>[] = [];\n for (const edge of this.Edges) {\n const source = nodeById.get(NormalizeUUID(edge.SourceID));\n const target = nodeById.get(NormalizeUUID(edge.TargetID));\n if (source && target) {\n links.push({ source, target });\n }\n }\n\n this.simulation = d3.forceSimulation<GraphNode>(this.Nodes)\n .force('link', d3.forceLink<GraphNode, d3.SimulationLinkDatum<GraphNode>>(links)\n .distance(this.Physics.LinkDistance || 120))\n .force('charge', d3.forceManyBody<GraphNode>()\n .strength(this.Physics.Repulsion || -450)\n .distanceMax(700))\n .force('collide', d3.forceCollide<GraphNode>((d: GraphNode) => (d.Radius || 26) + 16).iterations(2))\n .force('center', d3.forceCenter<GraphNode>(cx, cy));\n\n // Headless Pre-Warming: run 80 ticks synchronously in memory so the SVG renders resting immediately\n this.simulation.stop();\n for (let i = 0; i < 90; ++i) {\n this.simulation.tick();\n }\n\n this.syncCoordinates();\n\n // Auto-center & fit into view\n if (this.AutoFitOnLoad) {\n this.AutoFitToView();\n }\n\n // Attach live tick handler for interactive drag & drop\n this.simulation.on('tick', () => {\n this.syncCoordinates();\n this.cdr.markForCheck();\n });\n\n this.cdr.markForCheck();\n }\n\n private syncCoordinates(): void {\n for (const n of this.Nodes) {\n n.X = n.x;\n n.Y = n.y;\n n.VX = n.vx;\n n.VY = n.vy;\n }\n }\n\n private applyCircularLayout(): void {\n const cx = this.getContainerWidth() / 2 || 400;\n const cy = this.getContainerHeight() / 2 || 250;\n const r = Math.min(cx, cy) * 0.7 || 160;\n const count = this.Nodes.length || 1;\n\n this.Nodes.forEach((node, idx) => {\n const angle = (idx / count) * 2 * Math.PI;\n node.x = cx + r * Math.cos(angle);\n node.y = cy + r * Math.sin(angle);\n node.X = node.x;\n node.Y = node.y;\n });\n }\n\n // ── Public Programmatic Methods ───────────────────────────────────\n public ZoomIn(): void {\n this.Scale = Math.min(this.Scale * 1.2, 3.0);\n this.emitViewport();\n }\n\n public ZoomOut(): void {\n this.Scale = Math.max(this.Scale / 1.2, 0.3);\n this.emitViewport();\n }\n\n public FitToView(): void {\n this.AutoFitToView(40);\n }\n\n public AutoFitToView(padding = 40): void {\n if (!this.Nodes || this.Nodes.length === 0) return;\n\n const width = this.getContainerWidth() || 800;\n const height = this.getContainerHeight() || 420;\n\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const n of this.Nodes) {\n const nx = n.x ?? n.X ?? 0;\n const ny = n.y ?? n.Y ?? 0;\n const r = (n.Radius || 26) + 20; // include badge & labels\n if (nx - r < minX) minX = nx - r;\n if (nx + r > maxX) maxX = nx + r;\n if (ny - r < minY) minY = ny - r;\n if (ny + r > maxY) maxY = ny + r;\n }\n\n if (!isFinite(minX) || !isFinite(maxX) || !isFinite(minY) || !isFinite(maxY)) return;\n\n const bboxW = Math.max(maxX - minX, 100);\n const bboxH = Math.max(maxY - minY, 100);\n\n const scaleX = (width - padding * 2) / bboxW;\n const scaleY = (height - padding * 2) / bboxH;\n const targetScale = Math.min(Math.max(Math.min(scaleX, scaleY), 0.4), 1.25);\n\n this.Scale = targetScale;\n this.PanX = (width - (minX + maxX) * this.Scale) / 2;\n this.PanY = (height - (minY + maxY) * this.Scale) / 2;\n\n this.emitViewport();\n this.cdr.markForCheck();\n }\n\n public Rearrange(): void {\n this.initializePositions();\n this.SimulatePhysics();\n }\n\n public SetLayoutMode(mode: GraphLayoutMode): void {\n const beforeEvent = new BeforeLayoutChangeEventArgs(mode, this.LayoutMode);\n this.BeforeLayoutChange.emit(beforeEvent);\n if (beforeEvent.Cancel) return;\n\n const prev = this.LayoutMode;\n this.LayoutMode = mode;\n this.SimulatePhysics();\n this.LayoutChanged.emit(new LayoutChangedEventArgs(mode, prev));\n }\n\n public SelectNode(id: string): void {\n const node = this.Nodes.find(n => UUIDsEqual(n.ID, id));\n if (node) this.OnNodeClick(node, new MouseEvent('click'));\n }\n\n public ClearSelection(): void {\n this.SelectedNode = null;\n this.SelectedEdge = null;\n this.cdr.markForCheck();\n }\n\n public SearchNodes(query: string): void {\n this.SearchQuery = query;\n this.ApplyFilters();\n }\n\n public ExpandHops(nodeId: string, depth: number): void {\n const node = this.Nodes.find(n => UUIDsEqual(n.ID, nodeId));\n if (!node) return;\n\n const beforeEvent = new BeforeHopExpandEventArgs(node, (node.HopDistance || 0) + depth, node.HopDistance || 0);\n this.BeforeHopExpand.emit(beforeEvent);\n if (beforeEvent.Cancel) return;\n\n // Fire after event for host listener to fetch incremental relations\n this.HopExpanded.emit(new HopExpandedEventArgs(node, [], [], (node.HopDistance || 0) + depth));\n }\n\n // ── Event Handlers ────────────────────────────────────────────────\n public OnNodeClick(node: GraphNode, event: MouseEvent): void {\n event.stopPropagation();\n const beforeEvent = new BeforeNodeSelectEventArgs(node, this.SelectedNode);\n this.BeforeNodeSelect.emit(beforeEvent);\n if (beforeEvent.Cancel) return;\n\n const prev = this.SelectedNode;\n this.SelectedNode = node;\n this.SelectedEdge = null;\n this.NodeSelected.emit(new NodeSelectedEventArgs(node, prev));\n this.cdr.markForCheck();\n }\n\n public OnEdgeClick(edge: GraphEdge, event: MouseEvent): void {\n event.stopPropagation();\n const src = this.Nodes.find(n => UUIDsEqual(n.ID, edge.SourceID)) || null;\n const tgt = this.Nodes.find(n => UUIDsEqual(n.ID, edge.TargetID)) || null;\n\n const beforeEvent = new BeforeEdgeSelectEventArgs(edge, src, tgt);\n this.BeforeEdgeSelect.emit(beforeEvent);\n if (beforeEvent.Cancel) return;\n\n this.SelectedEdge = edge;\n this.EdgeSelected.emit(new EdgeSelectedEventArgs(edge, src, tgt));\n this.cdr.markForCheck();\n }\n\n public NavigateToEntity(node: GraphNode): void {\n // Focal-node dblclick must not navigate away from the record this\n // graph is illustrating — the inspector already hides the navigate\n // button for the same reason.\n if (this.IsFocalNode(node)) {\n return;\n }\n const rawId = this.stripCategoryPrefix(String(node.Data?.['ID'] || node.ID));\n const entityName = String(node.Data?.['EntityName'] || (node.Category === 'person' ? 'MJ_BizApps_Common: People' : 'MJ_BizApps_Common: Organizations'));\n const beforeEvent = new BeforeNodeNavigateEventArgs(node, entityName, rawId);\n this.BeforeNodeNavigate.emit(beforeEvent);\n if (beforeEvent.Cancel) return;\n\n // Hosts navigate. This widget is L1 and must not import Explorer's\n // NavigationService — emit the intent and let the surface open the record.\n this.NodeNavigated.emit(new NodeNavigatedEventArgs(node, entityName, rawId));\n }\n\n // ── Mouse Drag & Pan Handlers ─────────────────────────────────────\n public OnCanvasMouseDown(event: MouseEvent): void {\n if (event.target === this.CanvasRef.nativeElement || (event.target as HTMLElement).tagName === 'svg') {\n this.IsPanning = true;\n this.panStartX = event.clientX - this.PanX;\n this.panStartY = event.clientY - this.PanY;\n }\n }\n\n public OnCanvasMouseMove(event: MouseEvent): void {\n if (this.IsPanning) {\n this.PanX = event.clientX - this.panStartX;\n this.PanY = event.clientY - this.panStartY;\n this.emitViewport();\n this.cdr.markForCheck();\n } else if (this.draggedNode) {\n const coords = this.getCanvasRelativeCoords(event);\n this.draggedNode.fx = coords.x;\n this.draggedNode.fy = coords.y;\n this.draggedNode.x = coords.x;\n this.draggedNode.y = coords.y;\n this.draggedNode.X = coords.x;\n this.draggedNode.Y = coords.y;\n this.cdr.markForCheck();\n }\n }\n\n public OnCanvasMouseUp(_event: MouseEvent): void {\n this.IsPanning = false;\n if (this.draggedNode) {\n this.draggedNode.fx = null;\n this.draggedNode.fy = null;\n this.draggedNode = null;\n if (this.simulation) {\n this.simulation.alphaTarget(0);\n }\n }\n }\n\n public OnCanvasWheel(event: WheelEvent): void {\n event.preventDefault();\n const delta = event.deltaY > 0 ? 0.9 : 1.1;\n this.Scale = Math.min(Math.max(this.Scale * delta, 0.3), 3.0);\n this.emitViewport();\n this.cdr.markForCheck();\n }\n\n public OnNodeMouseDown(node: GraphNode, event: MouseEvent): void {\n event.stopPropagation();\n this.draggedNode = node;\n node.fx = node.x ?? node.X;\n node.fy = node.y ?? node.Y;\n if (this.simulation) {\n this.simulation.alphaTarget(0.3).restart();\n }\n }\n\n private emitViewport(): void {\n this.ViewportTransform.emit(new ViewportTransformEventArgs({ Scale: this.Scale, PanX: this.PanX, PanY: this.PanY }));\n this.cdr.markForCheck();\n }\n\n private getCanvasRelativeCoords(event: MouseEvent): { x: number; y: number } {\n const canvas = this.CanvasRef?.nativeElement;\n if (!canvas) {\n return {\n x: (event.clientX - this.PanX) / this.Scale,\n y: (event.clientY - this.PanY) / this.Scale\n };\n }\n const rect = canvas.getBoundingClientRect();\n const mouseX = event.clientX - rect.left;\n const mouseY = event.clientY - rect.top;\n return {\n x: (mouseX - this.PanX) / this.Scale,\n y: (mouseY - this.PanY) / this.Scale\n };\n }\n\n private getContainerWidth(): number {\n return this.CanvasRef?.nativeElement?.clientWidth || this.WrapperRef?.nativeElement?.clientWidth || 800;\n }\n\n private getContainerHeight(): number {\n return this.CanvasRef?.nativeElement?.clientHeight || this.WrapperRef?.nativeElement?.clientHeight || 420;\n }\n\n // ── Helpers ───────────────────────────────────────────────────────\n public ApplyFilters(): void {\n const q = this.SearchQuery.trim().toLowerCase();\n this.FilteredNodes = this.Nodes.filter(n => {\n return !q || n.Label.toLowerCase().includes(q) || (n.Sublabel && n.Sublabel.toLowerCase().includes(q));\n });\n this.cdr.markForCheck();\n }\n\n public GetNodeX(id: string): number {\n const node = this.Nodes.find(n => UUIDsEqual(n.ID, id));\n return node ? (node.X ?? node.x ?? 0) : 0;\n }\n\n public GetNodeY(id: string): number {\n const node = this.Nodes.find(n => UUIDsEqual(n.ID, id));\n return node ? (node.Y ?? node.y ?? 0) : 0;\n }\n\n public GetCategoryConfig(category?: string): GraphCategoryConfig {\n const key = String(category || '').toLowerCase();\n const found = this.Categories?.find(c => c.Category.toLowerCase() === key);\n if (found) return found;\n\n const builtin = DEFAULT_GRAPH_CATEGORIES.find(c => c.Category.toLowerCase() === key);\n if (builtin) return builtin;\n\n // Deterministic palette hash for arbitrary consumer-defined categories\n const hash = Math.abs(key.split('').reduce((acc, ch) => ((acc << 5) - acc) + ch.charCodeAt(0), 0));\n const fallbackColor = DYNAMIC_CATEGORY_PALETTE[hash % DYNAMIC_CATEGORY_PALETTE.length];\n const formattedLabel = category ? category.charAt(0).toUpperCase() + category.slice(1) : 'Item';\n return {\n Category: category || 'custom',\n Label: formattedLabel,\n Color: fallbackColor,\n IconClass: 'fa-solid fa-circle-dot'\n };\n }\n\n public get ActiveCategories(): GraphCategoryConfig[] {\n const present = new Set<string>();\n for (const n of this.Nodes) {\n if (n.Category) present.add(n.Category.toLowerCase());\n }\n const result: GraphCategoryConfig[] = [];\n for (const catKey of present) {\n result.push(this.GetCategoryConfig(catKey));\n }\n return result;\n }\n\n public GetCategoryLabel(category?: string): string {\n return this.GetCategoryConfig(category).Label;\n }\n\n public GetNodeColor(node: GraphNode): string {\n return node.Color ?? this.GetCategoryConfig(node.Category).Color;\n }\n\n public GetNodeIcon(node: GraphNode): string {\n return node.IconClass ?? this.GetCategoryConfig(node.Category).IconClass ?? 'fa-solid fa-circle-dot';\n }\n\n public GetNodeEdgeCount(id: string): number {\n return this.Edges.filter(e => UUIDsEqual(e.SourceID, id) || UUIDsEqual(e.TargetID, id)).length;\n }\n\n public IsEdgeHighlighted(edge: GraphEdge): boolean {\n return UUIDsEqual(this.SelectedEdge?.ID, edge.ID) ||\n UUIDsEqual(this.SelectedNode?.ID, edge.SourceID) ||\n UUIDsEqual(this.SelectedNode?.ID, edge.TargetID);\n }\n\n /**\n * Whether this node is the selected one. Exists as a method because the template cannot call\n * an imported function directly, and the comparison must go through UUIDsEqual rather than ===.\n */\n public IsNodeSelected(node: GraphNode): boolean {\n return UUIDsEqual(this.SelectedNode?.ID, node.ID);\n }\n\n public TruncateLabel(text: string, maxLen: number): string {\n if (!text) return '';\n return text.length > maxLen ? text.substring(0, maxLen - 1) + '…' : text;\n }\n\n public IsFocalNode(node: GraphNode): boolean {\n if (!node || !this.FocalNodeId) return false;\n const focalClean = this.stripCategoryPrefix(this.FocalNodeId).toLowerCase();\n const nodeClean = this.stripCategoryPrefix(node.ID).toLowerCase();\n const dataClean = node.Data?.['ID'] ? String(node.Data['ID']).toLowerCase() : '';\n return UUIDsEqual(node.ID, this.FocalNodeId) || nodeClean === focalClean || dataClean === focalClean;\n }\n\n /**\n * Hosts prefix node IDs with `{category}:`. Categories are dynamic\n * (`organization`, `asset`, `group`, plus caller keys), so strip any\n * known-category prefix rather than a hardcoded subset.\n */\n private stripCategoryPrefix(id: string): string {\n const idx = id.indexOf(':');\n if (idx <= 0) {\n return id;\n }\n const prefix = id.slice(0, idx).toLowerCase();\n const known =\n this.Categories?.some(c => c.Category.toLowerCase() === prefix) ||\n DEFAULT_GRAPH_CATEGORIES.some(c => c.Category.toLowerCase() === prefix);\n return known ? id.slice(idx + 1) : id;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-graph-view",
3
- "version": "6.2.0-edge.0",
3
+ "version": "6.2.0-edge.2",
4
4
  "description": "MemberJunction: Generic interactive network and relationship graph viewer with force-directed physics, Before/After cancelable events, and MJ design tokens",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -28,8 +28,8 @@
28
28
  "@angular/forms": "^21.2.22"
29
29
  },
30
30
  "dependencies": {
31
- "@memberjunction/ng-ui-components": "6.2.0-edge.0",
32
- "@memberjunction/global": "6.2.0-edge.0",
31
+ "@memberjunction/ng-ui-components": "6.2.0-edge.2",
32
+ "@memberjunction/global": "6.2.0-edge.2",
33
33
  "@types/d3": "^7.4.3",
34
34
  "d3": "^7.9.0",
35
35
  "tslib": "^2.8.1",