@html-graph/html-graph 8.19.0 → 8.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -152,6 +152,8 @@ declare type BezierEdgeShapeConfig = {
152
152
  readonly type?: "bezier" | undefined;
153
153
  } & BezierEdgeParams;
154
154
 
155
+ export declare const boxPortOffsetFn: PortOffsetFn;
156
+
155
157
  export declare class Canvas {
156
158
  readonly graph: Graph;
157
159
  readonly viewport: Viewport;
@@ -346,8 +348,8 @@ export declare interface DirectEdgeParams {
346
348
  readonly arrowRenderer?: ArrowRendererConfig | undefined;
347
349
  readonly hasSourceArrow?: boolean | undefined;
348
350
  readonly hasTargetArrow?: boolean | undefined;
349
- readonly sourceOffset?: number | undefined;
350
- readonly targetOffset?: number | undefined;
351
+ readonly sourceOffset?: PortOffset | undefined;
352
+ readonly targetOffset?: PortOffset | undefined;
351
353
  }
352
354
 
353
355
  export declare class DirectEdgeShape implements StructuredEdgeShape {
@@ -359,13 +361,14 @@ export declare class DirectEdgeShape implements StructuredEdgeShape {
359
361
  private readonly color;
360
362
  private readonly width;
361
363
  private readonly arrowLength;
362
- private readonly sourceOffset;
363
- private readonly targetOffset;
364
+ private readonly sourceOffsetFn;
365
+ private readonly targetOffsetFn;
364
366
  readonly onAfterRender: EventHandler<StructuredEdgeRenderModel>;
365
367
  private readonly afterRenderEmitter;
366
368
  private readonly arrowRenderer;
367
369
  constructor(params?: DirectEdgeParams);
368
370
  render(params: EdgeRenderParams): void;
371
+ private renderEmpty;
369
372
  }
370
373
 
371
374
  declare type DirectEdgeShapeConfig = {
@@ -851,10 +854,24 @@ export declare interface Point {
851
854
 
852
855
  export declare type PortElement = HTMLElement | SVGElement;
853
856
 
857
+ export declare type PortOffset = number | PortOffsetFn;
858
+
859
+ export declare type PortOffsetFn = (params: PortOffsetFnParams) => number;
860
+
861
+ export declare interface PortOffsetFnParams {
862
+ readonly direction: Point;
863
+ readonly radius: Radii;
864
+ }
865
+
854
866
  declare type Priority = ConstantPriority | IncrementalPriority | CustomPriority;
855
867
 
856
868
  export declare type PriorityFn = () => number;
857
869
 
870
+ export declare interface Radii {
871
+ readonly horizontal: number;
872
+ readonly vertical: number;
873
+ }
874
+
858
875
  export declare interface ScaleLimitPreprocessorParams {
859
876
  readonly minContentScale: number | null;
860
877
  readonly maxContentScale: number | null;
@@ -1191,10 +1208,7 @@ export declare interface ViewportTransformConfig {
1191
1208
  }
1192
1209
 
1193
1210
  export declare interface VirtualScrollConfig {
1194
- readonly nodeContainingRadius: {
1195
- readonly vertical: number;
1196
- readonly horizontal: number;
1197
- };
1211
+ readonly nodeContainingRadius: Radii;
1198
1212
  readonly events?: {
1199
1213
  readonly onBeforeNodeAttached?: (nodeId: Identifier) => void;
1200
1214
  readonly onAfterNodeDetached?: (nodeId: Identifier) => void;
@@ -1806,58 +1806,6 @@ class CycleCircleEdgePath {
1806
1806
  this.midpoint = absPoints[3];
1807
1807
  }
1808
1808
  }
1809
- class DirectEdgePath {
1810
- constructor(params) {
1811
- __publicField(this, "path");
1812
- __publicField(this, "midpoint");
1813
- __publicField(this, "diagonalDistance");
1814
- const {
1815
- from,
1816
- to,
1817
- sourceOffset,
1818
- targetOffset,
1819
- hasSourceArrow,
1820
- hasTargetArrow,
1821
- arrowLength
1822
- } = params;
1823
- this.midpoint = { x: (from.x + to.x) / 2, y: (from.y + to.y) / 2 };
1824
- const width = to.x - from.x;
1825
- const height = to.y - from.y;
1826
- this.diagonalDistance = Math.sqrt(width * width + height * height);
1827
- if (this.diagonalDistance === 0) {
1828
- this.path = "";
1829
- return;
1830
- }
1831
- const dir = { x: width, y: height };
1832
- const source = this.createDirectLinePoint({
1833
- offset: sourceOffset,
1834
- hasArrow: hasSourceArrow,
1835
- flip: 1,
1836
- shift: from,
1837
- arrowLength,
1838
- dir
1839
- });
1840
- const target = this.createDirectLinePoint({
1841
- offset: targetOffset,
1842
- hasArrow: hasTargetArrow,
1843
- flip: -1,
1844
- shift: to,
1845
- arrowLength,
1846
- dir
1847
- });
1848
- this.path = `M ${source.x} ${source.y} L ${target.x} ${target.y}`;
1849
- }
1850
- createDirectLinePoint(params) {
1851
- const arrowOffset = params.hasArrow ? params.arrowLength : 0;
1852
- const totalOffset = params.offset + arrowOffset;
1853
- const targetRatio = params.flip * totalOffset / this.diagonalDistance;
1854
- const { dir, shift } = params;
1855
- return {
1856
- x: dir.x * targetRatio + shift.x,
1857
- y: dir.y * targetRatio + shift.y
1858
- };
1859
- }
1860
- }
1861
1809
  const calculateDotourY = (from, to, detourDistance) => {
1862
1810
  const max = Math.max(from.y, to.y);
1863
1811
  const min = Math.min(from.y, to.y);
@@ -2005,7 +1953,7 @@ const edgeConstants = Object.freeze({
2005
1953
  smallCycleRadius: 15,
2006
1954
  curvature: 90,
2007
1955
  interactiveWidth: 10,
2008
- preOffset: 0
1956
+ portOffset: 0
2009
1957
  });
2010
1958
  const createDirectionVector = (dir) => {
2011
1959
  return { x: Math.cos(dir), y: Math.sin(dir) };
@@ -2546,6 +2494,13 @@ class VerticalEdgeShape {
2546
2494
  });
2547
2495
  }
2548
2496
  }
2497
+ const resolvePortOffsetFn = (offset) => {
2498
+ if (typeof offset === "number") {
2499
+ return () => offset;
2500
+ }
2501
+ return offset;
2502
+ };
2503
+ const defaultPortOffset = edgeConstants.portOffset;
2549
2504
  class DirectEdgeShape {
2550
2505
  constructor(params) {
2551
2506
  __publicField(this, "svg");
@@ -2559,8 +2514,8 @@ class DirectEdgeShape {
2559
2514
  __publicField(this, "color");
2560
2515
  __publicField(this, "width");
2561
2516
  __publicField(this, "arrowLength");
2562
- __publicField(this, "sourceOffset");
2563
- __publicField(this, "targetOffset");
2517
+ __publicField(this, "sourceOffsetFn");
2518
+ __publicField(this, "targetOffsetFn");
2564
2519
  __publicField(this, "onAfterRender");
2565
2520
  __publicField(this, "afterRenderEmitter");
2566
2521
  __publicField(this, "arrowRenderer");
@@ -2569,8 +2524,12 @@ class DirectEdgeShape {
2569
2524
  this.width = (params == null ? void 0 : params.width) ?? edgeConstants.width;
2570
2525
  this.arrowLength = (params == null ? void 0 : params.arrowLength) ?? edgeConstants.arrowLength;
2571
2526
  this.arrowRenderer = resolveArrowRenderer((params == null ? void 0 : params.arrowRenderer) ?? {});
2572
- this.sourceOffset = (params == null ? void 0 : params.sourceOffset) ?? edgeConstants.preOffset;
2573
- this.targetOffset = (params == null ? void 0 : params.targetOffset) ?? edgeConstants.preOffset;
2527
+ this.sourceOffsetFn = resolvePortOffsetFn(
2528
+ (params == null ? void 0 : params.sourceOffset) ?? defaultPortOffset
2529
+ );
2530
+ this.targetOffsetFn = resolvePortOffsetFn(
2531
+ (params == null ? void 0 : params.targetOffset) ?? defaultPortOffset
2532
+ );
2574
2533
  this.svg = createEdgeSvg(this.color);
2575
2534
  this.svg.appendChild(this.group);
2576
2535
  this.line = createEdgePath(this.width);
@@ -2591,68 +2550,118 @@ class DirectEdgeShape {
2591
2550
  svgPadding
2592
2551
  );
2593
2552
  setSvgRectangle(this.svg, { x, y, width, height });
2594
- const edgePath = new DirectEdgePath({
2595
- from,
2596
- to,
2597
- sourceOffset: this.sourceOffset,
2598
- targetOffset: this.targetOffset,
2599
- hasSourceArrow: this.sourceArrow !== null,
2600
- hasTargetArrow: this.targetArrow !== null,
2601
- arrowLength: this.arrowLength
2602
- });
2603
- this.line.setAttribute("d", edgePath.path);
2604
- let sourceArrowPath = null;
2605
- let targetArrowPath = null;
2606
- const diagonal = edgePath.diagonalDistance;
2553
+ const dirX = to.x - from.x;
2554
+ const dirY = to.y - from.y;
2555
+ const diagonal = Math.sqrt(dirX * dirX + dirY * dirY);
2607
2556
  if (diagonal === 0) {
2608
- if (this.sourceArrow !== null) {
2609
- sourceArrowPath = "";
2610
- this.sourceArrow.setAttribute("d", sourceArrowPath);
2557
+ this.renderEmpty(from);
2558
+ return;
2559
+ }
2560
+ const direction = { x: dirX / diagonal, y: dirY / diagonal };
2561
+ const sourceOffset = this.sourceOffsetFn({
2562
+ direction: { x: direction.x, y: direction.y },
2563
+ radius: {
2564
+ horizontal: params.from.width / 2,
2565
+ vertical: params.from.height / 2
2611
2566
  }
2612
- if (this.targetArrow !== null) {
2613
- targetArrowPath = "";
2614
- this.targetArrow.setAttribute("d", targetArrowPath);
2567
+ });
2568
+ const targetOffset = this.targetOffsetFn({
2569
+ direction: { x: -direction.x, y: -direction.y },
2570
+ radius: {
2571
+ horizontal: params.to.width / 2,
2572
+ vertical: params.to.height / 2
2615
2573
  }
2616
- } else {
2617
- const direction = {
2618
- x: (to.x - from.x) / diagonal,
2619
- y: (to.y - from.y) / diagonal
2574
+ });
2575
+ const source = {
2576
+ x: from.x + sourceOffset * direction.x,
2577
+ y: from.y + sourceOffset * direction.y
2578
+ };
2579
+ const target = {
2580
+ x: to.x - targetOffset * direction.x,
2581
+ y: to.y - targetOffset * direction.y
2582
+ };
2583
+ const diagonalSource = this.sourceArrow !== null ? this.arrowLength : 0;
2584
+ const sourceLine = {
2585
+ x: source.x + diagonalSource * direction.x,
2586
+ y: source.y + diagonalSource * direction.y
2587
+ };
2588
+ const diagonalTarget = this.targetArrow !== null ? this.arrowLength : 0;
2589
+ const targetLine = {
2590
+ x: target.x - diagonalTarget * direction.x,
2591
+ y: target.y - diagonalTarget * direction.y
2592
+ };
2593
+ const midpoint = {
2594
+ x: (source.x + target.x) / 2,
2595
+ y: (source.y + target.y) / 2
2596
+ };
2597
+ const path = `M ${sourceLine.x} ${sourceLine.y} L ${targetLine.x} ${targetLine.y}`;
2598
+ this.line.setAttribute("d", path);
2599
+ let sourceArrowPath = null;
2600
+ let targetArrowPath = null;
2601
+ if (this.sourceArrow) {
2602
+ const sourceOffsetPoint = {
2603
+ x: direction.x * sourceOffset + from.x,
2604
+ y: direction.y * sourceOffset + from.y
2620
2605
  };
2621
- if (this.sourceArrow) {
2622
- const sourceOffset = {
2623
- x: direction.x * this.sourceOffset,
2624
- y: direction.y * this.sourceOffset
2625
- };
2626
- sourceArrowPath = this.arrowRenderer({
2627
- direction,
2628
- shift: sourceOffset,
2629
- arrowLength: this.arrowLength
2630
- });
2631
- this.sourceArrow.setAttribute("d", sourceArrowPath);
2632
- }
2633
- if (this.targetArrow) {
2634
- const targetOffset = {
2635
- x: direction.x * this.targetOffset,
2636
- y: direction.y * this.targetOffset
2637
- };
2638
- targetArrowPath = this.arrowRenderer({
2639
- direction: { x: -direction.x, y: -direction.y },
2640
- shift: {
2641
- x: to.x - targetOffset.x,
2642
- y: to.y - targetOffset.y
2643
- },
2644
- arrowLength: this.arrowLength
2645
- });
2646
- this.targetArrow.setAttribute("d", targetArrowPath);
2647
- }
2606
+ sourceArrowPath = this.arrowRenderer({
2607
+ direction,
2608
+ shift: sourceOffsetPoint,
2609
+ arrowLength: this.arrowLength
2610
+ });
2611
+ this.sourceArrow.setAttribute("d", sourceArrowPath);
2612
+ }
2613
+ if (this.targetArrow) {
2614
+ const targetOffsetPoint = {
2615
+ x: direction.x * targetOffset,
2616
+ y: direction.y * targetOffset
2617
+ };
2618
+ targetArrowPath = this.arrowRenderer({
2619
+ direction: { x: -direction.x, y: -direction.y },
2620
+ shift: {
2621
+ x: to.x - targetOffsetPoint.x,
2622
+ y: to.y - targetOffsetPoint.y
2623
+ },
2624
+ arrowLength: this.arrowLength
2625
+ });
2626
+ this.targetArrow.setAttribute("d", targetArrowPath);
2648
2627
  }
2649
2628
  this.afterRenderEmitter.emit({
2650
- edgePath,
2629
+ edgePath: { path, midpoint },
2630
+ sourceArrowPath,
2631
+ targetArrowPath
2632
+ });
2633
+ }
2634
+ renderEmpty(midpoint) {
2635
+ const emptyPath = "";
2636
+ let sourceArrowPath = null;
2637
+ let targetArrowPath = null;
2638
+ this.line.setAttribute("d", emptyPath);
2639
+ if (this.sourceArrow !== null) {
2640
+ sourceArrowPath = "";
2641
+ this.sourceArrow.setAttribute("d", sourceArrowPath);
2642
+ }
2643
+ if (this.targetArrow !== null) {
2644
+ targetArrowPath = "";
2645
+ this.targetArrow.setAttribute("d", targetArrowPath);
2646
+ }
2647
+ this.afterRenderEmitter.emit({
2648
+ edgePath: { path: emptyPath, midpoint },
2651
2649
  sourceArrowPath,
2652
2650
  targetArrowPath
2653
2651
  });
2654
2652
  }
2655
2653
  }
2654
+ const boxPortOffsetFn = (params) => {
2655
+ const { direction, radius } = params;
2656
+ const { x, y } = direction;
2657
+ const { horizontal, vertical } = radius;
2658
+ const tg = y / x;
2659
+ const horX = Math.abs(vertical / tg);
2660
+ const vertY = Math.abs(horizontal * tg);
2661
+ const minX = Math.min(horizontal, horX);
2662
+ const minY = Math.min(vertical, vertY);
2663
+ return Math.sqrt(minX * minX + minY * minY);
2664
+ };
2656
2665
  const createEdgeGroup = () => {
2657
2666
  const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
2658
2667
  group.style.pointerEvents = "auto";
@@ -7109,5 +7118,6 @@ export {
7109
7118
  InteractiveEdgeShape,
7110
7119
  MidpointEdgeShape,
7111
7120
  StraightEdgeShape,
7112
- VerticalEdgeShape
7121
+ VerticalEdgeShape,
7122
+ boxPortOffsetFn
7113
7123
  };