@naniteninja/profile-comparison-lib 1.0.22 → 1.0.24

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/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, OnInit, AfterViewInit, OnChanges, EventEmitter, ElementRef, Renderer2, ChangeDetectorRef, SimpleChanges } from '@angular/core';
2
+ import { InjectionToken, OnInit, AfterViewInit, OnChanges, OnDestroy, EventEmitter, ElementRef, Renderer2, ChangeDetectorRef, NgZone, SimpleChanges } from '@angular/core';
3
+ import { SimulationNodeDatum, SimulationLinkDatum } from 'd3-force';
3
4
  import { Observable, BehaviorSubject } from 'rxjs';
4
5
  import * as i2 from '@angular/common';
5
6
  import * as i3 from '@angular/common/http';
@@ -10,7 +11,7 @@ import * as i4 from '@angular/forms';
10
11
  declare enum BackendMode {
11
12
  /** Use the real deployed backend (default). */
12
13
  Real = 0,
13
- /** Use a local mock server at localhost:3000. */
14
+ /** Use a local mock server at localhost:44101. */
14
15
  Mock = 1
15
16
  }
16
17
  declare const BACKEND_MODE_URLS: Record<BackendMode, string>;
@@ -174,7 +175,7 @@ interface IEnvironment {
174
175
  openaiApiKey: string;
175
176
  apiFaceplusKey?: string;
176
177
  apiFaceplusSecret?: string;
177
- /** Base URL for local mock server (e.g. http://localhost:3000/api). Used when backend mode is "mock". */
178
+ /** Base URL for local mock server (e.g. http://localhost:44101/api). Used when backend mode is "mock". */
178
179
  backendApiUrlMock?: string;
179
180
  /** Base URL for real deployed backend (e.g. AWS). Used when backend mode is "real". */
180
181
  backendApiUrlReal?: string;
@@ -403,12 +404,30 @@ declare class ProfileComparisonBackendService {
403
404
  static ɵprov: i0.ɵɵInjectableDeclaration<ProfileComparisonBackendService>;
404
405
  }
405
406
 
406
- declare class ProfileComparisonLibComponent implements OnInit, AfterViewInit, OnChanges {
407
+ /** Node type for the force-directed chip layout. */
408
+ interface ForceChipNode extends SimulationNodeDatum {
409
+ id: string;
410
+ label: string;
411
+ group: 'p1' | 'shared' | 'p2';
412
+ targetX?: number;
413
+ targetY?: number;
414
+ originalFx?: number;
415
+ originalFy?: number;
416
+ }
417
+ interface ForceChipLink extends SimulationLinkDatum<ForceChipNode> {
418
+ kind: 'cross' | 'intra';
419
+ strength: number;
420
+ distance: number;
421
+ similarity: number;
422
+ }
423
+ declare class ProfileComparisonLibComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy {
407
424
  private backendService;
408
425
  private renderer;
409
426
  private fileConversionService;
410
427
  private imageCompressionService;
411
428
  private cdr;
429
+ private ngZone;
430
+ private hostRef;
412
431
  private getVerboseLogging?;
413
432
  private static readonly DEFAULT_OBJECT_POSITION;
414
433
  private static readonly DEFAULT_EYE_ALIGNMENT_BIAS_PX;
@@ -510,6 +529,33 @@ declare class ProfileComparisonLibComponent implements OnInit, AfterViewInit, On
510
529
  similarity: number;
511
530
  similarityMatrixCsv: string;
512
531
  matrixData: IMatrixData | null;
532
+ private static readonly SPRING_THRESHOLD;
533
+ private static readonly CROSS_LINK_MIN_SIMILARITY;
534
+ private static readonly INTRA_GROUP_THRESHOLD;
535
+ private static readonly SHARED_PROMOTION_THRESHOLD;
536
+ private static readonly MAX_CROSS_LINKS_PER_NODE;
537
+ private static readonly MIN_CROSS_LINKS_PER_NODE;
538
+ private static readonly MAX_INTRA_LINKS_PER_NODE;
539
+ private static readonly MAX_RELEVANT_INTERESTS_PER_SIDE;
540
+ private static readonly CHIP_RADIUS;
541
+ private static readonly CHIP_COLLISION_BORDER_PADDING;
542
+ private static readonly MAX_LINK_DISTANCE;
543
+ private static readonly CANVAS_PADDING;
544
+ forceNodes: ForceChipNode[];
545
+ forceLinks: ForceChipLink[];
546
+ forceCanvasHeight: number;
547
+ chipFontSizePx: number;
548
+ chipPaddingXPx: number;
549
+ chipPaddingYPx: number;
550
+ chipLineHeight: number;
551
+ hoveredNode: ForceChipNode | null;
552
+ clickedNode: ForceChipNode | null;
553
+ draggedNode: ForceChipNode | null;
554
+ isDragging: boolean;
555
+ private simulation;
556
+ private layoutRebuildRaf;
557
+ private nodeDragBounds;
558
+ get activeNode(): ForceChipNode | null;
513
559
  /** When false, backend URL is not provided — show "Configure backend". */
514
560
  backendConfigured: boolean;
515
561
  /** The resolved backend URL computed from inputs and legacy token. */
@@ -530,11 +576,13 @@ declare class ProfileComparisonLibComponent implements OnInit, AfterViewInit, On
530
576
  shapeTextLeft: ElementRef<HTMLElement>;
531
577
  shapeTextRight: ElementRef<HTMLElement>;
532
578
  shapeTextCenter: ElementRef<HTMLElement>;
533
- constructor(backendService: ProfileComparisonBackendService, renderer: Renderer2, fileConversionService: FileConversionService, imageCompressionService: ImageCompressionService, cdr: ChangeDetectorRef, getVerboseLogging?: (() => boolean) | undefined);
579
+ chipsGrid: ElementRef<HTMLElement>;
580
+ constructor(backendService: ProfileComparisonBackendService, renderer: Renderer2, fileConversionService: FileConversionService, imageCompressionService: ImageCompressionService, cdr: ChangeDetectorRef, ngZone: NgZone, hostRef: ElementRef<HTMLElement>, getVerboseLogging?: (() => boolean) | undefined);
534
581
  private log;
535
582
  anchorSide: 'left' | 'right';
536
583
  rawLLMOutput: string;
537
584
  ngOnInit(): void;
585
+ ngOnDestroy(): void;
538
586
  ngAfterViewInit(): void;
539
587
  ngOnChanges(changes: SimpleChanges): void;
540
588
  /** Use for template: hide left/right item when it's a shared (center) item. Compares case-insensitively. */
@@ -549,7 +597,21 @@ declare class ProfileComparisonLibComponent implements OnInit, AfterViewInit, On
549
597
  private setOverlapSizeCssPx;
550
598
  waitForImagesAndInitDrag(): void;
551
599
  initDrag(): void;
600
+ private normalizeSimilarityToken;
601
+ private findLegendEntry;
602
+ private lookupSimilarity;
552
603
  private getSimilarity;
604
+ private orderBySemanticBarycenter;
605
+ private orderSharedBySemanticPull;
606
+ private canLinkNodes;
607
+ private getLinkNodeId;
608
+ private getLinkPairKey;
609
+ private selectLinksWithCaps;
610
+ private filterCenterItemsByThreshold;
611
+ private scheduleForceGraphRebuild;
612
+ onWindowResize(): void;
613
+ private buildForceGraph;
614
+ private selectTopSharedInterestsPerSide;
553
615
  private reorderInterestsByMatrix;
554
616
  onViewProfile(side: 'left' | 'right'): void;
555
617
  getPerson1UniqueInterests(): string[];
@@ -578,7 +640,40 @@ declare class ProfileComparisonLibComponent implements OnInit, AfterViewInit, On
578
640
  calculateFaceAlignment(user1Data: FaceDetectionData, user2Data: FaceDetectionData): void;
579
641
  applyDefaultAlignment(): void;
580
642
  isValidFaceData(face: IBoundingBox): boolean;
581
- static ɵfac: i0.ɵɵFactoryDeclaration<ProfileComparisonLibComponent, [null, null, null, null, null, { optional: true; }]>;
643
+ onNodeMouseEnter(node: ForceChipNode): void;
644
+ onNodeMouseLeave(node: ForceChipNode): void;
645
+ onNodeClick(node: ForceChipNode, event: MouseEvent): void;
646
+ onDocumentClick(): void;
647
+ /**
648
+ * Installs (or removes) a custom d3 force that pulls every linked node toward
649
+ * the anchor, stopping at an orbit radius scaled by similarity:
650
+ * highest-sim → MIN_ORBIT (touches anchor), lowest-sim → MAX_ORBIT.
651
+ *
652
+ * While active, the xTarget/yTarget restoring forces are muted so they don't
653
+ * fight the attraction. They are restored the moment attraction is cleared.
654
+ */
655
+ private updateAttractionForce;
656
+ isNodeConnected(node: ForceChipNode): boolean;
657
+ isLinkConnectedToActive(link: any): boolean;
658
+ /**
659
+ * Returns true if the link connects a p1 node to a p2 node (a direct left↔right match),
660
+ * as opposed to a connection involving a shared-pool chip.
661
+ */
662
+ isCrossGroupLink(link: any): boolean;
663
+ /**
664
+ * All force links sorted so secondary (shared-chip) links render first and
665
+ * primary (p1↔p2 direct match) links render last — SVG paints last-child on top.
666
+ */
667
+ get sortedForceLinks(): any[];
668
+ getLinkSourceX(link: any): number;
669
+ getLinkSourceY(link: any): number;
670
+ getLinkTargetX(link: any): number;
671
+ getLinkTargetY(link: any): number;
672
+ private findNode;
673
+ onNodeDragStart(node: ForceChipNode, event: MouseEvent | TouchEvent): void;
674
+ onDocumentDragMove(event: MouseEvent | TouchEvent): void;
675
+ onDocumentDragEnd(): void;
676
+ static ɵfac: i0.ɵɵFactoryDeclaration<ProfileComparisonLibComponent, [null, null, null, null, null, null, null, { optional: true; }]>;
582
677
  static ɵcmp: i0.ɵɵComponentDeclaration<ProfileComparisonLibComponent, "lib-profile-comparison", never, { "config": { "alias": "config"; "required": false; }; "user1File": { "alias": "user1File"; "required": false; }; "user2File": { "alias": "user2File"; "required": false; }; "backendMode": { "alias": "backendMode"; "required": false; }; "backendUrl": { "alias": "backendUrl"; "required": false; }; "fadeAllEdges": { "alias": "fadeAllEdges"; "required": false; }; "person1Name": { "alias": "person1Name"; "required": false; }; "person2Name": { "alias": "person2Name"; "required": false; }; "imageProxyPath": { "alias": "imageProxyPath"; "required": false; }; }, { "matrixDataChange": "matrixDataChange"; "rawLLMOutputChange": "rawLLMOutputChange"; "viewProfileClick": "viewProfileClick"; }, never, never, false, never>;
583
678
  }
584
679
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naniteninja/profile-comparison-lib",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^20.0.0",
6
6
  "@angular/core": "^20.0.0"