@ngroznykh/papirus 0.9.0 → 0.9.1

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.
@@ -45,6 +45,9 @@ export declare class ConnectionManager extends EventEmitter<ConnectionEvents> {
45
45
  private sourceAnchorId;
46
46
  private hoverNodeId;
47
47
  private hoverAnchorId;
48
+ private hoverPoint;
49
+ private hoverOutlineHandle;
50
+ private hoverOutlineSide;
48
51
  private hoverDisabled;
49
52
  private reconnectPoint;
50
53
  private previewTargetAnchorId;
@@ -112,7 +115,7 @@ export declare class ConnectionManager extends EventEmitter<ConnectionEvents> {
112
115
  enableHover(): void;
113
116
  /**
114
117
  * Try to start connection from a hovered anchor point.
115
- * When attachToOutline + Shift: start from anywhere on node outline.
118
+ * When attachToOutline: drag the outline handle, or Shift+drag from the node body.
116
119
  * Otherwise: requires clicking on an anchor/port so that node drag still works.
117
120
  */
118
121
  tryStartConnectionAtPoint(event: InputEvent): boolean;
@@ -191,6 +194,13 @@ export declare class ConnectionManager extends EventEmitter<ConnectionEvents> {
191
194
  private renderAnchorHighlights;
192
195
  private drawCross;
193
196
  private getNodeAtPoint;
197
+ private startOutlineConnection;
198
+ private outlineHandleHysteresis;
199
+ private outlineConnectHandleFor;
200
+ private outlineHandleHitRadius;
201
+ private findOutlineConnectHandleAt;
202
+ private renderOutlineConnectHandle;
203
+ private clearOutlineHandleCursor;
194
204
  private updateHover;
195
205
  private getAnchorAtPoint;
196
206
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectionManager.d.ts","sourceRoot":"","sources":["../../src/core/ConnectionManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ConnectionManager.d.ts","sourceRoot":"","sources":["../../src/core/ConnectionManager.ts"],"names":[],"mappings":"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"}
package/dist/papirus.js CHANGED
@@ -1731,6 +1731,101 @@ function directionToVector(dir) {
1731
1731
  };
1732
1732
  }
1733
1733
  }
1734
+ function clamp$1(value, min, max) {
1735
+ return Math.max(min, Math.min(max, value));
1736
+ }
1737
+ function dist(a, b) {
1738
+ return Math.hypot(a.x - b.x, a.y - b.y);
1739
+ }
1740
+ function closestPointOnRectSide(bounds, side, pointer) {
1741
+ const { x, y, width, height } = bounds;
1742
+ switch (side) {
1743
+ case "top": return {
1744
+ x: clamp$1(pointer.x, x, x + width),
1745
+ y
1746
+ };
1747
+ case "bottom": return {
1748
+ x: clamp$1(pointer.x, x, x + width),
1749
+ y: y + height
1750
+ };
1751
+ case "left": return {
1752
+ x,
1753
+ y: clamp$1(pointer.y, y, y + height)
1754
+ };
1755
+ case "right": return {
1756
+ x: x + width,
1757
+ y: clamp$1(pointer.y, y, y + height)
1758
+ };
1759
+ }
1760
+ }
1761
+ function closestPointOnRectOutline(bounds, pointer) {
1762
+ const sides = [
1763
+ "top",
1764
+ "right",
1765
+ "bottom",
1766
+ "left"
1767
+ ];
1768
+ let side = sides[0];
1769
+ let point = closestPointOnRectSide(bounds, side, pointer);
1770
+ let best = dist(pointer, point);
1771
+ for (let i = 1; i < sides.length; i++) {
1772
+ const nextSide = sides[i];
1773
+ const nextPoint = closestPointOnRectSide(bounds, nextSide, pointer);
1774
+ const nextDist = dist(pointer, nextPoint);
1775
+ if (nextDist < best) {
1776
+ side = nextSide;
1777
+ point = nextPoint;
1778
+ best = nextDist;
1779
+ }
1780
+ }
1781
+ return {
1782
+ side,
1783
+ point
1784
+ };
1785
+ }
1786
+ function getOutlineConnectHandle(bounds, pointer, offset, prevSide, hysteresis = 8) {
1787
+ const closest = closestPointOnRectOutline(bounds, pointer);
1788
+ let side = closest.side;
1789
+ let attach = closest.point;
1790
+ if (prevSide && prevSide !== closest.side) {
1791
+ const stay = closestPointOnRectSide(bounds, prevSide, pointer);
1792
+ if (dist(pointer, stay) <= dist(pointer, closest.point) + hysteresis) {
1793
+ side = prevSide;
1794
+ attach = stay;
1795
+ }
1796
+ }
1797
+ if (offset === 0) return {
1798
+ side,
1799
+ attach,
1800
+ handle: attach
1801
+ };
1802
+ const delta = {
1803
+ top: {
1804
+ x: 0,
1805
+ y: -offset
1806
+ },
1807
+ right: {
1808
+ x: offset,
1809
+ y: 0
1810
+ },
1811
+ bottom: {
1812
+ x: 0,
1813
+ y: offset
1814
+ },
1815
+ left: {
1816
+ x: -offset,
1817
+ y: 0
1818
+ }
1819
+ }[side];
1820
+ return {
1821
+ side,
1822
+ attach,
1823
+ handle: {
1824
+ x: attach.x + delta.x,
1825
+ y: attach.y + delta.y
1826
+ }
1827
+ };
1828
+ }
1734
1829
  //#endregion
1735
1830
  //#region src/core/ConnectionManager.ts
1736
1831
  /**
@@ -1747,6 +1842,9 @@ var ConnectionManager = class extends EventEmitter {
1747
1842
  this.sourceAnchorId = null;
1748
1843
  this.hoverNodeId = null;
1749
1844
  this.hoverAnchorId = null;
1845
+ this.hoverPoint = null;
1846
+ this.hoverOutlineHandle = false;
1847
+ this.hoverOutlineSide = null;
1750
1848
  this.hoverDisabled = false;
1751
1849
  this.reconnectPoint = null;
1752
1850
  this.previewTargetAnchorId = null;
@@ -1808,9 +1906,12 @@ var ConnectionManager = class extends EventEmitter {
1808
1906
  */
1809
1907
  clearPointerHover() {
1810
1908
  if (this.hoverDisabled) return;
1811
- if (this.hoverNodeId !== null || this.hoverAnchorId !== null) {
1909
+ if (this.hoverNodeId !== null || this.hoverAnchorId !== null || this.hoverOutlineHandle) {
1812
1910
  this.hoverNodeId = null;
1813
1911
  this.hoverAnchorId = null;
1912
+ this.hoverPoint = null;
1913
+ this.hoverOutlineSide = null;
1914
+ this.clearOutlineHandleCursor();
1814
1915
  this.renderer.markDirty();
1815
1916
  }
1816
1917
  }
@@ -1837,9 +1938,12 @@ var ConnectionManager = class extends EventEmitter {
1837
1938
  */
1838
1939
  disableHover() {
1839
1940
  this.hoverDisabled = true;
1840
- if (this.hoverNodeId !== null || this.hoverAnchorId !== null) {
1941
+ if (this.hoverNodeId !== null || this.hoverAnchorId !== null || this.hoverOutlineHandle) {
1841
1942
  this.hoverNodeId = null;
1842
1943
  this.hoverAnchorId = null;
1944
+ this.hoverPoint = null;
1945
+ this.hoverOutlineSide = null;
1946
+ this.clearOutlineHandleCursor();
1843
1947
  this.renderer.markDirty();
1844
1948
  }
1845
1949
  }
@@ -1851,7 +1955,7 @@ var ConnectionManager = class extends EventEmitter {
1851
1955
  }
1852
1956
  /**
1853
1957
  * Try to start connection from a hovered anchor point.
1854
- * When attachToOutline + Shift: start from anywhere on node outline.
1958
+ * When attachToOutline: drag the outline handle, or Shift+drag from the node body.
1855
1959
  * Otherwise: requires clicking on an anchor/port so that node drag still works.
1856
1960
  */
1857
1961
  tryStartConnectionAtPoint(event) {
@@ -1860,18 +1964,18 @@ var ConnectionManager = class extends EventEmitter {
1860
1964
  x: event.worldX,
1861
1965
  y: event.worldY
1862
1966
  };
1967
+ if (this.attachToOutline) {
1968
+ const handleHit = this.findOutlineConnectHandleAt(point);
1969
+ if (handleHit) {
1970
+ this.startOutlineConnection(handleHit.node, handleHit.attach);
1971
+ return true;
1972
+ }
1973
+ }
1863
1974
  const node = this.getNodeAtPoint(point, false);
1864
1975
  if (!node) return false;
1865
1976
  if (this.attachToOutline && event.shiftKey) {
1866
- const { point: outlinePoint, param } = node.getClosestPointOnOutline(point);
1867
- this.sourceNode = node;
1868
- this.isConnecting = true;
1869
- this.sourceAnchorId = null;
1870
- this.sourcePoint = outlinePoint;
1871
- this.sourceOutlineParam = param;
1872
- this.previewEndpoint = point;
1873
- this.emit("connectionStart", node);
1874
- this.renderer.markDirty();
1977
+ const { point: outlinePoint } = node.getClosestPointOnOutline(point);
1978
+ this.startOutlineConnection(node, outlinePoint);
1875
1979
  return true;
1876
1980
  }
1877
1981
  const hover = this.getAnchorAtPoint(node, point);
@@ -2473,7 +2577,10 @@ var ConnectionManager = class extends EventEmitter {
2473
2577
  renderHoverAnchors(ctx) {
2474
2578
  if (this.isConnecting || this.isReconnecting) return;
2475
2579
  this.renderEditablePolylineControls(ctx);
2476
- if (this.attachToOutline) return;
2580
+ if (this.attachToOutline) {
2581
+ this.renderOutlineConnectHandle(ctx);
2582
+ return;
2583
+ }
2477
2584
  if (!this.hoverNodeId) return;
2478
2585
  const node = this.renderer.getNode(this.hoverNodeId);
2479
2586
  if (!node) return;
@@ -2488,7 +2595,7 @@ var ConnectionManager = class extends EventEmitter {
2488
2595
  ctx.beginPath();
2489
2596
  ctx.arc(anchor.point.x, anchor.point.y, radius, 0, Math.PI * 2);
2490
2597
  ctx.fill();
2491
- if (isHovered) this.drawPlus(radius, ctx, anchor);
2598
+ if (isHovered) this.drawPlus(radius, ctx, anchor.point);
2492
2599
  }
2493
2600
  ctx.restore();
2494
2601
  }
@@ -2639,15 +2746,15 @@ var ConnectionManager = class extends EventEmitter {
2639
2746
  y
2640
2747
  };
2641
2748
  }
2642
- drawPlus(radius, ctx, anchor) {
2749
+ drawPlus(radius, ctx, point) {
2643
2750
  const plusSize = radius * .5;
2644
2751
  ctx.strokeStyle = "#ffffff";
2645
2752
  ctx.lineWidth = 1.5;
2646
2753
  ctx.beginPath();
2647
- ctx.moveTo(anchor.point.x - plusSize, anchor.point.y);
2648
- ctx.lineTo(anchor.point.x + plusSize, anchor.point.y);
2649
- ctx.moveTo(anchor.point.x, anchor.point.y - plusSize);
2650
- ctx.lineTo(anchor.point.x, anchor.point.y + plusSize);
2754
+ ctx.moveTo(point.x - plusSize, point.y);
2755
+ ctx.lineTo(point.x + plusSize, point.y);
2756
+ ctx.moveTo(point.x, point.y - plusSize);
2757
+ ctx.lineTo(point.x, point.y + plusSize);
2651
2758
  ctx.stroke();
2652
2759
  }
2653
2760
  renderAnchorHighlights(ctx, point, reconnecting) {
@@ -2668,7 +2775,7 @@ var ConnectionManager = class extends EventEmitter {
2668
2775
  ctx.arc(anchor.point.x, anchor.point.y, radius, 0, Math.PI * 2);
2669
2776
  ctx.fill();
2670
2777
  if (isNearest) if (forbidden) this.drawCross(radius, ctx, anchor);
2671
- else this.drawPlus(radius, ctx, anchor);
2778
+ else this.drawPlus(radius, ctx, anchor.point);
2672
2779
  }
2673
2780
  ctx.restore();
2674
2781
  }
@@ -2693,19 +2800,94 @@ var ConnectionManager = class extends EventEmitter {
2693
2800
  }
2694
2801
  return null;
2695
2802
  }
2803
+ startOutlineConnection(node, attach) {
2804
+ const { point: outlinePoint, param } = node.getClosestPointOnOutline(attach);
2805
+ this.sourceNode = node;
2806
+ this.isConnecting = true;
2807
+ this.sourceAnchorId = null;
2808
+ this.sourcePoint = outlinePoint;
2809
+ this.sourceOutlineParam = param;
2810
+ this.previewEndpoint = attach;
2811
+ this.emit("connectionStart", node);
2812
+ this.renderer.markDirty();
2813
+ }
2814
+ outlineHandleHysteresis() {
2815
+ return 8 / Math.max(this.renderer.zoom, 1e-4);
2816
+ }
2817
+ outlineConnectHandleFor(node, pointer) {
2818
+ const prevSide = node.id === this.hoverNodeId ? this.hoverOutlineSide : null;
2819
+ const geom = getOutlineConnectHandle(node.getBounds(), pointer, 0, prevSide, this.outlineHandleHysteresis());
2820
+ const { point: onOutline } = node.getClosestPointOnOutline(geom.attach);
2821
+ return {
2822
+ attach: onOutline,
2823
+ handle: onOutline,
2824
+ side: geom.side
2825
+ };
2826
+ }
2827
+ outlineHandleHitRadius() {
2828
+ return 10 / Math.max(this.renderer.zoom, 1e-4);
2829
+ }
2830
+ findOutlineConnectHandleAt(point) {
2831
+ if (!this.attachToOutline) return null;
2832
+ const radiusSq = this.outlineHandleHitRadius() ** 2;
2833
+ const nodes = Array.from(this.renderer.nodes.values());
2834
+ for (let i = nodes.length - 1; i >= 0; i--) {
2835
+ const node = nodes[i];
2836
+ if (!node.visible || !this.isCompatibleTarget(node)) continue;
2837
+ const { attach, handle } = this.outlineConnectHandleFor(node, point);
2838
+ const dx = point.x - handle.x;
2839
+ const dy = point.y - handle.y;
2840
+ if (dx * dx + dy * dy <= radiusSq) return {
2841
+ node,
2842
+ attach,
2843
+ handle
2844
+ };
2845
+ }
2846
+ return null;
2847
+ }
2848
+ renderOutlineConnectHandle(ctx) {
2849
+ if (!this.hoverNodeId || !this.hoverPoint) return;
2850
+ const node = this.renderer.getNode(this.hoverNodeId);
2851
+ if (!node) return;
2852
+ const { handle } = this.outlineConnectHandleFor(node, this.hoverPoint);
2853
+ const radius = this.hoverOutlineHandle ? 6 : 4;
2854
+ ctx.save();
2855
+ ctx.setLineDash([]);
2856
+ ctx.fillStyle = "#3b82f6";
2857
+ ctx.beginPath();
2858
+ ctx.arc(handle.x, handle.y, radius, 0, Math.PI * 2);
2859
+ ctx.fill();
2860
+ this.drawPlus(radius, ctx, handle);
2861
+ ctx.restore();
2862
+ }
2863
+ clearOutlineHandleCursor() {
2864
+ if (this.hoverOutlineHandle) {
2865
+ this.hoverOutlineHandle = false;
2866
+ this.setCursor("");
2867
+ }
2868
+ }
2696
2869
  updateHover(point) {
2697
2870
  if (this.hoverDisabled) return;
2698
- const node = this.getNodeAtPoint(point, false);
2871
+ const handleHit = this.findOutlineConnectHandleAt(point);
2872
+ const node = handleHit?.node ?? this.getNodeAtPoint(point, false);
2699
2873
  const prevNodeId = this.hoverNodeId;
2700
2874
  const prevAnchorId = this.hoverAnchorId;
2875
+ const prevOutlineHandle = this.hoverOutlineHandle;
2876
+ this.hoverPoint = node ? point : null;
2701
2877
  if (!node) {
2702
2878
  this.hoverNodeId = null;
2703
2879
  this.hoverAnchorId = null;
2880
+ this.hoverOutlineSide = null;
2881
+ this.clearOutlineHandleCursor();
2704
2882
  } else {
2705
2883
  this.hoverNodeId = node.id;
2706
- this.hoverAnchorId = this.getAnchorAtPoint(node, point)?.id ?? null;
2884
+ this.hoverAnchorId = handleHit ? null : this.getAnchorAtPoint(node, point)?.id ?? null;
2885
+ this.hoverOutlineHandle = handleHit !== null;
2886
+ if (this.attachToOutline) this.hoverOutlineSide = this.outlineConnectHandleFor(node, point).side;
2887
+ if (this.hoverOutlineHandle) this.setCursor("crosshair");
2888
+ else if (prevOutlineHandle) this.setCursor("");
2707
2889
  }
2708
- if (prevNodeId !== this.hoverNodeId || prevAnchorId !== this.hoverAnchorId) this.renderer.markDirty();
2890
+ if (prevNodeId !== this.hoverNodeId || prevAnchorId !== this.hoverAnchorId || prevOutlineHandle !== this.hoverOutlineHandle || this.attachToOutline && node !== null) this.renderer.markDirty();
2709
2891
  }
2710
2892
  getAnchorAtPoint(node, point) {
2711
2893
  const anchorIds = !this.attachToOutline && node.ports.length > 0 ? node.getPortAnchorIds() : null;