@excalidraw/excalidraw 0.18.0-rc.4 → 0.18.0-rc.5

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.
Files changed (46) hide show
  1. package/README.md +1 -0
  2. package/dist/dev/{chunk-3O3BNMYV.js → chunk-UGZAZPWM.js} +1143 -848
  3. package/dist/dev/chunk-UGZAZPWM.js.map +7 -0
  4. package/dist/dev/data/{image-EN763OZS.js → image-NQXTDRIN.js} +2 -2
  5. package/dist/dev/index.js +6 -8
  6. package/dist/dev/index.js.map +2 -2
  7. package/dist/prod/chunk-44FFCT2W.js +34 -0
  8. package/dist/prod/data/{image-XQM6YLGO.js → image-WYICPQ4X.js} +1 -1
  9. package/dist/prod/index.js +2 -2
  10. package/dist/types/excalidraw/actions/actionCanvas.d.ts +5 -5
  11. package/dist/types/excalidraw/actions/actionExport.d.ts +7 -7
  12. package/dist/types/excalidraw/actions/actionFrame.d.ts +1 -1
  13. package/dist/types/excalidraw/actions/actionZindex.d.ts +2 -2
  14. package/dist/types/excalidraw/appState.d.ts +8 -8
  15. package/dist/types/excalidraw/clipboard.d.ts +4 -4
  16. package/dist/types/excalidraw/constants.d.ts +1 -0
  17. package/dist/types/excalidraw/data/blob.d.ts +1 -1
  18. package/dist/types/excalidraw/element/binding.d.ts +1 -2
  19. package/dist/types/excalidraw/element/collision.d.ts +10 -1
  20. package/dist/types/excalidraw/element/distance.d.ts +3 -0
  21. package/dist/types/excalidraw/element/newElement.d.ts +1 -1
  22. package/dist/types/excalidraw/element/transformHandles.d.ts +2 -2
  23. package/dist/types/excalidraw/element/utils.d.ts +21 -0
  24. package/dist/types/excalidraw/shapes.d.ts +1 -1
  25. package/dist/types/excalidraw/utils.d.ts +3 -3
  26. package/dist/types/excalidraw/visualdebug.d.ts +7 -8
  27. package/dist/types/excalidraw/zindex.d.ts +2 -2
  28. package/dist/types/math/curve.d.ts +22 -14
  29. package/dist/types/math/ellipse.d.ts +44 -0
  30. package/dist/types/math/index.d.ts +1 -1
  31. package/dist/types/math/line.d.ts +2 -30
  32. package/dist/types/math/point.d.ts +1 -29
  33. package/dist/types/math/rectangle.d.ts +3 -0
  34. package/dist/types/math/segment.d.ts +8 -1
  35. package/dist/types/math/types.d.ts +15 -6
  36. package/dist/types/math/vector.d.ts +0 -4
  37. package/package.json +1 -1
  38. package/dist/dev/chunk-3O3BNMYV.js.map +0 -7
  39. package/dist/prod/chunk-ELWWJGPE.js +0 -34
  40. package/dist/types/math/arc.d.ts +0 -6
  41. package/dist/types/math/ga/ga.d.ts +0 -63
  42. package/dist/types/math/ga/gadirections.d.ts +0 -8
  43. package/dist/types/math/ga/galines.d.ts +0 -22
  44. package/dist/types/math/ga/gapoints.d.ts +0 -7
  45. package/dist/types/math/ga/gatransforms.d.ts +0 -10
  46. /package/dist/dev/data/{image-EN763OZS.js.map → image-NQXTDRIN.js.map} +0 -0
@@ -745,6 +745,9 @@ function vectorMagnitude(v) {
745
745
  }
746
746
  var vectorNormalize = (v) => {
747
747
  const m = vectorMagnitude(v);
748
+ if (m === 0) {
749
+ return vector(0, 0);
750
+ }
748
751
  return vector(v[0] / m, v[1] / m);
749
752
  };
750
753
 
@@ -758,15 +761,15 @@ function pointFromArray(numberArray) {
758
761
  function pointFromPair(pair) {
759
762
  return pair;
760
763
  }
761
- function pointFromVector(v) {
762
- return v;
764
+ function pointFromVector(v, offset = pointFrom(0, 0)) {
765
+ return pointFrom(offset[0] + v[0], offset[1] + v[1]);
763
766
  }
764
767
  function isPoint(p) {
765
768
  return Array.isArray(p) && p.length === 2 && typeof p[0] === "number" && !isNaN(p[0]) && typeof p[1] === "number" && !isNaN(p[1]);
766
769
  }
767
770
  function pointsEqual(a, b) {
768
- const abs2 = Math.abs;
769
- return abs2(a[0] - b[0]) < PRECISION && abs2(a[1] - b[1]) < PRECISION;
771
+ const abs = Math.abs;
772
+ return abs(a[0] - b[0]) < PRECISION && abs(a[1] - b[1]) < PRECISION;
770
773
  }
771
774
  function pointRotateRads([x, y], [cx, cy], angle) {
772
775
  return pointFrom(
@@ -793,57 +796,47 @@ var isPointWithinBounds = (p, q, r) => {
793
796
  return q[0] <= Math.max(p[0], r[0]) && q[0] >= Math.min(p[0], r[0]) && q[1] <= Math.max(p[1], r[1]) && q[1] >= Math.min(p[1], r[1]);
794
797
  };
795
798
 
796
- // ../math/curve.ts
797
- function curve(a, b, c, d) {
798
- return [a, b, c, d];
799
+ // ../math/line.ts
800
+ function line(a, b) {
801
+ return [a, b];
802
+ }
803
+ function linesIntersectAt(a, b) {
804
+ const A1 = a[1][1] - a[0][1];
805
+ const B1 = a[0][0] - a[1][0];
806
+ const A2 = b[1][1] - b[0][1];
807
+ const B2 = b[0][0] - b[1][0];
808
+ const D = A1 * B2 - A2 * B1;
809
+ if (D !== 0) {
810
+ const C1 = A1 * a[0][0] + B1 * a[0][1];
811
+ const C2 = A2 * b[0][0] + B2 * b[0][1];
812
+ return pointFrom((C1 * B2 - C2 * B1) / D, (A1 * C2 - A2 * C1) / D);
813
+ }
814
+ return null;
799
815
  }
800
816
 
801
817
  // ../math/segment.ts
802
818
  function lineSegment(a, b) {
803
819
  return [a, b];
804
820
  }
805
- var segmentsIntersectAt = (a, b) => {
806
- const a0 = vectorFromPoint(a[0]);
807
- const a1 = vectorFromPoint(a[1]);
808
- const b0 = vectorFromPoint(b[0]);
809
- const b1 = vectorFromPoint(b[1]);
810
- const r = vectorSubtract(a1, a0);
811
- const s = vectorSubtract(b1, b0);
812
- const denominator = vectorCross(r, s);
813
- if (denominator === 0) {
814
- return null;
815
- }
816
- const i = vectorSubtract(vectorFromPoint(b[0]), vectorFromPoint(a[0]));
817
- const u = vectorCross(i, r) / denominator;
818
- const t = vectorCross(i, s) / denominator;
819
- if (u === 0) {
820
- return null;
821
- }
822
- const p = vectorAdd(a0, vectorScale(r, t));
823
- if (t >= 0 && t < 1 && u >= 0 && u < 1) {
824
- return pointFromVector(p);
825
- }
826
- return null;
827
- };
828
- var pointOnLineSegment = (point2, line, threshold = PRECISION) => {
829
- const distance3 = distanceToLineSegment(point2, line);
830
- if (distance3 === 0) {
821
+ var pointOnLineSegment = (point, line2, threshold = PRECISION) => {
822
+ const distance2 = distanceToLineSegment(point, line2);
823
+ if (distance2 === 0) {
831
824
  return true;
832
825
  }
833
- return distance3 < threshold;
826
+ return distance2 < threshold;
834
827
  };
835
- var distanceToLineSegment = (point2, line) => {
836
- const [x, y] = point2;
837
- const [[x1, y1], [x2, y2]] = line;
828
+ var distanceToLineSegment = (point, line2) => {
829
+ const [x, y] = point;
830
+ const [[x1, y1], [x2, y2]] = line2;
838
831
  const A = x - x1;
839
832
  const B = y - y1;
840
833
  const C = x2 - x1;
841
834
  const D = y2 - y1;
842
- const dot2 = A * C + B * D;
835
+ const dot = A * C + B * D;
843
836
  const len_sq = C * C + D * D;
844
837
  let param = -1;
845
838
  if (len_sq !== 0) {
846
- param = dot2 / len_sq;
839
+ param = dot / len_sq;
847
840
  }
848
841
  let xx;
849
842
  let yy;
@@ -861,6 +854,179 @@ var distanceToLineSegment = (point2, line) => {
861
854
  const dy = y - yy;
862
855
  return Math.sqrt(dx * dx + dy * dy);
863
856
  };
857
+ function lineSegmentIntersectionPoints(l, s) {
858
+ const candidate = linesIntersectAt(line(l[0], l[1]), line(s[0], s[1]));
859
+ if (!candidate || !pointOnLineSegment(candidate, s) || !pointOnLineSegment(candidate, l)) {
860
+ return null;
861
+ }
862
+ return candidate;
863
+ }
864
+
865
+ // ../math/rectangle.ts
866
+ function rectangle(topLeft, bottomRight) {
867
+ return [topLeft, bottomRight];
868
+ }
869
+ function rectangleIntersectLineSegment(r, l) {
870
+ return [
871
+ lineSegment(r[0], pointFrom(r[1][0], r[0][1])),
872
+ lineSegment(pointFrom(r[1][0], r[0][1]), r[1]),
873
+ lineSegment(r[1], pointFrom(r[0][0], r[1][1])),
874
+ lineSegment(pointFrom(r[0][0], r[1][1]), r[0])
875
+ ].map((s) => lineSegmentIntersectionPoints(l, s)).filter((i) => !!i);
876
+ }
877
+
878
+ // ../math/curve.ts
879
+ function curve(a, b, c, d) {
880
+ return [a, b, c, d];
881
+ }
882
+ function gradient(f, t0, s0, delta = 1e-6) {
883
+ return [
884
+ (f(t0 + delta, s0) - f(t0 - delta, s0)) / (2 * delta),
885
+ (f(t0, s0 + delta) - f(t0, s0 - delta)) / (2 * delta)
886
+ ];
887
+ }
888
+ function solve(f, t0, s0, tolerance = 1e-3, iterLimit = 10) {
889
+ let error = Infinity;
890
+ let iter = 0;
891
+ while (error >= tolerance) {
892
+ if (iter >= iterLimit) {
893
+ return null;
894
+ }
895
+ const y0 = f(t0, s0);
896
+ const jacobian = [
897
+ gradient((t, s) => f(t, s)[0], t0, s0),
898
+ gradient((t, s) => f(t, s)[1], t0, s0)
899
+ ];
900
+ const b = [[-y0[0]], [-y0[1]]];
901
+ const det = jacobian[0][0] * jacobian[1][1] - jacobian[0][1] * jacobian[1][0];
902
+ if (det === 0) {
903
+ return null;
904
+ }
905
+ const iJ = [
906
+ [jacobian[1][1] / det, -jacobian[0][1] / det],
907
+ [-jacobian[1][0] / det, jacobian[0][0] / det]
908
+ ];
909
+ const h = [
910
+ [iJ[0][0] * b[0][0] + iJ[0][1] * b[1][0]],
911
+ [iJ[1][0] * b[0][0] + iJ[1][1] * b[1][0]]
912
+ ];
913
+ t0 = t0 + h[0][0];
914
+ s0 = s0 + h[1][0];
915
+ const [tErr, sErr] = f(t0, s0);
916
+ error = Math.max(Math.abs(tErr), Math.abs(sErr));
917
+ iter += 1;
918
+ }
919
+ return [t0, s0];
920
+ }
921
+ var bezierEquation = (c, t) => pointFrom(
922
+ (1 - t) ** 3 * c[0][0] + 3 * (1 - t) ** 2 * t * c[1][0] + 3 * (1 - t) * t ** 2 * c[2][0] + t ** 3 * c[3][0],
923
+ (1 - t) ** 3 * c[0][1] + 3 * (1 - t) ** 2 * t * c[1][1] + 3 * (1 - t) * t ** 2 * c[2][1] + t ** 3 * c[3][1]
924
+ );
925
+ function curveIntersectLineSegment(c, l) {
926
+ const bounds = curveBounds(c);
927
+ if (rectangleIntersectLineSegment(
928
+ rectangle(
929
+ pointFrom(bounds[0], bounds[1]),
930
+ pointFrom(bounds[2], bounds[3])
931
+ ),
932
+ l
933
+ ).length === 0) {
934
+ return [];
935
+ }
936
+ const line2 = (s) => pointFrom(
937
+ l[0][0] + s * (l[1][0] - l[0][0]),
938
+ l[0][1] + s * (l[1][1] - l[0][1])
939
+ );
940
+ const initial_guesses = [
941
+ [0.5, 0],
942
+ [0.2, 0],
943
+ [0.8, 0]
944
+ ];
945
+ const calculate = ([t0, s0]) => {
946
+ const solution2 = solve(
947
+ (t2, s2) => {
948
+ const bezier_point = bezierEquation(c, t2);
949
+ const line_point = line2(s2);
950
+ return [
951
+ bezier_point[0] - line_point[0],
952
+ bezier_point[1] - line_point[1]
953
+ ];
954
+ },
955
+ t0,
956
+ s0
957
+ );
958
+ if (!solution2) {
959
+ return null;
960
+ }
961
+ const [t, s] = solution2;
962
+ if (t < 0 || t > 1 || s < 0 || s > 1) {
963
+ return null;
964
+ }
965
+ return bezierEquation(c, t);
966
+ };
967
+ let solution = calculate(initial_guesses[0]);
968
+ if (solution) {
969
+ return [solution];
970
+ }
971
+ solution = calculate(initial_guesses[1]);
972
+ if (solution) {
973
+ return [solution];
974
+ }
975
+ solution = calculate(initial_guesses[2]);
976
+ if (solution) {
977
+ return [solution];
978
+ }
979
+ return [];
980
+ }
981
+ function curveClosestPoint(c, p, tolerance = 1e-3) {
982
+ const localMinimum = (min, max, f, e = tolerance) => {
983
+ let m = min;
984
+ let n = max;
985
+ let k;
986
+ while (n - m > e) {
987
+ k = (n + m) / 2;
988
+ if (f(k - e) < f(k + e)) {
989
+ n = k;
990
+ } else {
991
+ m = k;
992
+ }
993
+ }
994
+ return k;
995
+ };
996
+ const maxSteps = 30;
997
+ let closestStep = 0;
998
+ for (let min = Infinity, step = 0; step < maxSteps; step++) {
999
+ const d = pointDistance(p, bezierEquation(c, step / maxSteps));
1000
+ if (d < min) {
1001
+ min = d;
1002
+ closestStep = step;
1003
+ }
1004
+ }
1005
+ const t0 = Math.max((closestStep - 1) / maxSteps, 0);
1006
+ const t1 = Math.min((closestStep + 1) / maxSteps, 1);
1007
+ const solution = localMinimum(
1008
+ t0,
1009
+ t1,
1010
+ (t) => pointDistance(p, bezierEquation(c, t))
1011
+ );
1012
+ if (!solution) {
1013
+ return null;
1014
+ }
1015
+ return bezierEquation(c, solution);
1016
+ }
1017
+ function curvePointDistance(c, p) {
1018
+ const closest = curveClosestPoint(c, p);
1019
+ if (!closest) {
1020
+ return 0;
1021
+ }
1022
+ return pointDistance(p, closest);
1023
+ }
1024
+ function curveBounds(c) {
1025
+ const [P0, P1, P2, P3] = c;
1026
+ const x = [P0[0], P1[0], P2[0], P3[0]];
1027
+ const y = [P0[1], P1[1], P2[1], P3[1]];
1028
+ return [Math.min(...x), Math.min(...y), Math.max(...x), Math.max(...y)];
1029
+ }
864
1030
 
865
1031
  // ../math/polygon.ts
866
1032
  function polygon(...points) {
@@ -869,9 +1035,9 @@ function polygon(...points) {
869
1035
  function polygonFromPoints(points) {
870
1036
  return polygonClose(points);
871
1037
  }
872
- var polygonIncludesPoint = (point2, polygon2) => {
873
- const x = point2[0];
874
- const y = point2[1];
1038
+ var polygonIncludesPoint = (point, polygon2) => {
1039
+ const x = point[0];
1040
+ const y = point[1];
875
1041
  let inside = false;
876
1042
  for (let i = 0, j = polygon2.length - 1; i < polygon2.length; j = i++) {
877
1043
  const xi = polygon2[i][0];
@@ -1051,8 +1217,8 @@ var throttleRAF = (fn, opts) => {
1051
1217
  var easeOut = (k) => {
1052
1218
  return 1 - Math.pow(1 - k, 4);
1053
1219
  };
1054
- var easeOutInterpolate = (from3, to, progress) => {
1055
- return (to - from3) * easeOut(progress) + from3;
1220
+ var easeOutInterpolate = (from, to, progress) => {
1221
+ return (to - from) * easeOut(progress) + from;
1056
1222
  };
1057
1223
  var easeToValuesRAF = ({
1058
1224
  fromValues,
@@ -1592,9 +1758,6 @@ var isBindableElement = (element, includeLocked = true) => {
1592
1758
  var isRectanguloidElement = (element) => {
1593
1759
  return element != null && (element.type === "rectangle" || element.type === "diamond" || element.type === "image" || element.type === "iframe" || element.type === "embeddable" || element.type === "frame" || element.type === "magicframe" || element.type === "text" && !element.containerId);
1594
1760
  };
1595
- var isRectangularElement = (element) => {
1596
- return element != null && (element.type === "rectangle" || element.type === "image" || element.type === "text" || element.type === "iframe" || element.type === "embeddable" || element.type === "frame" || element.type === "magicframe" || element.type === "freedraw");
1597
- };
1598
1761
  var isTextBindableContainer = (element, includeLocked = true) => {
1599
1762
  return element != null && (!element.locked || includeLocked === true) && (element.type === "rectangle" || element.type === "diamond" || element.type === "ellipse" || isArrowElement(element));
1600
1763
  };
@@ -1745,8 +1908,8 @@ var getLineWidth = (text, font) => {
1745
1908
  var getTextWidth = (text, font) => {
1746
1909
  const lines = splitIntoLines(text);
1747
1910
  let width = 0;
1748
- lines.forEach((line) => {
1749
- width = Math.max(width, getLineWidth(line, font));
1911
+ lines.forEach((line2) => {
1912
+ width = Math.max(width, getLineWidth(line2, font));
1750
1913
  });
1751
1914
  return width;
1752
1915
  };
@@ -2030,9 +2193,9 @@ var Break = {
2030
2193
  }
2031
2194
  })
2032
2195
  };
2033
- var parseTokens = (line) => {
2196
+ var parseTokens = (line2) => {
2034
2197
  const breakLineRegex = getLineBreakRegex();
2035
- return line.normalize("NFC").split(breakLineRegex).filter(Boolean);
2198
+ return line2.normalize("NFC").split(breakLineRegex).filter(Boolean);
2036
2199
  };
2037
2200
  var wrapText = (text, font, maxWidth) => {
2038
2201
  if (!Number.isFinite(maxWidth) || maxWidth < 0) {
@@ -2051,9 +2214,9 @@ var wrapText = (text, font, maxWidth) => {
2051
2214
  }
2052
2215
  return lines.join("\n");
2053
2216
  };
2054
- var wrapLine = (line, font, maxWidth) => {
2217
+ var wrapLine = (line2, font, maxWidth) => {
2055
2218
  const lines = [];
2056
- const tokens = parseTokens(line);
2219
+ const tokens = parseTokens(line2);
2057
2220
  const tokenIterator = tokens[Symbol.iterator]();
2058
2221
  let currentLine = "";
2059
2222
  let currentLineWidth = 0;
@@ -2116,14 +2279,14 @@ var wrapWord = (word, font, maxWidth) => {
2116
2279
  }
2117
2280
  return lines;
2118
2281
  };
2119
- var trimLine = (line, font, maxWidth) => {
2120
- const shouldTrimWhitespaces = getLineWidth(line, font) > maxWidth;
2282
+ var trimLine = (line2, font, maxWidth) => {
2283
+ const shouldTrimWhitespaces = getLineWidth(line2, font) > maxWidth;
2121
2284
  if (!shouldTrimWhitespaces) {
2122
- return line;
2285
+ return line2;
2123
2286
  }
2124
- let [, trimmedLine, whitespaces] = line.match(/^(.+?)(\s+)$/) ?? [
2125
- line,
2126
- line.trimEnd(),
2287
+ let [, trimmedLine, whitespaces] = line2.match(/^(.+?)(\s+)$/) ?? [
2288
+ line2,
2289
+ line2.trimEnd(),
2127
2290
  ""
2128
2291
  ];
2129
2292
  let trimmedLineWidth = getLineWidth(trimmedLine, font);
@@ -7040,38 +7203,8 @@ var getClosedCurveShape = (element, roughShape, startingPoint = pointFrom(0, 0),
7040
7203
  data: polygonFromPoints(polygonPoints)
7041
7204
  };
7042
7205
  };
7043
- var segmentIntersectRectangleElement = (element, segment, gap = 0) => {
7044
- const bounds = [
7045
- element.x - gap,
7046
- element.y - gap,
7047
- element.x + element.width + gap,
7048
- element.y + element.height + gap
7049
- ];
7050
- const center = pointFrom(
7051
- (bounds[0] + bounds[2]) / 2,
7052
- (bounds[1] + bounds[3]) / 2
7053
- );
7054
- return [
7055
- lineSegment(
7056
- pointRotateRads(pointFrom(bounds[0], bounds[1]), center, element.angle),
7057
- pointRotateRads(pointFrom(bounds[2], bounds[1]), center, element.angle)
7058
- ),
7059
- lineSegment(
7060
- pointRotateRads(pointFrom(bounds[2], bounds[1]), center, element.angle),
7061
- pointRotateRads(pointFrom(bounds[2], bounds[3]), center, element.angle)
7062
- ),
7063
- lineSegment(
7064
- pointRotateRads(pointFrom(bounds[2], bounds[3]), center, element.angle),
7065
- pointRotateRads(pointFrom(bounds[0], bounds[3]), center, element.angle)
7066
- ),
7067
- lineSegment(
7068
- pointRotateRads(pointFrom(bounds[0], bounds[3]), center, element.angle),
7069
- pointRotateRads(pointFrom(bounds[0], bounds[1]), center, element.angle)
7070
- )
7071
- ].map((s) => segmentsIntersectAt(segment, s)).filter((i) => !!i);
7072
- };
7073
- var distanceToEllipse = (p, ellipse) => {
7074
- const { angle, halfWidth, halfHeight, center } = ellipse;
7206
+ var distanceToEllipse = (p, ellipse2) => {
7207
+ const { angle, halfWidth, halfHeight, center } = ellipse2;
7075
7208
  const a = halfWidth;
7076
7209
  const b = halfHeight;
7077
7210
  const translatedPoint = vectorAdd(
@@ -7113,11 +7246,11 @@ var distanceToEllipse = (p, ellipse) => {
7113
7246
  pointFrom(minX, minY)
7114
7247
  );
7115
7248
  };
7116
- var pointOnEllipse = (point2, ellipse, threshold = PRECISION) => {
7117
- return distanceToEllipse(point2, ellipse) <= threshold;
7249
+ var pointOnEllipse = (point, ellipse2, threshold = PRECISION) => {
7250
+ return distanceToEllipse(point, ellipse2) <= threshold;
7118
7251
  };
7119
- var pointInEllipse = (p, ellipse) => {
7120
- const { center, angle, halfWidth, halfHeight } = ellipse;
7252
+ var pointInEllipse = (p, ellipse2) => {
7253
+ const { center, angle, halfWidth, halfHeight } = ellipse2;
7121
7254
  const translatedPoint = vectorAdd(
7122
7255
  vectorFromPoint(p),
7123
7256
  vectorScale(vectorFromPoint(center), -1)
@@ -7131,37 +7264,37 @@ var pointInEllipse = (p, ellipse) => {
7131
7264
  };
7132
7265
 
7133
7266
  // ../utils/collision.ts
7134
- var isPointOnShape = (point2, shape, tolerance = 0) => {
7267
+ var isPointOnShape = (point, shape, tolerance = 0) => {
7135
7268
  switch (shape.type) {
7136
7269
  case "polygon":
7137
- return pointOnPolygon(point2, shape.data, tolerance);
7270
+ return pointOnPolygon(point, shape.data, tolerance);
7138
7271
  case "ellipse":
7139
- return pointOnEllipse(point2, shape.data, tolerance);
7272
+ return pointOnEllipse(point, shape.data, tolerance);
7140
7273
  case "line":
7141
- return pointOnLineSegment(point2, shape.data, tolerance);
7274
+ return pointOnLineSegment(point, shape.data, tolerance);
7142
7275
  case "polyline":
7143
- return pointOnPolyline(point2, shape.data, tolerance);
7276
+ return pointOnPolyline(point, shape.data, tolerance);
7144
7277
  case "curve":
7145
- return pointOnCurve(point2, shape.data, tolerance);
7278
+ return pointOnCurve(point, shape.data, tolerance);
7146
7279
  case "polycurve":
7147
- return pointOnPolycurve(point2, shape.data, tolerance);
7280
+ return pointOnPolycurve(point, shape.data, tolerance);
7148
7281
  default:
7149
7282
  throw Error(`shape ${shape} is not implemented`);
7150
7283
  }
7151
7284
  };
7152
- var isPointInShape = (point2, shape) => {
7285
+ var isPointInShape = (point, shape) => {
7153
7286
  switch (shape.type) {
7154
7287
  case "polygon":
7155
- return polygonIncludesPoint(point2, shape.data);
7288
+ return polygonIncludesPoint(point, shape.data);
7156
7289
  case "line":
7157
7290
  return false;
7158
7291
  case "curve":
7159
7292
  return false;
7160
7293
  case "ellipse":
7161
- return pointInEllipse(point2, shape.data);
7294
+ return pointInEllipse(point, shape.data);
7162
7295
  case "polyline": {
7163
7296
  const polygon2 = polygonFromPoints(shape.data.flat());
7164
- return polygonIncludesPoint(point2, polygon2);
7297
+ return polygonIncludesPoint(point, polygon2);
7165
7298
  }
7166
7299
  case "polycurve": {
7167
7300
  return false;
@@ -7170,36 +7303,409 @@ var isPointInShape = (point2, shape) => {
7170
7303
  throw Error(`shape ${shape} is not implemented`);
7171
7304
  }
7172
7305
  };
7173
- var pointOnPolycurve = (point2, polycurve, tolerance) => {
7174
- return polycurve.some((curve2) => pointOnCurve(point2, curve2, tolerance));
7306
+ var pointOnPolycurve = (point, polycurve, tolerance) => {
7307
+ return polycurve.some((curve2) => pointOnCurve(point, curve2, tolerance));
7175
7308
  };
7176
7309
  var cubicBezierEquation = (curve2) => {
7177
7310
  const [p0, p1, p2, p3] = curve2;
7178
7311
  return (t, idx) => Math.pow(1 - t, 3) * p3[idx] + 3 * t * Math.pow(1 - t, 2) * p2[idx] + 3 * Math.pow(t, 2) * (1 - t) * p1[idx] + p0[idx] * Math.pow(t, 3);
7179
7312
  };
7180
7313
  var polyLineFromCurve = (curve2, segments = 10) => {
7181
- const equation2 = cubicBezierEquation(curve2);
7182
- let startingPoint = [equation2(0, 0), equation2(0, 1)];
7314
+ const equation = cubicBezierEquation(curve2);
7315
+ let startingPoint = [equation(0, 0), equation(0, 1)];
7183
7316
  const lineSegments = [];
7184
7317
  let t = 0;
7185
7318
  const increment = 1 / segments;
7186
7319
  for (let i = 0; i < segments; i++) {
7187
7320
  t += increment;
7188
7321
  if (t <= 1) {
7189
- const nextPoint = pointFrom(equation2(t, 0), equation2(t, 1));
7322
+ const nextPoint = pointFrom(equation(t, 0), equation(t, 1));
7190
7323
  lineSegments.push(lineSegment(startingPoint, nextPoint));
7191
7324
  startingPoint = nextPoint;
7192
7325
  }
7193
7326
  }
7194
7327
  return lineSegments;
7195
7328
  };
7196
- var pointOnCurve = (point2, curve2, threshold) => {
7197
- return pointOnPolyline(point2, polyLineFromCurve(curve2), threshold);
7329
+ var pointOnCurve = (point, curve2, threshold) => {
7330
+ return pointOnPolyline(point, polyLineFromCurve(curve2), threshold);
7198
7331
  };
7199
- var pointOnPolyline = (point2, polyline, threshold = 1e-4) => {
7200
- return polyline.some((line) => pointOnLineSegment(point2, line, threshold));
7332
+ var pointOnPolyline = (point, polyline, threshold = 1e-4) => {
7333
+ return polyline.some((line2) => pointOnLineSegment(point, line2, threshold));
7201
7334
  };
7202
7335
 
7336
+ // ../math/ellipse.ts
7337
+ function ellipse(center, halfWidth, halfHeight) {
7338
+ return {
7339
+ center,
7340
+ halfWidth,
7341
+ halfHeight
7342
+ };
7343
+ }
7344
+ var ellipseDistanceFromPoint = (p, ellipse2) => {
7345
+ const { halfWidth, halfHeight, center } = ellipse2;
7346
+ const a = halfWidth;
7347
+ const b = halfHeight;
7348
+ const translatedPoint = vectorAdd(
7349
+ vectorFromPoint(p),
7350
+ vectorScale(vectorFromPoint(center), -1)
7351
+ );
7352
+ const px = Math.abs(translatedPoint[0]);
7353
+ const py = Math.abs(translatedPoint[1]);
7354
+ let tx = 0.707;
7355
+ let ty = 0.707;
7356
+ for (let i = 0; i < 3; i++) {
7357
+ const x = a * tx;
7358
+ const y = b * ty;
7359
+ const ex = (a * a - b * b) * tx ** 3 / a;
7360
+ const ey = (b * b - a * a) * ty ** 3 / b;
7361
+ const rx = x - ex;
7362
+ const ry = y - ey;
7363
+ const qx = px - ex;
7364
+ const qy = py - ey;
7365
+ const r = Math.hypot(ry, rx);
7366
+ const q = Math.hypot(qy, qx);
7367
+ tx = Math.min(1, Math.max(0, (qx * r / q + ex) / a));
7368
+ ty = Math.min(1, Math.max(0, (qy * r / q + ey) / b));
7369
+ const t = Math.hypot(ty, tx);
7370
+ tx /= t;
7371
+ ty /= t;
7372
+ }
7373
+ const [minX, minY] = [
7374
+ a * tx * Math.sign(translatedPoint[0]),
7375
+ b * ty * Math.sign(translatedPoint[1])
7376
+ ];
7377
+ return pointDistance(pointFromVector(translatedPoint), pointFrom(minX, minY));
7378
+ };
7379
+ function ellipseLineIntersectionPoints({ center, halfWidth, halfHeight }, [g, h]) {
7380
+ const [cx, cy] = center;
7381
+ const x1 = g[0] - cx;
7382
+ const y1 = g[1] - cy;
7383
+ const x2 = h[0] - cx;
7384
+ const y2 = h[1] - cy;
7385
+ const a = Math.pow(x2 - x1, 2) / Math.pow(halfWidth, 2) + Math.pow(y2 - y1, 2) / Math.pow(halfHeight, 2);
7386
+ const b = 2 * (x1 * (x2 - x1) / Math.pow(halfWidth, 2) + y1 * (y2 - y1) / Math.pow(halfHeight, 2));
7387
+ const c = Math.pow(x1, 2) / Math.pow(halfWidth, 2) + Math.pow(y1, 2) / Math.pow(halfHeight, 2) - 1;
7388
+ const t1 = (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
7389
+ const t2 = (-b - Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
7390
+ const candidates = [
7391
+ pointFrom(x1 + t1 * (x2 - x1) + cx, y1 + t1 * (y2 - y1) + cy),
7392
+ pointFrom(x1 + t2 * (x2 - x1) + cx, y1 + t2 * (y2 - y1) + cy)
7393
+ ].filter((p) => !isNaN(p[0]) && !isNaN(p[1]));
7394
+ if (candidates.length === 2 && pointsEqual(candidates[0], candidates[1])) {
7395
+ return [candidates[0]];
7396
+ }
7397
+ return candidates;
7398
+ }
7399
+
7400
+ // element/utils.ts
7401
+ function deconstructRectanguloidElement(element, offset = 0) {
7402
+ const roundness = getCornerRadius(
7403
+ Math.min(element.width, element.height),
7404
+ element
7405
+ );
7406
+ if (roundness <= 0) {
7407
+ const r2 = rectangle(
7408
+ pointFrom(element.x - offset, element.y - offset),
7409
+ pointFrom(
7410
+ element.x + element.width + offset,
7411
+ element.y + element.height + offset
7412
+ )
7413
+ );
7414
+ const top2 = lineSegment(
7415
+ pointFrom(r2[0][0] + roundness, r2[0][1]),
7416
+ pointFrom(r2[1][0] - roundness, r2[0][1])
7417
+ );
7418
+ const right2 = lineSegment(
7419
+ pointFrom(r2[1][0], r2[0][1] + roundness),
7420
+ pointFrom(r2[1][0], r2[1][1] - roundness)
7421
+ );
7422
+ const bottom2 = lineSegment(
7423
+ pointFrom(r2[0][0] + roundness, r2[1][1]),
7424
+ pointFrom(r2[1][0] - roundness, r2[1][1])
7425
+ );
7426
+ const left2 = lineSegment(
7427
+ pointFrom(r2[0][0], r2[1][1] - roundness),
7428
+ pointFrom(r2[0][0], r2[0][1] + roundness)
7429
+ );
7430
+ const sides2 = [top2, right2, bottom2, left2];
7431
+ return [sides2, []];
7432
+ }
7433
+ const center = pointFrom(
7434
+ element.x + element.width / 2,
7435
+ element.y + element.height / 2
7436
+ );
7437
+ const r = rectangle(
7438
+ pointFrom(element.x, element.y),
7439
+ pointFrom(element.x + element.width, element.y + element.height)
7440
+ );
7441
+ const top = lineSegment(
7442
+ pointFrom(r[0][0] + roundness, r[0][1]),
7443
+ pointFrom(r[1][0] - roundness, r[0][1])
7444
+ );
7445
+ const right = lineSegment(
7446
+ pointFrom(r[1][0], r[0][1] + roundness),
7447
+ pointFrom(r[1][0], r[1][1] - roundness)
7448
+ );
7449
+ const bottom = lineSegment(
7450
+ pointFrom(r[0][0] + roundness, r[1][1]),
7451
+ pointFrom(r[1][0] - roundness, r[1][1])
7452
+ );
7453
+ const left = lineSegment(
7454
+ pointFrom(r[0][0], r[1][1] - roundness),
7455
+ pointFrom(r[0][0], r[0][1] + roundness)
7456
+ );
7457
+ const offsets = [
7458
+ vectorScale(
7459
+ vectorNormalize(
7460
+ vectorFromPoint(pointFrom(r[0][0] - offset, r[0][1] - offset), center)
7461
+ ),
7462
+ offset
7463
+ ),
7464
+ // TOP LEFT
7465
+ vectorScale(
7466
+ vectorNormalize(
7467
+ vectorFromPoint(pointFrom(r[1][0] + offset, r[0][1] - offset), center)
7468
+ ),
7469
+ offset
7470
+ ),
7471
+ //TOP RIGHT
7472
+ vectorScale(
7473
+ vectorNormalize(
7474
+ vectorFromPoint(pointFrom(r[1][0] + offset, r[1][1] + offset), center)
7475
+ ),
7476
+ offset
7477
+ ),
7478
+ // BOTTOM RIGHT
7479
+ vectorScale(
7480
+ vectorNormalize(
7481
+ vectorFromPoint(pointFrom(r[0][0] - offset, r[1][1] + offset), center)
7482
+ ),
7483
+ offset
7484
+ )
7485
+ // BOTTOM LEFT
7486
+ ];
7487
+ const corners = [
7488
+ curve(
7489
+ pointFromVector(offsets[0], left[1]),
7490
+ pointFromVector(
7491
+ offsets[0],
7492
+ pointFrom(
7493
+ left[1][0] + 2 / 3 * (r[0][0] - left[1][0]),
7494
+ left[1][1] + 2 / 3 * (r[0][1] - left[1][1])
7495
+ )
7496
+ ),
7497
+ pointFromVector(
7498
+ offsets[0],
7499
+ pointFrom(
7500
+ top[0][0] + 2 / 3 * (r[0][0] - top[0][0]),
7501
+ top[0][1] + 2 / 3 * (r[0][1] - top[0][1])
7502
+ )
7503
+ ),
7504
+ pointFromVector(offsets[0], top[0])
7505
+ ),
7506
+ // TOP LEFT
7507
+ curve(
7508
+ pointFromVector(offsets[1], top[1]),
7509
+ pointFromVector(
7510
+ offsets[1],
7511
+ pointFrom(
7512
+ top[1][0] + 2 / 3 * (r[1][0] - top[1][0]),
7513
+ top[1][1] + 2 / 3 * (r[0][1] - top[1][1])
7514
+ )
7515
+ ),
7516
+ pointFromVector(
7517
+ offsets[1],
7518
+ pointFrom(
7519
+ right[0][0] + 2 / 3 * (r[1][0] - right[0][0]),
7520
+ right[0][1] + 2 / 3 * (r[0][1] - right[0][1])
7521
+ )
7522
+ ),
7523
+ pointFromVector(offsets[1], right[0])
7524
+ ),
7525
+ // TOP RIGHT
7526
+ curve(
7527
+ pointFromVector(offsets[2], right[1]),
7528
+ pointFromVector(
7529
+ offsets[2],
7530
+ pointFrom(
7531
+ right[1][0] + 2 / 3 * (r[1][0] - right[1][0]),
7532
+ right[1][1] + 2 / 3 * (r[1][1] - right[1][1])
7533
+ )
7534
+ ),
7535
+ pointFromVector(
7536
+ offsets[2],
7537
+ pointFrom(
7538
+ bottom[1][0] + 2 / 3 * (r[1][0] - bottom[1][0]),
7539
+ bottom[1][1] + 2 / 3 * (r[1][1] - bottom[1][1])
7540
+ )
7541
+ ),
7542
+ pointFromVector(offsets[2], bottom[1])
7543
+ ),
7544
+ // BOTTOM RIGHT
7545
+ curve(
7546
+ pointFromVector(offsets[3], bottom[0]),
7547
+ pointFromVector(
7548
+ offsets[3],
7549
+ pointFrom(
7550
+ bottom[0][0] + 2 / 3 * (r[0][0] - bottom[0][0]),
7551
+ bottom[0][1] + 2 / 3 * (r[1][1] - bottom[0][1])
7552
+ )
7553
+ ),
7554
+ pointFromVector(
7555
+ offsets[3],
7556
+ pointFrom(
7557
+ left[0][0] + 2 / 3 * (r[0][0] - left[0][0]),
7558
+ left[0][1] + 2 / 3 * (r[1][1] - left[0][1])
7559
+ )
7560
+ ),
7561
+ pointFromVector(offsets[3], left[0])
7562
+ )
7563
+ // BOTTOM LEFT
7564
+ ];
7565
+ const sides = [
7566
+ lineSegment(corners[0][3], corners[1][0]),
7567
+ lineSegment(corners[1][3], corners[2][0]),
7568
+ lineSegment(corners[2][3], corners[3][0]),
7569
+ lineSegment(corners[3][3], corners[0][0])
7570
+ ];
7571
+ return [sides, corners];
7572
+ }
7573
+ function deconstructDiamondElement(element, offset = 0) {
7574
+ const [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY] = getDiamondPoints(element);
7575
+ const verticalRadius = getCornerRadius(Math.abs(topX - leftX), element);
7576
+ const horizontalRadius = getCornerRadius(Math.abs(rightY - topY), element);
7577
+ if (element.roundness?.type == null) {
7578
+ const [top2, right2, bottom2, left2] = [
7579
+ pointFrom(element.x + topX, element.y + topY - offset),
7580
+ pointFrom(element.x + rightX + offset, element.y + rightY),
7581
+ pointFrom(element.x + bottomX, element.y + bottomY + offset),
7582
+ pointFrom(element.x + leftX - offset, element.y + leftY)
7583
+ ];
7584
+ const topRight = lineSegment(
7585
+ pointFrom(top2[0] + verticalRadius, top2[1] + horizontalRadius),
7586
+ pointFrom(right2[0] - verticalRadius, right2[1] - horizontalRadius)
7587
+ );
7588
+ const bottomRight = lineSegment(
7589
+ pointFrom(right2[0] - verticalRadius, right2[1] + horizontalRadius),
7590
+ pointFrom(bottom2[0] + verticalRadius, bottom2[1] - horizontalRadius)
7591
+ );
7592
+ const bottomLeft = lineSegment(
7593
+ pointFrom(bottom2[0] - verticalRadius, bottom2[1] - horizontalRadius),
7594
+ pointFrom(left2[0] + verticalRadius, left2[1] + horizontalRadius)
7595
+ );
7596
+ const topLeft = lineSegment(
7597
+ pointFrom(left2[0] + verticalRadius, left2[1] - horizontalRadius),
7598
+ pointFrom(top2[0] - verticalRadius, top2[1] + horizontalRadius)
7599
+ );
7600
+ return [[topRight, bottomRight, bottomLeft, topLeft], []];
7601
+ }
7602
+ const center = pointFrom(
7603
+ element.x + element.width / 2,
7604
+ element.y + element.height / 2
7605
+ );
7606
+ const [top, right, bottom, left] = [
7607
+ pointFrom(element.x + topX, element.y + topY),
7608
+ pointFrom(element.x + rightX, element.y + rightY),
7609
+ pointFrom(element.x + bottomX, element.y + bottomY),
7610
+ pointFrom(element.x + leftX, element.y + leftY)
7611
+ ];
7612
+ const offsets = [
7613
+ vectorScale(vectorNormalize(vectorFromPoint(right, center)), offset),
7614
+ // RIGHT
7615
+ vectorScale(vectorNormalize(vectorFromPoint(bottom, center)), offset),
7616
+ // BOTTOM
7617
+ vectorScale(vectorNormalize(vectorFromPoint(left, center)), offset),
7618
+ // LEFT
7619
+ vectorScale(vectorNormalize(vectorFromPoint(top, center)), offset)
7620
+ // TOP
7621
+ ];
7622
+ const corners = [
7623
+ curve(
7624
+ pointFromVector(
7625
+ offsets[0],
7626
+ pointFrom(
7627
+ right[0] - verticalRadius,
7628
+ right[1] - horizontalRadius
7629
+ )
7630
+ ),
7631
+ pointFromVector(offsets[0], right),
7632
+ pointFromVector(offsets[0], right),
7633
+ pointFromVector(
7634
+ offsets[0],
7635
+ pointFrom(
7636
+ right[0] - verticalRadius,
7637
+ right[1] + horizontalRadius
7638
+ )
7639
+ )
7640
+ ),
7641
+ // RIGHT
7642
+ curve(
7643
+ pointFromVector(
7644
+ offsets[1],
7645
+ pointFrom(
7646
+ bottom[0] + verticalRadius,
7647
+ bottom[1] - horizontalRadius
7648
+ )
7649
+ ),
7650
+ pointFromVector(offsets[1], bottom),
7651
+ pointFromVector(offsets[1], bottom),
7652
+ pointFromVector(
7653
+ offsets[1],
7654
+ pointFrom(
7655
+ bottom[0] - verticalRadius,
7656
+ bottom[1] - horizontalRadius
7657
+ )
7658
+ )
7659
+ ),
7660
+ // BOTTOM
7661
+ curve(
7662
+ pointFromVector(
7663
+ offsets[2],
7664
+ pointFrom(
7665
+ left[0] + verticalRadius,
7666
+ left[1] + horizontalRadius
7667
+ )
7668
+ ),
7669
+ pointFromVector(offsets[2], left),
7670
+ pointFromVector(offsets[2], left),
7671
+ pointFromVector(
7672
+ offsets[2],
7673
+ pointFrom(
7674
+ left[0] + verticalRadius,
7675
+ left[1] - horizontalRadius
7676
+ )
7677
+ )
7678
+ ),
7679
+ // LEFT
7680
+ curve(
7681
+ pointFromVector(
7682
+ offsets[3],
7683
+ pointFrom(
7684
+ top[0] - verticalRadius,
7685
+ top[1] + horizontalRadius
7686
+ )
7687
+ ),
7688
+ pointFromVector(offsets[3], top),
7689
+ pointFromVector(offsets[3], top),
7690
+ pointFromVector(
7691
+ offsets[3],
7692
+ pointFrom(
7693
+ top[0] + verticalRadius,
7694
+ top[1] + horizontalRadius
7695
+ )
7696
+ )
7697
+ )
7698
+ // TOP
7699
+ ];
7700
+ const sides = [
7701
+ lineSegment(corners[0][3], corners[1][0]),
7702
+ lineSegment(corners[1][3], corners[2][0]),
7703
+ lineSegment(corners[2][3], corners[3][0]),
7704
+ lineSegment(corners[3][3], corners[0][0])
7705
+ ];
7706
+ return [sides, corners];
7707
+ }
7708
+
7203
7709
  // element/collision.ts
7204
7710
  var shouldTestInside = (element) => {
7205
7711
  if (element.type === "arrow") {
@@ -7258,6 +7764,93 @@ var hitElementBoundingBoxOnly = (hitArgs, elementsMap) => {
7258
7764
  var hitElementBoundText = (x, y, textShape) => {
7259
7765
  return !!textShape && isPointInShape(pointFrom(x, y), textShape);
7260
7766
  };
7767
+ var intersectElementWithLineSegment = (element, line2, offset = 0) => {
7768
+ switch (element.type) {
7769
+ case "rectangle":
7770
+ case "image":
7771
+ case "text":
7772
+ case "iframe":
7773
+ case "embeddable":
7774
+ case "frame":
7775
+ case "magicframe":
7776
+ return intersectRectanguloidWithLineSegment(element, line2, offset);
7777
+ case "diamond":
7778
+ return intersectDiamondWithLineSegment(element, line2, offset);
7779
+ case "ellipse":
7780
+ return intersectEllipseWithLineSegment(element, line2, offset);
7781
+ default:
7782
+ throw new Error(`Unimplemented element type '${element.type}'`);
7783
+ }
7784
+ };
7785
+ var intersectRectanguloidWithLineSegment = (element, l, offset = 0) => {
7786
+ const center = pointFrom(
7787
+ element.x + element.width / 2,
7788
+ element.y + element.height / 2
7789
+ );
7790
+ const rotatedA = pointRotateRads(
7791
+ l[0],
7792
+ center,
7793
+ -element.angle
7794
+ );
7795
+ const rotatedB = pointRotateRads(
7796
+ l[1],
7797
+ center,
7798
+ -element.angle
7799
+ );
7800
+ const [sides, corners] = deconstructRectanguloidElement(element, offset);
7801
+ return [
7802
+ // Test intersection against the sides, keep only the valid
7803
+ // intersection points and rotate them back to scene space
7804
+ ...sides.map(
7805
+ (s) => lineSegmentIntersectionPoints(
7806
+ lineSegment(rotatedA, rotatedB),
7807
+ s
7808
+ )
7809
+ ).filter((x) => x != null).map((j) => pointRotateRads(j, center, element.angle)),
7810
+ // Test intersection against the corners which are cubic bezier curves,
7811
+ // keep only the valid intersection points and rotate them back to scene
7812
+ // space
7813
+ ...corners.flatMap(
7814
+ (t) => curveIntersectLineSegment(t, lineSegment(rotatedA, rotatedB))
7815
+ ).filter((i) => i != null).map((j) => pointRotateRads(j, center, element.angle))
7816
+ ].filter(
7817
+ (p, idx, points) => points.findIndex((d) => pointsEqual(p, d)) === idx
7818
+ );
7819
+ };
7820
+ var intersectDiamondWithLineSegment = (element, l, offset = 0) => {
7821
+ const center = pointFrom(
7822
+ element.x + element.width / 2,
7823
+ element.y + element.height / 2
7824
+ );
7825
+ const rotatedA = pointRotateRads(l[0], center, -element.angle);
7826
+ const rotatedB = pointRotateRads(l[1], center, -element.angle);
7827
+ const [sides, curves] = deconstructDiamondElement(element, offset);
7828
+ return [
7829
+ ...sides.map(
7830
+ (s) => lineSegmentIntersectionPoints(
7831
+ lineSegment(rotatedA, rotatedB),
7832
+ s
7833
+ )
7834
+ ).filter((p) => p != null).map((p) => pointRotateRads(p, center, element.angle)),
7835
+ ...curves.flatMap(
7836
+ (p) => curveIntersectLineSegment(p, lineSegment(rotatedA, rotatedB))
7837
+ ).filter((p) => p != null).map((p) => pointRotateRads(p, center, element.angle))
7838
+ ].filter(
7839
+ (p, idx, points) => points.findIndex((d) => pointsEqual(p, d)) === idx
7840
+ );
7841
+ };
7842
+ var intersectEllipseWithLineSegment = (element, l, offset = 0) => {
7843
+ const center = pointFrom(
7844
+ element.x + element.width / 2,
7845
+ element.y + element.height / 2
7846
+ );
7847
+ const rotatedA = pointRotateRads(l[0], center, -element.angle);
7848
+ const rotatedB = pointRotateRads(l[1], center, -element.angle);
7849
+ return ellipseLineIntersectionPoints(
7850
+ ellipse(center, element.width / 2 + offset, element.height / 2 + offset),
7851
+ line(rotatedA, rotatedB)
7852
+ ).map((p) => pointRotateRads(p, center, element.angle));
7853
+ };
7261
7854
 
7262
7855
  // keys.ts
7263
7856
  var CODES = {
@@ -7521,9 +8114,9 @@ var getControlPointsForBezierCurve = (element, endPoint) => {
7521
8114
  const p1 = pointFrom(data[0], data[1]);
7522
8115
  const p2 = pointFrom(data[2], data[3]);
7523
8116
  const p3 = pointFrom(data[4], data[5]);
7524
- const distance3 = pointDistance(p3, endPoint);
7525
- if (distance3 < minDistance) {
7526
- minDistance = distance3;
8117
+ const distance2 = pointDistance(p3, endPoint);
8118
+ if (distance2 < minDistance) {
8119
+ minDistance = distance2;
7527
8120
  controlPoints = [p0, p1, p2, p3];
7528
8121
  }
7529
8122
  currentP = p3;
@@ -7533,9 +8126,9 @@ var getControlPointsForBezierCurve = (element, endPoint) => {
7533
8126
  return controlPoints;
7534
8127
  };
7535
8128
  var getBezierXY = (p0, p1, p2, p3, t) => {
7536
- const equation2 = (t2, idx) => Math.pow(1 - t2, 3) * p3[idx] + 3 * t2 * Math.pow(1 - t2, 2) * p2[idx] + 3 * Math.pow(t2, 2) * (1 - t2) * p1[idx] + p0[idx] * Math.pow(t2, 3);
7537
- const tx = equation2(t, 0);
7538
- const ty = equation2(t, 1);
8129
+ const equation = (t2, idx) => Math.pow(1 - t2, 3) * p3[idx] + 3 * t2 * Math.pow(1 - t2, 2) * p2[idx] + 3 * Math.pow(t2, 2) * (1 - t2) * p1[idx] + p0[idx] * Math.pow(t2, 3);
8130
+ const tx = equation(t, 0);
8131
+ const ty = equation(t, 1);
7539
8132
  return pointFrom(tx, ty);
7540
8133
  };
7541
8134
  var getPointsInBezierCurve = (element, endPoint) => {
@@ -7568,11 +8161,11 @@ var getBezierCurveArcLengths = (element, endPoint) => {
7568
8161
  arcLengths[0] = 0;
7569
8162
  const points = getPointsInBezierCurve(element, endPoint);
7570
8163
  let index = 0;
7571
- let distance3 = 0;
8164
+ let distance2 = 0;
7572
8165
  while (index < points.length - 1) {
7573
8166
  const segmentDistance = pointDistance(points[index], points[index + 1]);
7574
- distance3 += segmentDistance;
7575
- arcLengths.push(distance3);
8167
+ distance2 += segmentDistance;
8168
+ arcLengths.push(distance2);
7576
8169
  index++;
7577
8170
  }
7578
8171
  return arcLengths;
@@ -7605,7 +8198,7 @@ var mapIntervalToBezierT = (element, endPoint, interval) => {
7605
8198
  }
7606
8199
  return 1 - (index + (targetLength - arcLengths[index]) / (arcLengths[index + 1] - arcLengths[index])) / pointsCount;
7607
8200
  };
7608
- var aabbForElement = (element, offset2) => {
8201
+ var aabbForElement = (element, offset) => {
7609
8202
  const bbox = {
7610
8203
  minX: element.x,
7611
8204
  minY: element.y,
@@ -7641,8 +8234,8 @@ var aabbForElement = (element, offset2) => {
7641
8234
  Math.max(topLeftX, topRightX, bottomRightX, bottomLeftX),
7642
8235
  Math.max(topLeftY, topRightY, bottomRightY, bottomLeftY)
7643
8236
  ];
7644
- if (offset2) {
7645
- const [topOffset, rightOffset, downOffset, leftOffset] = offset2;
8237
+ if (offset) {
8238
+ const [topOffset, rightOffset, downOffset, leftOffset] = offset;
7646
8239
  return [
7647
8240
  bounds[0] - leftOffset,
7648
8241
  bounds[1] - topOffset,
@@ -7670,8 +8263,8 @@ var getCornerRadius = (x, element) => {
7670
8263
  var isPathALoop = (points, zoomValue = 1) => {
7671
8264
  if (points.length >= 3) {
7672
8265
  const [first, last] = [points[0], points[points.length - 1]];
7673
- const distance3 = pointDistance(first, last);
7674
- return distance3 <= LINE_CONFIRM_THRESHOLD / zoomValue;
8266
+ const distance2 = pointDistance(first, last);
8267
+ return distance2 <= LINE_CONFIRM_THRESHOLD / zoomValue;
7675
8268
  }
7676
8269
  return false;
7677
8270
  };
@@ -8474,11 +9067,11 @@ var renderSelectionElement = (element, context, appState, selectionColor) => {
8474
9067
  context.save();
8475
9068
  context.translate(element.x + appState.scrollX, element.y + appState.scrollY);
8476
9069
  context.fillStyle = "rgba(0, 0, 200, 0.04)";
8477
- const offset2 = 0.5 / appState.zoom.value;
8478
- context.fillRect(offset2, offset2, element.width, element.height);
9070
+ const offset = 0.5 / appState.zoom.value;
9071
+ context.fillRect(offset, offset, element.width, element.height);
8479
9072
  context.lineWidth = 1 / appState.zoom.value;
8480
9073
  context.strokeStyle = selectionColor;
8481
- context.strokeRect(offset2, offset2, element.width, element.height);
9074
+ context.strokeRect(offset, offset, element.width, element.height);
8482
9075
  context.restore();
8483
9076
  };
8484
9077
  var renderElement = (element, elementsMap, allElementsMap, rc, context, renderConfig, appState) => {
@@ -8742,11 +9335,11 @@ function getSvgPathFromStroke2(points) {
8742
9335
  }
8743
9336
  const max = points.length - 1;
8744
9337
  return points.reduce(
8745
- (acc, point2, i, arr) => {
9338
+ (acc, point, i, arr) => {
8746
9339
  if (i === max) {
8747
- acc.push(point2, med(point2, arr[0]), "L", arr[0], "Z");
9340
+ acc.push(point, med(point, arr[0]), "L", arr[0], "Z");
8748
9341
  } else {
8749
- acc.push(point2, med(point2, arr[i + 1]));
9342
+ acc.push(point, med(point, arr[i + 1]));
8750
9343
  }
8751
9344
  return acc;
8752
9345
  },
@@ -9261,33 +9854,33 @@ var generateElbowArrowShape = (points, radius) => {
9261
9854
  for (let i = 1; i < points.length - 1; i += 1) {
9262
9855
  const prev = points[i - 1];
9263
9856
  const next = points[i + 1];
9264
- const point2 = points[i];
9265
- const prevIsHorizontal = headingForPointIsHorizontal(point2, prev);
9266
- const nextIsHorizontal = headingForPointIsHorizontal(next, point2);
9857
+ const point = points[i];
9858
+ const prevIsHorizontal = headingForPointIsHorizontal(point, prev);
9859
+ const nextIsHorizontal = headingForPointIsHorizontal(next, point);
9267
9860
  const corner = Math.min(
9268
9861
  radius,
9269
9862
  pointDistance(points[i], next) / 2,
9270
9863
  pointDistance(points[i], prev) / 2
9271
9864
  );
9272
9865
  if (prevIsHorizontal) {
9273
- if (prev[0] < point2[0]) {
9866
+ if (prev[0] < point[0]) {
9274
9867
  subpoints.push([points[i][0] - corner, points[i][1]]);
9275
9868
  } else {
9276
9869
  subpoints.push([points[i][0] + corner, points[i][1]]);
9277
9870
  }
9278
- } else if (prev[1] < point2[1]) {
9871
+ } else if (prev[1] < point[1]) {
9279
9872
  subpoints.push([points[i][0], points[i][1] - corner]);
9280
9873
  } else {
9281
9874
  subpoints.push([points[i][0], points[i][1] + corner]);
9282
9875
  }
9283
9876
  subpoints.push(points[i]);
9284
9877
  if (nextIsHorizontal) {
9285
- if (next[0] < point2[0]) {
9878
+ if (next[0] < point[0]) {
9286
9879
  subpoints.push([points[i][0] - corner, points[i][1]]);
9287
9880
  } else {
9288
9881
  subpoints.push([points[i][0] + corner, points[i][1]]);
9289
9882
  }
9290
- } else if (next[1] < point2[1]) {
9883
+ } else if (next[1] < point[1]) {
9291
9884
  subpoints.push([points[i][0], points[i][1] - corner]);
9292
9885
  } else {
9293
9886
  subpoints.push([points[i][0], points[i][1] + corner]);
@@ -9306,23 +9899,23 @@ var generateElbowArrowShape = (points, radius) => {
9306
9899
 
9307
9900
  // points.ts
9308
9901
  var getSizeFromPoints = (points) => {
9309
- const xs = points.map((point2) => point2[0]);
9310
- const ys = points.map((point2) => point2[1]);
9902
+ const xs = points.map((point) => point[0]);
9903
+ const ys = points.map((point) => point[1]);
9311
9904
  return {
9312
9905
  width: Math.max(...xs) - Math.min(...xs),
9313
9906
  height: Math.max(...ys) - Math.min(...ys)
9314
9907
  };
9315
9908
  };
9316
9909
  var rescalePoints = (dimension, newSize, points, normalize) => {
9317
- const coordinates = points.map((point2) => point2[dimension]);
9910
+ const coordinates = points.map((point) => point[dimension]);
9318
9911
  const maxCoordinate = Math.max(...coordinates);
9319
9912
  const minCoordinate = Math.min(...coordinates);
9320
9913
  const size = maxCoordinate - minCoordinate;
9321
9914
  const scale = size === 0 ? 1 : newSize / size;
9322
9915
  let nextMinCoordinate = Infinity;
9323
- const scaledPoints = points.map((point2) => {
9324
- const newCoordinate = point2[dimension] * scale;
9325
- const newPoint = [...point2];
9916
+ const scaledPoints = points.map((point) => {
9917
+ const newCoordinate = point[dimension] * scale;
9918
+ const newPoint = [...point];
9326
9919
  newPoint[dimension] = newCoordinate;
9327
9920
  if (newCoordinate < nextMinCoordinate) {
9328
9921
  nextMinCoordinate = newCoordinate;
@@ -9335,11 +9928,11 @@ var rescalePoints = (dimension, newSize, points, normalize) => {
9335
9928
  if (scaledPoints.length === 2) {
9336
9929
  return scaledPoints;
9337
9930
  }
9338
- const translation2 = minCoordinate - nextMinCoordinate;
9931
+ const translation = minCoordinate - nextMinCoordinate;
9339
9932
  const nextPoints = scaledPoints.map(
9340
9933
  (scaledPoint) => pointFromPair(
9341
9934
  scaledPoint.map((value, currentDimension) => {
9342
- return currentDimension === dimension ? value + translation2 : value;
9935
+ return currentDimension === dimension ? value + translation : value;
9343
9936
  })
9344
9937
  )
9345
9938
  );
@@ -9531,7 +10124,7 @@ var getElementLineSegments = (element, elementsMap) => {
9531
10124
  [cx, y2],
9532
10125
  [x1, cy],
9533
10126
  [x2, cy]
9534
- ].map((point2) => pointRotateRads(point2, center, element.angle));
10127
+ ].map((point) => pointRotateRads(point, center, element.angle));
9535
10128
  if (element.type === "diamond") {
9536
10129
  return [
9537
10130
  lineSegment(n, w),
@@ -9737,12 +10330,12 @@ var getArrowheadPoints = (element, shape, position, arrowhead) => {
9737
10330
  } else if (prevOp.op === "bcurveTo") {
9738
10331
  p0 = pointFrom(prevOp.data[4], prevOp.data[5]);
9739
10332
  }
9740
- const equation2 = (t, idx) => Math.pow(1 - t, 3) * p3[idx] + 3 * t * Math.pow(1 - t, 2) * p2[idx] + 3 * Math.pow(t, 2) * (1 - t) * p1[idx] + p0[idx] * Math.pow(t, 3);
10333
+ const equation = (t, idx) => Math.pow(1 - t, 3) * p3[idx] + 3 * t * Math.pow(1 - t, 2) * p2[idx] + 3 * Math.pow(t, 2) * (1 - t) * p1[idx] + p0[idx] * Math.pow(t, 3);
9741
10334
  const [x2, y2] = position === "start" ? p0 : p3;
9742
- const [x1, y1] = [equation2(0.3, 0), equation2(0.3, 1)];
9743
- const distance3 = Math.hypot(x2 - x1, y2 - y1);
9744
- const nx = (x2 - x1) / distance3;
9745
- const ny = (y2 - y1) / distance3;
10335
+ const [x1, y1] = [equation(0.3, 0), equation(0.3, 1)];
10336
+ const distance2 = Math.hypot(x2 - x1, y2 - y1);
10337
+ const nx = (x2 - x1) / distance2;
10338
+ const ny = (y2 - y1) / distance2;
9746
10339
  const size = getArrowheadSize(arrowhead);
9747
10340
  let length = 0;
9748
10341
  {
@@ -9953,7 +10546,7 @@ var getElementPointsCoords = (element, points) => {
9953
10546
  maxY + element.y
9954
10547
  ];
9955
10548
  };
9956
- var getClosestElementBounds = (elements, from3) => {
10549
+ var getClosestElementBounds = (elements, from) => {
9957
10550
  if (!elements.length) {
9958
10551
  return [0, 0, 0, 0];
9959
10552
  }
@@ -9962,12 +10555,12 @@ var getClosestElementBounds = (elements, from3) => {
9962
10555
  const elementsMap = arrayToMap(elements);
9963
10556
  elements.forEach((element) => {
9964
10557
  const [x1, y1, x2, y2] = getElementBounds(element, elementsMap);
9965
- const distance3 = pointDistance(
10558
+ const distance2 = pointDistance(
9966
10559
  pointFrom((x1 + x2) / 2, (y1 + y2) / 2),
9967
- pointFrom(from3.x, from3.y)
10560
+ pointFrom(from.x, from.y)
9968
10561
  );
9969
- if (distance3 < minDistance) {
9970
- minDistance = distance3;
10562
+ if (distance2 < minDistance) {
10563
+ minDistance = distance2;
9971
10564
  closestElement = element;
9972
10565
  }
9973
10566
  });
@@ -10005,214 +10598,58 @@ var getCenterForBounds = (bounds) => pointFrom(
10005
10598
  bounds[1] + (bounds[3] - bounds[1]) / 2
10006
10599
  );
10007
10600
 
10008
- // ../math/ga/ga.ts
10009
- var point = (x, y) => [0, 0, 0, 0, y, x, 1, 0];
10010
- var offset = (x, y) => [
10011
- 0,
10012
- 0,
10013
- 0,
10014
- 0,
10015
- y,
10016
- x,
10017
- 0,
10018
- 0
10019
- ];
10020
- var nvector = (value = 0, index = 0) => {
10021
- const result = [0, 0, 0, 0, 0, 0, 0, 0];
10022
- if (index < 0 || index > 7) {
10023
- throw new Error(`Expected \`index\` between 0 and 7, got \`${index}\``);
10024
- }
10025
- if (value !== 0) {
10026
- result[index] = value;
10027
- }
10028
- return result;
10029
- };
10030
- var reverse = (nvector2) => [
10031
- nvector2[0],
10032
- nvector2[1],
10033
- nvector2[2],
10034
- nvector2[3],
10035
- -nvector2[4],
10036
- -nvector2[5],
10037
- -nvector2[6],
10038
- -nvector2[7]
10039
- ];
10040
- var add = (a, b) => {
10041
- if (isNumber(b)) {
10042
- return [a[0] + b, a[1], a[2], a[3], a[4], a[5], a[6], a[7]];
10601
+ // element/distance.ts
10602
+ var distanceToBindableElement = (element, p) => {
10603
+ switch (element.type) {
10604
+ case "rectangle":
10605
+ case "image":
10606
+ case "text":
10607
+ case "iframe":
10608
+ case "embeddable":
10609
+ case "frame":
10610
+ case "magicframe":
10611
+ return distanceToRectanguloidElement(element, p);
10612
+ case "diamond":
10613
+ return distanceToDiamondElement(element, p);
10614
+ case "ellipse":
10615
+ return distanceToEllipseElement(element, p);
10043
10616
  }
10044
- return [
10045
- a[0] + b[0],
10046
- a[1] + b[1],
10047
- a[2] + b[2],
10048
- a[3] + b[3],
10049
- a[4] + b[4],
10050
- a[5] + b[5],
10051
- a[6] + b[6],
10052
- a[7] + b[7]
10053
- ];
10054
10617
  };
10055
- var sub = (a, b) => {
10056
- if (isNumber(b)) {
10057
- return [a[0] - b, a[1], a[2], a[3], a[4], a[5], a[6], a[7]];
10058
- }
10059
- return [
10060
- a[0] - b[0],
10061
- a[1] - b[1],
10062
- a[2] - b[2],
10063
- a[3] - b[3],
10064
- a[4] - b[4],
10065
- a[5] - b[5],
10066
- a[6] - b[6],
10067
- a[7] - b[7]
10068
- ];
10618
+ var distanceToRectanguloidElement = (element, p) => {
10619
+ const center = pointFrom(
10620
+ element.x + element.width / 2,
10621
+ element.y + element.height / 2
10622
+ );
10623
+ const rotatedPoint = pointRotateRads(p, center, -element.angle);
10624
+ const [sides, corners] = deconstructRectanguloidElement(element);
10625
+ return Math.min(
10626
+ ...sides.map((s) => distanceToLineSegment(rotatedPoint, s)),
10627
+ ...corners.map((a) => curvePointDistance(a, rotatedPoint)).filter((d) => d !== null)
10628
+ );
10069
10629
  };
10070
- var mul = (a, b) => {
10071
- if (isNumber(b)) {
10072
- return [
10073
- a[0] * b,
10074
- a[1] * b,
10075
- a[2] * b,
10076
- a[3] * b,
10077
- a[4] * b,
10078
- a[5] * b,
10079
- a[6] * b,
10080
- a[7] * b
10081
- ];
10082
- }
10083
- return [
10084
- mulScalar(a, b),
10085
- b[1] * a[0] + b[0] * a[1] - b[4] * a[2] + b[5] * a[3] + b[2] * a[4] - b[3] * a[5] - b[7] * a[6] - b[6] * a[7],
10086
- b[2] * a[0] + b[0] * a[2] - b[6] * a[3] + b[3] * a[6],
10087
- b[3] * a[0] + b[6] * a[2] + b[0] * a[3] - b[2] * a[6],
10088
- b[4] * a[0] + b[2] * a[1] - b[1] * a[2] + b[7] * a[3] + b[0] * a[4] + b[6] * a[5] - b[5] * a[6] + b[3] * a[7],
10089
- b[5] * a[0] - b[3] * a[1] + b[7] * a[2] + b[1] * a[3] - b[6] * a[4] + b[0] * a[5] + b[4] * a[6] + b[2] * a[7],
10090
- b[6] * a[0] + b[3] * a[2] - b[2] * a[3] + b[0] * a[6],
10091
- b[7] * a[0] + b[6] * a[1] + b[5] * a[2] + b[4] * a[3] + b[3] * a[4] + b[2] * a[5] + b[1] * a[6] + b[0] * a[7]
10092
- ];
10630
+ var distanceToDiamondElement = (element, p) => {
10631
+ const center = pointFrom(
10632
+ element.x + element.width / 2,
10633
+ element.y + element.height / 2
10634
+ );
10635
+ const rotatedPoint = pointRotateRads(p, center, -element.angle);
10636
+ const [sides, curves] = deconstructDiamondElement(element);
10637
+ return Math.min(
10638
+ ...sides.map((s) => distanceToLineSegment(rotatedPoint, s)),
10639
+ ...curves.map((a) => curvePointDistance(a, rotatedPoint)).filter((d) => d !== null)
10640
+ );
10093
10641
  };
10094
- var mulScalar = (a, b) => b[0] * a[0] + b[2] * a[2] + b[3] * a[3] - b[6] * a[6];
10095
- var meet = (a, b) => [
10096
- b[0] * a[0],
10097
- b[1] * a[0] + b[0] * a[1],
10098
- b[2] * a[0] + b[0] * a[2],
10099
- b[3] * a[0] + b[0] * a[3],
10100
- b[4] * a[0] + b[2] * a[1] - b[1] * a[2] + b[0] * a[4],
10101
- b[5] * a[0] - b[3] * a[1] + b[1] * a[3] + b[0] * a[5],
10102
- b[6] * a[0] + b[3] * a[2] - b[2] * a[3] + b[0] * a[6],
10103
- b[7] * a[0] + b[6] * a[1] + b[5] * a[2] + b[4] * a[3] + b[3] * a[4] + b[2] * a[5] + b[1] * a[6]
10104
- ];
10105
- var join = (a, b) => [
10106
- joinScalar(a, b),
10107
- a[1] * b[7] + a[4] * b[5] - a[5] * b[4] + a[7] * b[1],
10108
- a[2] * b[7] - a[4] * b[6] + a[6] * b[4] + a[7] * b[2],
10109
- a[3] * b[7] + a[5] * b[6] - a[6] * b[5] + a[7] * b[3],
10110
- a[4] * b[7] + a[7] * b[4],
10111
- a[5] * b[7] + a[7] * b[5],
10112
- a[6] * b[7] + a[7] * b[6],
10113
- a[7] * b[7]
10114
- ];
10115
- var joinScalar = (a, b) => a[0] * b[7] + a[1] * b[6] + a[2] * b[5] + a[3] * b[4] + a[4] * b[3] + a[5] * b[2] + a[6] * b[1] + a[7] * b[0];
10116
- var dot = (a, b) => [
10117
- b[0] * a[0] + b[2] * a[2] + b[3] * a[3] - b[6] * a[6],
10118
- b[1] * a[0] + b[0] * a[1] - b[4] * a[2] + b[5] * a[3] + b[2] * a[4] - b[3] * a[5] - b[7] * a[6] - b[6] * a[7],
10119
- b[2] * a[0] + b[0] * a[2] - b[6] * a[3] + b[3] * a[6],
10120
- b[3] * a[0] + b[6] * a[2] + b[0] * a[3] - b[2] * a[6],
10121
- b[4] * a[0] + b[7] * a[3] + b[0] * a[4] + b[3] * a[7],
10122
- b[5] * a[0] + b[7] * a[2] + b[0] * a[5] + b[2] * a[7],
10123
- b[6] * a[0] + b[0] * a[6],
10124
- b[7] * a[0] + b[0] * a[7]
10125
- ];
10126
- var norm = (a) => Math.sqrt(Math.abs(a[0] * a[0] - a[2] * a[2] - a[3] * a[3] + a[6] * a[6]));
10127
- var inorm = (a) => Math.sqrt(Math.abs(a[7] * a[7] - a[5] * a[5] - a[4] * a[4] + a[1] * a[1]));
10128
- var normalized = (a) => {
10129
- const n = norm(a);
10130
- if (n === 0 || n === 1) {
10131
- return a;
10132
- }
10133
- const sign2 = a[6] < 0 ? -1 : 1;
10134
- return mul(a, sign2 / n);
10135
- };
10136
- var inormalized = (a) => {
10137
- const n = inorm(a);
10138
- if (n === 0 || n === 1) {
10139
- return a;
10140
- }
10141
- return mul(a, 1 / n);
10142
- };
10143
- var isNumber = (a) => typeof a === "number";
10144
- var E0 = nvector(1, 1);
10145
- var E1 = nvector(1, 2);
10146
- var E2 = nvector(1, 3);
10147
- var E01 = nvector(1, 4);
10148
- var E20 = nvector(1, 5);
10149
- var E12 = nvector(1, 6);
10150
- var E012 = nvector(1, 7);
10151
-
10152
- // ../math/ga/galines.ts
10153
- var equation = (a, b, c) => normalized([0, c, a, b, 0, 0, 0, 0]);
10154
- var through = (from3, to) => normalized(join(to, from3));
10155
- var orthogonal = (line, point2) => dot(line, point2);
10156
- var orthogonalThrough = (against, intersection) => orthogonal(through(against, intersection), intersection);
10157
- var sign = (line) => Math.sign(line[1]);
10158
-
10159
- // ../math/ga/gapoints.ts
10160
- var from = ([x, y]) => [
10161
- 0,
10162
- 0,
10163
- 0,
10164
- 0,
10165
- y,
10166
- x,
10167
- 1,
10168
- 0
10169
- ];
10170
- var toTuple = (point2) => [point2[5], point2[4]];
10171
- var abs = (point2) => [
10172
- 0,
10173
- 0,
10174
- 0,
10175
- 0,
10176
- Math.abs(point2[4]),
10177
- Math.abs(point2[5]),
10178
- 1,
10179
- 0
10180
- ];
10181
- var intersect = (line1, line2) => normalized(meet(line1, line2));
10182
- var distance2 = (point1, point2) => norm(join(point1, point2));
10183
- var distanceToLine = (point2, line) => joinScalar(point2, line);
10184
-
10185
- // ../math/ga/gadirections.ts
10186
- var from2 = (point2) => [
10187
- 0,
10188
- 0,
10189
- 0,
10190
- 0,
10191
- point2[4],
10192
- point2[5],
10193
- 0,
10194
- 0
10195
- ];
10196
- var fromTo = (from3, to) => inormalized([0, 0, 0, 0, to[4] - from3[4], to[5] - from3[5], 0, 0]);
10197
-
10198
- // ../math/ga/gatransforms.ts
10199
- var rotation = (pivot, angle) => add(mul(pivot, Math.sin(angle / 2)), Math.cos(angle / 2));
10200
- var translation = (direction) => [
10201
- 1,
10202
- 0,
10203
- 0,
10204
- 0,
10205
- -(0.5 * direction[5]),
10206
- 0.5 * direction[4],
10207
- 0,
10208
- 0
10209
- ];
10210
- var translationOrthogonal = (direction, distance3) => {
10211
- const scale = 0.5 * distance3;
10212
- return [1, 0, 0, 0, scale * direction[4], scale * direction[5], 0, 0];
10642
+ var distanceToEllipseElement = (element, p) => {
10643
+ const center = pointFrom(
10644
+ element.x + element.width / 2,
10645
+ element.y + element.height / 2
10646
+ );
10647
+ return ellipseDistanceFromPoint(
10648
+ // Instead of rotating the ellipse, rotate the point to the inverse angle
10649
+ pointRotateRads(p, center, -element.angle),
10650
+ ellipse(center, element.width / 2, element.height / 2)
10651
+ );
10213
10652
  };
10214
- var compose = (motor1, motor2) => mul(motor2, motor1);
10215
- var apply = (motor, nvector2) => normalized(mul(mul(motor, nvector2), reverse(motor)));
10216
10653
 
10217
10654
  // element/binding.ts
10218
10655
  var shouldEnableBindingForPointerEvent = (event) => {
@@ -10464,21 +10901,26 @@ var bindLinearElement = (linearElement, hoveredElement, startOrEnd, elementsMap)
10464
10901
  }
10465
10902
  const binding = {
10466
10903
  elementId: hoveredElement.id,
10467
- ...normalizePointBinding(
10468
- calculateFocusAndGap(
10904
+ ...isElbowArrow(linearElement) ? {
10905
+ ...calculateFixedPointForElbowArrowBinding(
10469
10906
  linearElement,
10470
10907
  hoveredElement,
10471
10908
  startOrEnd,
10472
10909
  elementsMap
10473
10910
  ),
10474
- hoveredElement
10475
- ),
10476
- ...isElbowArrow(linearElement) ? calculateFixedPointForElbowArrowBinding(
10477
- linearElement,
10478
- hoveredElement,
10479
- startOrEnd,
10480
- elementsMap
10481
- ) : { fixedPoint: null }
10911
+ focus: 0,
10912
+ gap: 0
10913
+ } : {
10914
+ ...normalizePointBinding(
10915
+ calculateFocusAndGap(
10916
+ linearElement,
10917
+ hoveredElement,
10918
+ startOrEnd,
10919
+ elementsMap
10920
+ ),
10921
+ hoveredElement
10922
+ )
10923
+ }
10482
10924
  };
10483
10925
  mutateElement(linearElement, {
10484
10926
  [startOrEnd === "start" ? "startBinding" : "endBinding"]: binding
@@ -10611,16 +11053,8 @@ var calculateFocusAndGap = (linearElement, hoveredElement, startOrEnd, elementsM
10611
11053
  elementsMap
10612
11054
  );
10613
11055
  return {
10614
- focus: determineFocusDistance(
10615
- hoveredElement,
10616
- adjacentPoint,
10617
- edgePoint,
10618
- elementsMap
10619
- ),
10620
- gap: Math.max(
10621
- 1,
10622
- distanceToBindableElement(hoveredElement, edgePoint, elementsMap)
10623
- )
11056
+ focus: determineFocusDistance(hoveredElement, adjacentPoint, edgePoint),
11057
+ gap: Math.max(1, distanceToBindableElement(hoveredElement, edgePoint))
10624
11058
  };
10625
11059
  };
10626
11060
  var updateBoundElements = (changedElement, elementsMap, options) => {
@@ -10659,17 +11093,17 @@ var updateBoundElements = (changedElement, elementsMap, options) => {
10659
11093
  element,
10660
11094
  (bindableElement, bindingProp) => {
10661
11095
  if (bindableElement && isBindableElement(bindableElement) && (bindingProp === "startBinding" || bindingProp === "endBinding") && changedElement.id === element[bindingProp]?.elementId) {
10662
- const point2 = updateBoundPoint(
11096
+ const point = updateBoundPoint(
10663
11097
  element,
10664
11098
  bindingProp,
10665
11099
  bindings[bindingProp],
10666
11100
  bindableElement,
10667
11101
  elementsMap
10668
11102
  );
10669
- if (point2) {
11103
+ if (point) {
10670
11104
  return {
10671
11105
  index: bindingProp === "startBinding" ? 0 : element.points.length - 1,
10672
- point: point2
11106
+ point
10673
11107
  };
10674
11108
  }
10675
11109
  }
@@ -10699,13 +11133,13 @@ var getHeadingForElbowArrowSnap = (p, otherPoint, bindableElement, aabb, element
10699
11133
  if (!bindableElement || !aabb) {
10700
11134
  return otherPointHeading;
10701
11135
  }
10702
- const distance3 = getDistanceForBinding(
11136
+ const distance2 = getDistanceForBinding(
10703
11137
  origPoint,
10704
11138
  bindableElement,
10705
11139
  elementsMap,
10706
11140
  zoom
10707
11141
  );
10708
- if (!distance3) {
11142
+ if (!distance2) {
10709
11143
  return vectorToHeading(
10710
11144
  vectorFromPoint(
10711
11145
  p,
@@ -10718,49 +11152,57 @@ var getHeadingForElbowArrowSnap = (p, otherPoint, bindableElement, aabb, element
10718
11152
  }
10719
11153
  return headingForPointFromElement(bindableElement, aabb, p);
10720
11154
  };
10721
- var getDistanceForBinding = (point2, bindableElement, elementsMap, zoom) => {
10722
- const distance3 = distanceToBindableElement(
10723
- bindableElement,
10724
- point2,
10725
- elementsMap
10726
- );
11155
+ var getDistanceForBinding = (point, bindableElement, elementsMap, zoom) => {
11156
+ const distance2 = distanceToBindableElement(bindableElement, point);
10727
11157
  const bindDistance = maxBindingGap(
10728
11158
  bindableElement,
10729
11159
  bindableElement.width,
10730
11160
  bindableElement.height,
10731
11161
  zoom
10732
11162
  );
10733
- return distance3 > bindDistance ? null : distance3;
11163
+ return distance2 > bindDistance ? null : distance2;
10734
11164
  };
10735
- var bindPointToSnapToElementOutline = (p, otherPoint, bindableElement, elementsMap) => {
11165
+ var bindPointToSnapToElementOutline = (arrow, bindableElement, startOrEnd) => {
10736
11166
  const aabb = bindableElement && aabbForElement(bindableElement);
11167
+ const localP = arrow.points[startOrEnd === "start" ? 0 : arrow.points.length - 1];
11168
+ const globalP = pointFrom(
11169
+ arrow.x + localP[0],
11170
+ arrow.y + localP[1]
11171
+ );
11172
+ const p = isRectanguloidElement(bindableElement) ? avoidRectangularCorner(bindableElement, globalP) : globalP;
10737
11173
  if (bindableElement && aabb) {
10738
- const heading = headingForPointFromElement(bindableElement, aabb, p);
10739
- const intersections = [
10740
- ...intersectElementWithLine(
10741
- bindableElement,
10742
- pointFrom(p[0], p[1] - 2 * bindableElement.height),
10743
- pointFrom(p[0], p[1] + 2 * bindableElement.height),
10744
- FIXED_BINDING_DISTANCE,
10745
- elementsMap
10746
- ) ?? [],
10747
- ...intersectElementWithLine(
10748
- bindableElement,
10749
- pointFrom(p[0] - 2 * bindableElement.width, p[1]),
10750
- pointFrom(p[0] + 2 * bindableElement.width, p[1]),
10751
- FIXED_BINDING_DISTANCE,
10752
- elementsMap
10753
- ) ?? []
10754
- ];
10755
- const isVertical = compareHeading(heading, HEADING_LEFT) || compareHeading(heading, HEADING_RIGHT);
10756
- const dist = Math.abs(
10757
- distanceToBindableElement(bindableElement, p, elementsMap)
10758
- );
10759
- const isInner = isVertical ? dist < bindableElement.width * -0.1 : dist < bindableElement.height * -0.1;
10760
- intersections.sort((a, b) => pointDistanceSq(a, p) - pointDistanceSq(b, p));
10761
- return isInner ? headingToMidBindPoint(otherPoint, bindableElement, aabb) : intersections.filter(
10762
- (i) => isVertical ? Math.abs(p[1] - i[1]) < 0.1 : Math.abs(p[0] - i[0]) < 0.1
10763
- )[0] ?? p;
11174
+ const center = getCenterForBounds(aabb);
11175
+ const intersection = intersectElementWithLineSegment(
11176
+ bindableElement,
11177
+ lineSegment(
11178
+ center,
11179
+ pointFromVector(
11180
+ vectorScale(
11181
+ vectorNormalize(vectorFromPoint(p, center)),
11182
+ Math.max(bindableElement.width, bindableElement.height)
11183
+ ),
11184
+ center
11185
+ )
11186
+ )
11187
+ )[0];
11188
+ const currentDistance = pointDistance(p, center);
11189
+ const fullDistance = pointDistance(intersection, center);
11190
+ const ratio = currentDistance / fullDistance;
11191
+ switch (true) {
11192
+ case ratio > 0.9:
11193
+ if (currentDistance - fullDistance > FIXED_BINDING_DISTANCE) {
11194
+ return p;
11195
+ }
11196
+ return pointFromVector(
11197
+ vectorScale(
11198
+ vectorNormalize(vectorFromPoint(p, intersection)),
11199
+ ratio > 1 ? FIXED_BINDING_DISTANCE : -FIXED_BINDING_DISTANCE
11200
+ ),
11201
+ intersection
11202
+ );
11203
+ default:
11204
+ return headingToMidBindPoint(p, bindableElement, aabb);
11205
+ }
10764
11206
  }
10765
11207
  return p;
10766
11208
  };
@@ -10945,24 +11387,44 @@ var updateBoundPoint = (linearElement, startOrEnd, binding, bindableElement, ele
10945
11387
  const focusPointAbsolute = determineFocusPoint(
10946
11388
  bindableElement,
10947
11389
  binding.focus,
10948
- adjacentPoint,
10949
- elementsMap
11390
+ adjacentPoint
10950
11391
  );
10951
11392
  let newEdgePoint;
10952
11393
  if (binding.gap === 0) {
10953
11394
  newEdgePoint = focusPointAbsolute;
10954
11395
  } else {
10955
- const intersections = intersectElementWithLine(
10956
- bindableElement,
10957
- adjacentPoint,
10958
- focusPointAbsolute,
10959
- binding.gap,
11396
+ const edgePointAbsolute = LinearElementEditor.getPointAtIndexGlobalCoordinates(
11397
+ linearElement,
11398
+ edgePointIndex,
10960
11399
  elementsMap
10961
11400
  );
10962
- if (!intersections || intersections.length === 0) {
11401
+ const center = pointFrom(
11402
+ bindableElement.x + bindableElement.width / 2,
11403
+ bindableElement.y + bindableElement.height / 2
11404
+ );
11405
+ const interceptorLength = pointDistance(adjacentPoint, edgePointAbsolute) + pointDistance(adjacentPoint, center) + Math.max(bindableElement.width, bindableElement.height) * 2;
11406
+ const intersections = intersectElementWithLineSegment(
11407
+ bindableElement,
11408
+ lineSegment(
11409
+ adjacentPoint,
11410
+ pointFromVector(
11411
+ vectorScale(
11412
+ vectorNormalize(vectorFromPoint(focusPointAbsolute, adjacentPoint)),
11413
+ interceptorLength
11414
+ ),
11415
+ adjacentPoint
11416
+ )
11417
+ ),
11418
+ binding.gap
11419
+ ).sort(
11420
+ (g, h) => pointDistanceSq(g, adjacentPoint) - pointDistanceSq(h, adjacentPoint)
11421
+ );
11422
+ if (intersections.length > 1) {
11423
+ newEdgePoint = intersections[0];
11424
+ } else if (intersections.length === 1) {
10963
11425
  newEdgePoint = focusPointAbsolute;
10964
11426
  } else {
10965
- newEdgePoint = intersections[0];
11427
+ newEdgePoint = edgePointAbsolute;
10966
11428
  }
10967
11429
  }
10968
11430
  return LinearElementEditor.pointFromAbsoluteCoords(
@@ -10978,22 +11440,10 @@ var calculateFixedPointForElbowArrowBinding = (linearElement, hoveredElement, st
10978
11440
  hoveredElement.x + hoveredElement.width,
10979
11441
  hoveredElement.y + hoveredElement.height
10980
11442
  ];
10981
- const edgePointIndex = startOrEnd === "start" ? 0 : linearElement.points.length - 1;
10982
- const globalPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
10983
- linearElement,
10984
- edgePointIndex,
10985
- elementsMap
10986
- );
10987
- const otherGlobalPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
10988
- linearElement,
10989
- edgePointIndex,
10990
- elementsMap
10991
- );
10992
11443
  const snappedPoint = bindPointToSnapToElementOutline(
10993
- globalPoint,
10994
- otherGlobalPoint,
11444
+ linearElement,
10995
11445
  hoveredElement,
10996
- elementsMap
11446
+ startOrEnd
10997
11447
  );
10998
11448
  const globalMidPoint = pointFrom(
10999
11449
  bounds[0] + (bounds[2] - bounds[0]) / 2,
@@ -11157,347 +11607,193 @@ var maxBindingGap = (element, elementWidth, elementHeight, zoom) => {
11157
11607
  BINDING_HIGHLIGHT_THICKNESS / zoomValue + BINDING_HIGHLIGHT_OFFSET
11158
11608
  );
11159
11609
  };
11160
- var distanceToBindableElement = (element, point2, elementsMap) => {
11161
- switch (element.type) {
11162
- case "rectangle":
11163
- case "image":
11164
- case "text":
11165
- case "iframe":
11166
- case "embeddable":
11167
- case "frame":
11168
- case "magicframe":
11169
- return distanceToRectangle(element, point2, elementsMap);
11170
- case "diamond":
11171
- return distanceToDiamond(element, point2, elementsMap);
11172
- case "ellipse":
11173
- return distanceToEllipse2(element, point2, elementsMap);
11174
- }
11175
- };
11176
- var distanceToRectangle = (element, p, elementsMap) => {
11177
- const [, pointRel, hwidth, hheight] = pointRelativeToElement(
11178
- element,
11179
- p,
11180
- elementsMap
11181
- );
11182
- return Math.max(
11183
- distanceToLine(pointRel, equation(0, 1, -hheight)),
11184
- distanceToLine(pointRel, equation(1, 0, -hwidth))
11185
- );
11186
- };
11187
- var distanceToDiamond = (element, point2, elementsMap) => {
11188
- const [, pointRel, hwidth, hheight] = pointRelativeToElement(
11189
- element,
11190
- point2,
11191
- elementsMap
11192
- );
11193
- const side = equation(hheight, hwidth, -hheight * hwidth);
11194
- return distanceToLine(pointRel, side);
11195
- };
11196
- var distanceToEllipse2 = (element, point2, elementsMap) => {
11197
- const [pointRel, tangent] = ellipseParamsForTest(element, point2, elementsMap);
11198
- return -sign(tangent) * distanceToLine(pointRel, tangent);
11199
- };
11200
- var ellipseParamsForTest = (element, point2, elementsMap) => {
11201
- const [, pointRel, hwidth, hheight] = pointRelativeToElement(
11202
- element,
11203
- point2,
11204
- elementsMap
11205
- );
11206
- const [px, py] = toTuple(pointRel);
11207
- let tx = 0.707;
11208
- let ty = 0.707;
11209
- const a = hwidth;
11210
- const b = hheight;
11211
- [0, 1, 2, 3].forEach((_) => {
11212
- const xx = a * tx;
11213
- const yy = b * ty;
11214
- const ex = (a * a - b * b) * tx ** 3 / a;
11215
- const ey = (b * b - a * a) * ty ** 3 / b;
11216
- const rx = xx - ex;
11217
- const ry = yy - ey;
11218
- const qx = px - ex;
11219
- const qy = py - ey;
11220
- const r = Math.hypot(ry, rx);
11221
- const q = Math.hypot(qy, qx);
11222
- tx = Math.min(1, Math.max(0, (qx * r / q + ex) / a));
11223
- ty = Math.min(1, Math.max(0, (qy * r / q + ey) / b));
11224
- const t = Math.hypot(ty, tx);
11225
- tx /= t;
11226
- ty /= t;
11227
- });
11228
- const closestPoint = point(a * tx, b * ty);
11229
- const tangent = orthogonalThrough(pointRel, closestPoint);
11230
- return [pointRel, tangent];
11231
- };
11232
- var pointRelativeToElement = (element, pointTuple, elementsMap) => {
11233
- const point2 = from(pointTuple);
11234
- const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
11235
- const center = coordsCenter(x1, y1, x2, y2);
11236
- const rotate = rotation(center, element.angle);
11237
- const pointRotated = apply(rotate, point2);
11238
- const pointRelToCenter = sub(pointRotated, from2(center));
11239
- const pointRelToCenterAbs = abs(pointRelToCenter);
11240
- const elementPos = offset(element.x, element.y);
11241
- const pointRelToPos = sub(pointRotated, elementPos);
11242
- const halfWidth = (x2 - x1) / 2;
11243
- const halfHeight = (y2 - y1) / 2;
11244
- return [pointRelToPos, pointRelToCenterAbs, halfWidth, halfHeight];
11245
- };
11246
- var relativizationToElementCenter = (element, elementsMap) => {
11247
- const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
11248
- const center = coordsCenter(x1, y1, x2, y2);
11249
- const rotate = rotation(center, element.angle);
11250
- const translate = reverse(
11251
- translation(from2(center))
11252
- );
11253
- return compose(rotate, translate);
11254
- };
11255
- var coordsCenter = (x1, y1, x2, y2) => {
11256
- return point((x1 + x2) / 2, (y1 + y2) / 2);
11257
- };
11258
- var determineFocusDistance = (element, a, b, elementsMap) => {
11259
- const relateToCenter = relativizationToElementCenter(element, elementsMap);
11260
- const aRel = apply(relateToCenter, from(a));
11261
- const bRel = apply(relateToCenter, from(b));
11262
- const line = through(aRel, bRel);
11263
- const q = element.height / element.width;
11264
- const hwidth = element.width / 2;
11265
- const hheight = element.height / 2;
11266
- const n = line[2];
11267
- const m = line[3];
11268
- const c = line[1];
11269
- const mabs = Math.abs(m);
11270
- const nabs = Math.abs(n);
11271
- let ret;
11272
- switch (element.type) {
11273
- case "rectangle":
11274
- case "image":
11275
- case "text":
11276
- case "iframe":
11277
- case "embeddable":
11278
- case "frame":
11279
- case "magicframe":
11280
- ret = c / (hwidth * (nabs + q * mabs));
11281
- break;
11282
- case "diamond":
11283
- ret = mabs < nabs ? c / (nabs * hwidth) : c / (mabs * hheight);
11284
- break;
11285
- case "ellipse":
11286
- ret = c / (hwidth * Math.sqrt(n ** 2 + q ** 2 * m ** 2));
11287
- break;
11288
- }
11289
- return ret || 0;
11290
- };
11291
- var determineFocusPoint = (element, focus, adjecentPoint, elementsMap) => {
11292
- if (focus === 0) {
11293
- const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
11294
- const center = coordsCenter(x1, y1, x2, y2);
11295
- return pointFromPair(toTuple(center));
11296
- }
11297
- const relateToCenter = relativizationToElementCenter(element, elementsMap);
11298
- const adjecentPointRel = apply(
11299
- relateToCenter,
11300
- from(adjecentPoint)
11301
- );
11302
- const reverseRelateToCenter = reverse(relateToCenter);
11303
- let point2;
11304
- switch (element.type) {
11305
- case "rectangle":
11306
- case "image":
11307
- case "text":
11308
- case "diamond":
11309
- case "iframe":
11310
- case "embeddable":
11311
- case "frame":
11312
- case "magicframe":
11313
- point2 = findFocusPointForRectangulars(element, focus, adjecentPointRel);
11314
- break;
11315
- case "ellipse":
11316
- point2 = findFocusPointForEllipse(element, focus, adjecentPointRel);
11317
- break;
11318
- }
11319
- return pointFromPair(
11320
- toTuple(apply(reverseRelateToCenter, point2))
11610
+ var determineFocusDistance = (element, a, b) => {
11611
+ const center = pointFrom(
11612
+ element.x + element.width / 2,
11613
+ element.y + element.height / 2
11321
11614
  );
11322
- };
11323
- var intersectElementWithLine = (element, a, b, gap = 0, elementsMap) => {
11324
- if (isRectangularElement(element)) {
11325
- return segmentIntersectRectangleElement(element, lineSegment(a, b), gap);
11615
+ if (pointsEqual(a, b)) {
11616
+ return 0;
11326
11617
  }
11327
- const relateToCenter = relativizationToElementCenter(element, elementsMap);
11328
- const aRel = apply(relateToCenter, from(a));
11329
- const bRel = apply(relateToCenter, from(b));
11330
- const line = through(aRel, bRel);
11331
- const reverseRelateToCenter = reverse(relateToCenter);
11332
- const intersections = getSortedElementLineIntersections(
11333
- element,
11334
- line,
11335
- aRel,
11336
- gap
11337
- );
11338
- return intersections.map(
11339
- (point2) => pointFromPair(
11340
- toTuple(apply(reverseRelateToCenter, point2))
11618
+ const rotatedA = pointRotateRads(a, center, -element.angle);
11619
+ const rotatedB = pointRotateRads(b, center, -element.angle);
11620
+ const sign = Math.sign(
11621
+ vectorCross(
11622
+ vectorFromPoint(rotatedB, a),
11623
+ vectorFromPoint(rotatedB, center)
11624
+ )
11625
+ ) * -1;
11626
+ const rotatedInterceptor = lineSegment(
11627
+ rotatedB,
11628
+ pointFromVector(
11629
+ vectorScale(
11630
+ vectorNormalize(vectorFromPoint(rotatedB, rotatedA)),
11631
+ Math.max(element.width * 2, element.height * 2)
11632
+ ),
11633
+ rotatedB
11341
11634
  )
11342
- // pointFromArray(
11343
- // ,
11344
- // ),
11345
- );
11346
- };
11347
- var getSortedElementLineIntersections = (element, line, nearPoint, gap = 0) => {
11348
- let intersections;
11349
- switch (element.type) {
11350
- case "rectangle":
11351
- case "image":
11352
- case "text":
11353
- case "diamond":
11354
- case "iframe":
11355
- case "embeddable":
11356
- case "frame":
11357
- case "magicframe":
11358
- const corners = getCorners(element);
11359
- intersections = corners.flatMap((point2, i) => {
11360
- const edge = [point2, corners[(i + 1) % 4]];
11361
- return intersectSegment(line, offsetSegment(edge, gap));
11362
- }).concat(
11363
- corners.flatMap((point2) => getCircleIntersections(point2, gap, line))
11364
- );
11365
- break;
11366
- case "ellipse":
11367
- intersections = getEllipseIntersections(element, gap, line);
11368
- break;
11369
- }
11370
- if (intersections.length < 2) {
11371
- return [];
11372
- }
11373
- const sortedIntersections = intersections.sort(
11374
- (i1, i2) => distance2(i1, nearPoint) - distance2(i2, nearPoint)
11375
11635
  );
11376
- return [
11377
- sortedIntersections[0],
11378
- sortedIntersections[sortedIntersections.length - 1]
11636
+ const axes = element.type === "diamond" ? [
11637
+ lineSegment(
11638
+ pointFrom(element.x + element.width / 2, element.y),
11639
+ pointFrom(
11640
+ element.x + element.width / 2,
11641
+ element.y + element.height
11642
+ )
11643
+ ),
11644
+ lineSegment(
11645
+ pointFrom(element.x, element.y + element.height / 2),
11646
+ pointFrom(
11647
+ element.x + element.width,
11648
+ element.y + element.height / 2
11649
+ )
11650
+ )
11651
+ ] : [
11652
+ lineSegment(
11653
+ pointFrom(element.x, element.y),
11654
+ pointFrom(
11655
+ element.x + element.width,
11656
+ element.y + element.height
11657
+ )
11658
+ ),
11659
+ lineSegment(
11660
+ pointFrom(element.x + element.width, element.y),
11661
+ pointFrom(element.x, element.y + element.height)
11662
+ )
11379
11663
  ];
11380
- };
11381
- var getCorners = (element, scale = 1) => {
11382
- const hx = scale * element.width / 2;
11383
- const hy = scale * element.height / 2;
11384
- switch (element.type) {
11385
- case "rectangle":
11386
- case "image":
11387
- case "text":
11388
- case "iframe":
11389
- case "embeddable":
11390
- case "frame":
11391
- case "magicframe":
11392
- return [
11393
- point(hx, hy),
11394
- point(hx, -hy),
11395
- point(-hx, -hy),
11396
- point(-hx, hy)
11397
- ];
11398
- case "diamond":
11399
- return [
11400
- point(0, hy),
11401
- point(hx, 0),
11402
- point(0, -hy),
11403
- point(-hx, 0)
11404
- ];
11405
- }
11406
- };
11407
- var intersectSegment = (line, segment) => {
11408
- const [a, b] = segment;
11409
- const aDist = distanceToLine(a, line);
11410
- const bDist = distanceToLine(b, line);
11411
- if (aDist * bDist >= 0) {
11412
- return [];
11413
- }
11414
- return [intersect(line, through(a, b))];
11415
- };
11416
- var offsetSegment = (segment, distance3) => {
11417
- const [a, b] = segment;
11418
- const offset2 = translationOrthogonal(
11419
- fromTo(a, b),
11420
- distance3
11421
- );
11422
- return [apply(offset2, a), apply(offset2, b)];
11423
- };
11424
- var getEllipseIntersections = (element, gap, line) => {
11425
- const a = element.width / 2 + gap;
11426
- const b = element.height / 2 + gap;
11427
- const m = line[2];
11428
- const n = line[3];
11429
- const c = line[1];
11430
- const squares = a * a * m * m + b * b * n * n;
11431
- const discr = squares - c * c;
11432
- if (squares === 0 || discr <= 0) {
11433
- return [];
11434
- }
11435
- const discrRoot = Math.sqrt(discr);
11436
- const xn = -a * a * m * c;
11437
- const yn = -b * b * n * c;
11438
- return [
11439
- point(
11440
- (xn + a * b * n * discrRoot) / squares,
11441
- (yn - a * b * m * discrRoot) / squares
11664
+ const interceptees = element.type === "diamond" ? [
11665
+ lineSegment(
11666
+ pointFrom(
11667
+ element.x + element.width / 2,
11668
+ element.y - element.height
11669
+ ),
11670
+ pointFrom(
11671
+ element.x + element.width / 2,
11672
+ element.y + element.height * 2
11673
+ )
11674
+ ),
11675
+ lineSegment(
11676
+ pointFrom(
11677
+ element.x - element.width,
11678
+ element.y + element.height / 2
11679
+ ),
11680
+ pointFrom(
11681
+ element.x + element.width * 2,
11682
+ element.y + element.height / 2
11683
+ )
11684
+ )
11685
+ ] : [
11686
+ lineSegment(
11687
+ pointFrom(
11688
+ element.x - element.width,
11689
+ element.y - element.height
11690
+ ),
11691
+ pointFrom(
11692
+ element.x + element.width * 2,
11693
+ element.y + element.height * 2
11694
+ )
11442
11695
  ),
11443
- point(
11444
- (xn - a * b * n * discrRoot) / squares,
11445
- (yn + a * b * m * discrRoot) / squares
11696
+ lineSegment(
11697
+ pointFrom(
11698
+ element.x + element.width * 2,
11699
+ element.y - element.height
11700
+ ),
11701
+ pointFrom(
11702
+ element.x - element.width,
11703
+ element.y + element.height * 2
11704
+ )
11446
11705
  )
11447
11706
  ];
11448
- };
11449
- var getCircleIntersections = (center, radius, line) => {
11450
- if (radius === 0) {
11451
- return distanceToLine(line, center) === 0 ? [center] : [];
11452
- }
11453
- const m = line[2];
11454
- const n = line[3];
11455
- const c = line[1];
11456
- const [a, b] = toTuple(center);
11457
- const r = radius;
11458
- const squares = m * m + n * n;
11459
- const discr = r * r * squares - (m * a + n * b + c) ** 2;
11460
- if (squares === 0 || discr <= 0) {
11461
- return [];
11707
+ const ordered = [
11708
+ lineSegmentIntersectionPoints(rotatedInterceptor, interceptees[0]),
11709
+ lineSegmentIntersectionPoints(rotatedInterceptor, interceptees[1])
11710
+ ].filter((p) => p !== null).sort((g, h) => pointDistanceSq(g, b) - pointDistanceSq(h, b)).map(
11711
+ (p, idx) => sign * pointDistance(center, p) / (element.type === "diamond" ? pointDistance(axes[idx][0], axes[idx][1]) / 2 : Math.sqrt(element.width ** 2 + element.height ** 2) / 2)
11712
+ ).sort((g, h) => Math.abs(g) - Math.abs(h));
11713
+ const signedDistanceRatio = ordered[0] ?? 0;
11714
+ return signedDistanceRatio;
11715
+ };
11716
+ var determineFocusPoint = (element, focus, adjacentPoint) => {
11717
+ const center = pointFrom(
11718
+ element.x + element.width / 2,
11719
+ element.y + element.height / 2
11720
+ );
11721
+ if (focus === 0) {
11722
+ return center;
11462
11723
  }
11463
- const discrRoot = Math.sqrt(discr);
11464
- const xn = a * n * n - b * m * n - m * c;
11465
- const yn = b * m * m - a * m * n - n * c;
11466
- return [
11467
- point((xn + n * discrRoot) / squares, (yn - m * discrRoot) / squares),
11468
- point((xn - n * discrRoot) / squares, (yn + m * discrRoot) / squares)
11724
+ const candidates = (element.type === "diamond" ? [
11725
+ pointFrom(element.x, element.y + element.height / 2),
11726
+ pointFrom(element.x + element.width / 2, element.y),
11727
+ pointFrom(
11728
+ element.x + element.width,
11729
+ element.y + element.height / 2
11730
+ ),
11731
+ pointFrom(
11732
+ element.x + element.width / 2,
11733
+ element.y + element.height
11734
+ )
11735
+ ] : [
11736
+ pointFrom(element.x, element.y),
11737
+ pointFrom(element.x + element.width, element.y),
11738
+ pointFrom(
11739
+ element.x + element.width,
11740
+ element.y + element.height
11741
+ ),
11742
+ pointFrom(element.x, element.y + element.height)
11743
+ ]).map(
11744
+ (p) => pointFromVector(
11745
+ vectorScale(vectorFromPoint(p, center), Math.abs(focus)),
11746
+ center
11747
+ )
11748
+ ).map((p) => pointRotateRads(p, center, element.angle));
11749
+ const selected = [
11750
+ vectorCross(
11751
+ vectorFromPoint(adjacentPoint, candidates[0]),
11752
+ vectorFromPoint(candidates[1], candidates[0])
11753
+ ) > 0 && // TOP
11754
+ (focus > 0 ? vectorCross(
11755
+ vectorFromPoint(adjacentPoint, candidates[1]),
11756
+ vectorFromPoint(candidates[2], candidates[1])
11757
+ ) < 0 : vectorCross(
11758
+ vectorFromPoint(adjacentPoint, candidates[3]),
11759
+ vectorFromPoint(candidates[0], candidates[3])
11760
+ ) < 0),
11761
+ vectorCross(
11762
+ vectorFromPoint(adjacentPoint, candidates[1]),
11763
+ vectorFromPoint(candidates[2], candidates[1])
11764
+ ) > 0 && // RIGHT
11765
+ (focus > 0 ? vectorCross(
11766
+ vectorFromPoint(adjacentPoint, candidates[2]),
11767
+ vectorFromPoint(candidates[3], candidates[2])
11768
+ ) < 0 : vectorCross(
11769
+ vectorFromPoint(adjacentPoint, candidates[0]),
11770
+ vectorFromPoint(candidates[1], candidates[0])
11771
+ ) < 0),
11772
+ vectorCross(
11773
+ vectorFromPoint(adjacentPoint, candidates[2]),
11774
+ vectorFromPoint(candidates[3], candidates[2])
11775
+ ) > 0 && // BOTTOM
11776
+ (focus > 0 ? vectorCross(
11777
+ vectorFromPoint(adjacentPoint, candidates[3]),
11778
+ vectorFromPoint(candidates[0], candidates[3])
11779
+ ) < 0 : vectorCross(
11780
+ vectorFromPoint(adjacentPoint, candidates[1]),
11781
+ vectorFromPoint(candidates[2], candidates[1])
11782
+ ) < 0),
11783
+ vectorCross(
11784
+ vectorFromPoint(adjacentPoint, candidates[3]),
11785
+ vectorFromPoint(candidates[0], candidates[3])
11786
+ ) > 0 && // LEFT
11787
+ (focus > 0 ? vectorCross(
11788
+ vectorFromPoint(adjacentPoint, candidates[0]),
11789
+ vectorFromPoint(candidates[1], candidates[0])
11790
+ ) < 0 : vectorCross(
11791
+ vectorFromPoint(adjacentPoint, candidates[2]),
11792
+ vectorFromPoint(candidates[3], candidates[2])
11793
+ ) < 0)
11469
11794
  ];
11470
- };
11471
- var findFocusPointForEllipse = (ellipse, relativeDistance, point2) => {
11472
- const relativeDistanceAbs = Math.abs(relativeDistance);
11473
- const a = ellipse.width * relativeDistanceAbs / 2;
11474
- const b = ellipse.height * relativeDistanceAbs / 2;
11475
- const orientation = Math.sign(relativeDistance);
11476
- const [px, pyo] = toTuple(point2);
11477
- const py = pyo === 0 ? 1e-4 : pyo;
11478
- const squares = px ** 2 * b ** 2 + py ** 2 * a ** 2;
11479
- const m = (-px * b ** 2 + orientation * py * Math.sqrt(Math.max(0, squares - a ** 2 * b ** 2))) / squares;
11480
- let n = (-m * px - 1) / py;
11481
- if (n === 0) {
11482
- n = (Object.is(n, -0) ? -1 : 1) * 0.01;
11483
- }
11484
- const x = -(a ** 2 * m) / (n ** 2 * b ** 2 + m ** 2 * a ** 2);
11485
- return point(x, (-m * x - 1) / n);
11486
- };
11487
- var findFocusPointForRectangulars = (element, relativeDistance, point2) => {
11488
- const relativeDistanceAbs = Math.abs(relativeDistance);
11489
- const orientation = Math.sign(relativeDistance);
11490
- const corners = getCorners(element, relativeDistanceAbs);
11491
- let maxDistance = 0;
11492
- let tangentPoint = null;
11493
- corners.forEach((corner) => {
11494
- const distance3 = orientation * through(point2, corner)[1];
11495
- if (distance3 > maxDistance) {
11496
- maxDistance = distance3;
11497
- tangentPoint = corner;
11498
- }
11499
- });
11500
- return tangentPoint;
11795
+ const focusPoint = selected[0] ? focus > 0 ? candidates[1] : candidates[0] : selected[1] ? focus > 0 ? candidates[2] : candidates[1] : selected[2] ? focus > 0 ? candidates[3] : candidates[2] : focus > 0 ? candidates[0] : candidates[3];
11796
+ return focusPoint;
11501
11797
  };
11502
11798
  var bindingProperties = /* @__PURE__ */ new Set([
11503
11799
  "boundElements",
@@ -12530,10 +12826,10 @@ var round2 = (x) => {
12530
12826
  };
12531
12827
  var dedupePoints = (points) => {
12532
12828
  const map = /* @__PURE__ */ new Map();
12533
- for (const point2 of points) {
12534
- const key = point2.join(",");
12829
+ for (const point of points) {
12830
+ const key = point.join(",");
12535
12831
  if (!map.has(key)) {
12536
- map.set(key, point2);
12832
+ map.set(key, point);
12537
12833
  }
12538
12834
  }
12539
12835
  return Array.from(map.values());
@@ -12596,7 +12892,7 @@ var createPointSnapLines = (nearestSnapsX, nearestSnapsY) => {
12596
12892
  var dedupeGapSnapLines = (gapSnapLines) => {
12597
12893
  const map = /* @__PURE__ */ new Map();
12598
12894
  for (const gapSnapLine of gapSnapLines) {
12599
- const key = gapSnapLine.points.flat().map((point2) => [round2(point2)]).join(",");
12895
+ const key = gapSnapLine.points.flat().map((point) => [round2(point)]).join(",");
12600
12896
  if (!map.has(key)) {
12601
12897
  map.set(key, gapSnapLine);
12602
12898
  }
@@ -13068,8 +13364,8 @@ var _LinearElementEditor = class _LinearElementEditor {
13068
13364
  element,
13069
13365
  elementsMap
13070
13366
  );
13071
- const nextSelectedPoints = pointsSceneCoords.reduce((acc, point2, index) => {
13072
- if (point2[0] >= selectionX1 && point2[0] <= selectionX2 && point2[1] >= selectionY1 && point2[1] <= selectionY2 || event.shiftKey && selectedPointsIndices?.includes(index)) {
13367
+ const nextSelectedPoints = pointsSceneCoords.reduce((acc, point, index) => {
13368
+ if (point[0] >= selectionX1 && point[0] <= selectionX2 && point[1] >= selectionY1 && point[1] <= selectionY2 || event.shiftKey && selectedPointsIndices?.includes(index)) {
13073
13369
  acc.push(index);
13074
13370
  }
13075
13371
  return acc;
@@ -13258,11 +13554,11 @@ var _LinearElementEditor = class _LinearElementEditor {
13258
13554
  }
13259
13555
  return false;
13260
13556
  }
13261
- let distance3 = pointDistance(startPoint, endPoint);
13557
+ let distance2 = pointDistance(startPoint, endPoint);
13262
13558
  if (element.points.length > 2 && element.roundness) {
13263
- distance3 = getBezierCurveLength(element, endPoint);
13559
+ distance2 = getBezierCurveLength(element, endPoint);
13264
13560
  }
13265
- return distance3 * zoom.value < _LinearElementEditor.POINT_HANDLE_SIZE * 4;
13561
+ return distance2 * zoom.value < _LinearElementEditor.POINT_HANDLE_SIZE * 4;
13266
13562
  }
13267
13563
  static getSegmentMidPoint(element, startPoint, endPoint, endPointIndex, elementsMap) {
13268
13564
  let segmentMidPoint = pointCenter(startPoint, endPoint);
@@ -13677,7 +13973,7 @@ var _LinearElementEditor = class _LinearElementEditor {
13677
13973
  let offsetY = 0;
13678
13974
  const isDeletingOriginPoint = pointIndices.includes(0);
13679
13975
  if (isDeletingOriginPoint) {
13680
- const firstNonDeletedPoint = element.points.find((point2, idx) => {
13976
+ const firstNonDeletedPoint = element.points.find((point, idx) => {
13681
13977
  return !pointIndices.includes(idx);
13682
13978
  });
13683
13979
  if (firstNonDeletedPoint) {
@@ -13907,23 +14203,23 @@ var _LinearElementEditor = class _LinearElementEditor {
13907
14203
  const nextFixedSegments = Object.values(fixedSegments).sort(
13908
14204
  (a, b) => a.index - b.index
13909
14205
  );
13910
- const offset2 = nextFixedSegments.map((segment) => segment.index).reduce((count, idx) => idx < index ? count + 1 : count, 0);
14206
+ const offset = nextFixedSegments.map((segment) => segment.index).reduce((count, idx) => idx < index ? count + 1 : count, 0);
13911
14207
  mutateElement(element, {
13912
14208
  fixedSegments: nextFixedSegments
13913
14209
  });
13914
- const point2 = pointFrom(
13915
- element.x + (element.fixedSegments[offset2].start[0] + element.fixedSegments[offset2].end[0]) / 2,
13916
- element.y + (element.fixedSegments[offset2].start[1] + element.fixedSegments[offset2].end[1]) / 2
14210
+ const point = pointFrom(
14211
+ element.x + (element.fixedSegments[offset].start[0] + element.fixedSegments[offset].end[0]) / 2,
14212
+ element.y + (element.fixedSegments[offset].start[1] + element.fixedSegments[offset].end[1]) / 2
13917
14213
  );
13918
14214
  return {
13919
14215
  ...linearElement,
13920
- segmentMidPointHoveredCoords: point2,
14216
+ segmentMidPointHoveredCoords: point,
13921
14217
  pointerDownState: {
13922
14218
  ...linearElement.pointerDownState,
13923
14219
  segmentMidpoint: {
13924
14220
  added: false,
13925
- index: element.fixedSegments[offset2].index,
13926
- value: point2
14221
+ index: element.fixedSegments[offset].index,
14222
+ value: point
13927
14223
  }
13928
14224
  }
13929
14225
  };
@@ -14017,14 +14313,14 @@ __publicField(_LinearElementEditor, "getSegmentMidpointHitCoords", (linearElemen
14017
14313
  const threshold = (_LinearElementEditor.POINT_HANDLE_SIZE + 1) / appState.zoom.value;
14018
14314
  const existingSegmentMidpointHitCoords = linearElementEditor.segmentMidPointHoveredCoords;
14019
14315
  if (existingSegmentMidpointHitCoords) {
14020
- const distance3 = pointDistance(
14316
+ const distance2 = pointDistance(
14021
14317
  pointFrom(
14022
14318
  existingSegmentMidpointHitCoords[0],
14023
14319
  existingSegmentMidpointHitCoords[1]
14024
14320
  ),
14025
14321
  pointFrom(scenePointer.x, scenePointer.y)
14026
14322
  );
14027
- if (distance3 <= threshold) {
14323
+ if (distance2 <= threshold) {
14028
14324
  return existingSegmentMidpointHitCoords;
14029
14325
  }
14030
14326
  }
@@ -14032,11 +14328,11 @@ __publicField(_LinearElementEditor, "getSegmentMidpointHitCoords", (linearElemen
14032
14328
  const midPoints = _LinearElementEditor.getEditorMidPoints(element, elementsMap, appState);
14033
14329
  while (index < midPoints.length) {
14034
14330
  if (midPoints[index] !== null) {
14035
- const distance3 = pointDistance(
14331
+ const distance2 = pointDistance(
14036
14332
  midPoints[index],
14037
14333
  pointFrom(scenePointer.x, scenePointer.y)
14038
14334
  );
14039
- if (distance3 <= threshold) {
14335
+ if (distance2 <= threshold) {
14040
14336
  return midPoints[index];
14041
14337
  }
14042
14338
  }
@@ -15552,23 +15848,23 @@ var Delta = class _Delta {
15552
15848
  *
15553
15849
  * WARN: it's based on shallow compare performed only on the first level and doesn't go deeper than that.
15554
15850
  */
15555
- static *distinctKeysIterator(join2, object1, object2, skipShallowCompare = false) {
15851
+ static *distinctKeysIterator(join, object1, object2, skipShallowCompare = false) {
15556
15852
  if (object1 === object2) {
15557
15853
  return;
15558
15854
  }
15559
15855
  let keys = [];
15560
- if (join2 === "left") {
15856
+ if (join === "left") {
15561
15857
  keys = Object.keys(object1);
15562
- } else if (join2 === "right") {
15858
+ } else if (join === "right") {
15563
15859
  keys = Object.keys(object2);
15564
- } else if (join2 === "full") {
15860
+ } else if (join === "full") {
15565
15861
  keys = Array.from(
15566
15862
  /* @__PURE__ */ new Set([...Object.keys(object1), ...Object.keys(object2)])
15567
15863
  );
15568
15864
  } else {
15569
15865
  assertNever(
15570
- join2,
15571
- `Unknown distinctKeysIterator's join param "${join2}"`,
15866
+ join,
15867
+ `Unknown distinctKeysIterator's join param "${join}"`,
15572
15868
  true
15573
15869
  );
15574
15870
  }
@@ -17019,7 +17315,7 @@ var maybeWrapNodesInFrameClipPath = (element, root, nodes, frameRendering, eleme
17019
17315
  return null;
17020
17316
  };
17021
17317
  var renderElementToSvg = (element, elementsMap, rsvg, svgRoot, files, offsetX, offsetY, renderConfig) => {
17022
- const offset2 = { x: offsetX, y: offsetY };
17318
+ const offset = { x: offsetX, y: offsetY };
17023
17319
  const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
17024
17320
  let cx = (x2 - x1) / 2 - (element.x - x1);
17025
17321
  let cy = (y2 - y1) / 2 - (element.y - y1);
@@ -17111,8 +17407,8 @@ var renderElementToSvg = (element, elementsMap, rsvg, svgRoot, files, offsetX, o
17111
17407
  rsvg,
17112
17408
  root,
17113
17409
  files,
17114
- label.x + offset2.x - element.x,
17115
- label.y + offset2.y - element.y,
17410
+ label.x + offset.x - element.x,
17411
+ label.y + offset.y - element.y,
17116
17412
  renderConfig
17117
17413
  );
17118
17414
  const embeddableNode = roughSVGDrawWithPrecision(
@@ -19043,7 +19339,7 @@ var tryParseNumber = (s) => {
19043
19339
  }
19044
19340
  return parseFloat(`${(match[1] || match[2]) + match[3]}`.replace(/,/g, ""));
19045
19341
  };
19046
- var isNumericColumn = (lines, columnIndex) => lines.slice(1).every((line) => tryParseNumber(line[columnIndex]) !== null);
19342
+ var isNumericColumn = (lines, columnIndex) => lines.slice(1).every((line2) => tryParseNumber(line2[columnIndex]) !== null);
19047
19343
  var tryParseCells = (cells) => {
19048
19344
  const numCols = cells[0].length;
19049
19345
  if (numCols > 2) {
@@ -19055,7 +19351,7 @@ var tryParseCells = (cells) => {
19055
19351
  }
19056
19352
  const hasHeader2 = tryParseNumber(cells[0][0]) === null;
19057
19353
  const values = (hasHeader2 ? cells.slice(1) : cells).map(
19058
- (line) => tryParseNumber(line[0])
19354
+ (line2) => tryParseNumber(line2[0])
19059
19355
  );
19060
19356
  if (values.length < 2) {
19061
19357
  return { type: NOT_SPREADSHEET, reason: "Less than two rows" };
@@ -19101,15 +19397,15 @@ var transposeCells = (cells) => {
19101
19397
  return nextCells;
19102
19398
  };
19103
19399
  var tryParseSpreadsheet = (text) => {
19104
- let lines = text.trim().split("\n").map((line) => line.trim().split(" "));
19400
+ let lines = text.trim().split("\n").map((line2) => line2.trim().split(" "));
19105
19401
  if (lines.length && lines[0].length !== 2) {
19106
- lines = text.trim().split("\n").map((line) => line.trim().split(","));
19402
+ lines = text.trim().split("\n").map((line2) => line2.trim().split(","));
19107
19403
  }
19108
19404
  if (lines.length === 0) {
19109
19405
  return { type: NOT_SPREADSHEET, reason: "No values" };
19110
19406
  }
19111
19407
  const numColsFirstLine = lines[0].length;
19112
- const isSpreadsheet = lines.every((line) => line.length === numColsFirstLine);
19408
+ const isSpreadsheet = lines.every((line2) => line2.length === numColsFirstLine);
19113
19409
  if (!isSpreadsheet) {
19114
19410
  return {
19115
19411
  type: NOT_SPREADSHEET,
@@ -19296,7 +19592,7 @@ var chartTypeLine = (spreadsheet, x, y) => {
19296
19592
  const maxY = Math.max(...points.map((element) => element[1]));
19297
19593
  const minX = Math.min(...points.map((element) => element[0]));
19298
19594
  const minY = Math.min(...points.map((element) => element[1]));
19299
- const line = newLinearElement({
19595
+ const line2 = newLinearElement({
19300
19596
  backgroundColor,
19301
19597
  groupIds: [groupId],
19302
19598
  ...commonProps,
@@ -19349,7 +19645,7 @@ var chartTypeLine = (spreadsheet, x, y) => {
19349
19645
  backgroundColor,
19350
19646
  define_import_meta_env_default.DEV
19351
19647
  ),
19352
- line,
19648
+ line2,
19353
19649
  ...lines,
19354
19650
  ...dots
19355
19651
  ];
@@ -19950,12 +20246,12 @@ var elementsOverlappingBBox = ({
19950
20246
  };
19951
20247
 
19952
20248
  // ../utils/bbox.ts
19953
- function getBBox(line) {
20249
+ function getBBox(line2) {
19954
20250
  return [
19955
- Math.min(line[0][0], line[1][0]),
19956
- Math.min(line[0][1], line[1][1]),
19957
- Math.max(line[0][0], line[1][0]),
19958
- Math.max(line[0][1], line[1][1])
20251
+ Math.min(line2[0][0], line2[1][0]),
20252
+ Math.min(line2[0][1], line2[1][1]),
20253
+ Math.max(line2[0][0], line2[1][0]),
20254
+ Math.max(line2[0][1], line2[1][1])
19959
20255
  ];
19960
20256
  }
19961
20257
  function doBBoxesIntersect(a, b) {
@@ -21413,10 +21709,10 @@ var handleEndpointDrag = (arrow, updatedPoints, fixedSegments, startHeading, end
21413
21709
  )
21414
21710
  }));
21415
21711
  const newPoints = [];
21416
- const offset2 = 2 + (startIsSpecial ? 1 : 0);
21712
+ const offset = 2 + (startIsSpecial ? 1 : 0);
21417
21713
  const endOffset = 2 + (endIsSpecial ? 1 : 0);
21418
- while (newPoints.length + offset2 < globalUpdatedPoints.length - endOffset) {
21419
- newPoints.push(globalUpdatedPoints[newPoints.length + offset2]);
21714
+ while (newPoints.length + offset < globalUpdatedPoints.length - endOffset) {
21715
+ newPoints.push(globalUpdatedPoints[newPoints.length + offset]);
21420
21716
  }
21421
21717
  {
21422
21718
  const secondPoint = globalUpdatedPoints[startIsSpecial ? 2 : 1];
@@ -21669,19 +21965,27 @@ var getElbowArrowData = (arrow, elementsMap, nextPoints, options) => {
21669
21965
  options?.zoom
21670
21966
  ) : [startElement, endElement];
21671
21967
  const startGlobalPoint = getGlobalPoint(
21968
+ {
21969
+ ...arrow,
21970
+ elbowed: true,
21971
+ points: nextPoints
21972
+ },
21973
+ "start",
21672
21974
  arrow.startBinding?.fixedPoint,
21673
21975
  origStartGlobalPoint,
21674
- origEndGlobalPoint,
21675
- elementsMap,
21676
21976
  startElement,
21677
21977
  hoveredStartElement,
21678
21978
  options?.isDragging
21679
21979
  );
21680
21980
  const endGlobalPoint = getGlobalPoint(
21981
+ {
21982
+ ...arrow,
21983
+ elbowed: true,
21984
+ points: nextPoints
21985
+ },
21986
+ "end",
21681
21987
  arrow.endBinding?.fixedPoint,
21682
21988
  origEndGlobalPoint,
21683
- origStartGlobalPoint,
21684
- elementsMap,
21685
21989
  endElement,
21686
21990
  hoveredEndElement,
21687
21991
  options?.isDragging
@@ -22201,11 +22505,11 @@ var gridNodeFromAddr = ([col, row], grid) => {
22201
22505
  }
22202
22506
  return grid.data[row * grid.col + col] ?? null;
22203
22507
  };
22204
- var pointToGridNode = (point2, grid) => {
22508
+ var pointToGridNode = (point, grid) => {
22205
22509
  for (let col = 0; col < grid.col; col++) {
22206
22510
  for (let row = 0; row < grid.row; row++) {
22207
22511
  const candidate = gridNodeFromAddr([col, row], grid);
22208
- if (candidate && point2[0] === candidate.pos[0] && point2[1] === candidate.pos[1]) {
22512
+ if (candidate && point[0] === candidate.pos[0] && point[1] === candidate.pos[1]) {
22209
22513
  return candidate;
22210
22514
  }
22211
22515
  }
@@ -22301,14 +22605,13 @@ var neighborIndexToHeading = (idx) => {
22301
22605
  }
22302
22606
  return HEADING_LEFT;
22303
22607
  };
22304
- var getGlobalPoint = (fixedPointRatio, initialPoint, otherPoint, elementsMap, boundElement, hoveredElement, isDragging) => {
22608
+ var getGlobalPoint = (arrow, startOrEnd, fixedPointRatio, initialPoint, boundElement, hoveredElement, isDragging) => {
22305
22609
  if (isDragging) {
22306
22610
  if (hoveredElement) {
22307
- const snapPoint = getSnapPoint(
22308
- initialPoint,
22309
- otherPoint,
22611
+ const snapPoint = bindPointToSnapToElementOutline(
22612
+ arrow,
22310
22613
  hoveredElement,
22311
- elementsMap
22614
+ startOrEnd
22312
22615
  );
22313
22616
  return snapToMid(hoveredElement, snapPoint);
22314
22617
  }
@@ -22320,26 +22623,18 @@ var getGlobalPoint = (fixedPointRatio, initialPoint, otherPoint, elementsMap, bo
22320
22623
  boundElement
22321
22624
  );
22322
22625
  return Math.abs(
22323
- distanceToBindableElement(boundElement, fixedGlobalPoint, elementsMap) - FIXED_BINDING_DISTANCE
22324
- ) > 0.01 ? getSnapPoint(initialPoint, otherPoint, boundElement, elementsMap) : fixedGlobalPoint;
22626
+ distanceToBindableElement(boundElement, fixedGlobalPoint) - FIXED_BINDING_DISTANCE
22627
+ ) > 0.01 ? bindPointToSnapToElementOutline(arrow, boundElement, startOrEnd) : fixedGlobalPoint;
22325
22628
  }
22326
22629
  return initialPoint;
22327
22630
  };
22328
- var getSnapPoint = (p, otherPoint, element, elementsMap) => bindPointToSnapToElementOutline(
22329
- isRectanguloidElement(element) ? avoidRectangularCorner(element, p) : p,
22330
- otherPoint,
22331
- element,
22332
- elementsMap
22333
- );
22334
22631
  var getBindPointHeading = (p, otherPoint, elementsMap, hoveredElement, origPoint) => getHeadingForElbowArrowSnap(
22335
22632
  p,
22336
22633
  otherPoint,
22337
22634
  hoveredElement,
22338
22635
  hoveredElement && aabbForElement(
22339
22636
  hoveredElement,
22340
- Array(4).fill(
22341
- distanceToBindableElement(hoveredElement, p, elementsMap)
22342
- )
22637
+ Array(4).fill(distanceToBindableElement(hoveredElement, p))
22343
22638
  ),
22344
22639
  elementsMap,
22345
22640
  origPoint
@@ -24025,7 +24320,7 @@ var resizeMultipleElements = (selectedElements, elementsMap, handleDirection, sc
24025
24320
  };
24026
24321
 
24027
24322
  // element/dragElements.ts
24028
- var dragSelectedElements = (pointerDownState, _selectedElements, offset2, scene, snapOffset, gridSize) => {
24323
+ var dragSelectedElements = (pointerDownState, _selectedElements, offset, scene, snapOffset, gridSize) => {
24029
24324
  if (_selectedElements.length === 1 && isElbowArrow(_selectedElements[0]) && (_selectedElements[0].startBinding || _selectedElements[0].endBinding)) {
24030
24325
  return;
24031
24326
  }
@@ -24059,7 +24354,7 @@ var dragSelectedElements = (pointerDownState, _selectedElements, offset2, scene,
24059
24354
  );
24060
24355
  const adjustedOffset = calculateOffset(
24061
24356
  commonBounds,
24062
- offset2,
24357
+ offset,
24063
24358
  snapOffset,
24064
24359
  gridSize
24065
24360
  );
@@ -24242,7 +24537,7 @@ var parseFileContents = async (blob) => {
24242
24537
  let contents;
24243
24538
  if (blob.type === MIME_TYPES.png) {
24244
24539
  try {
24245
- return await (await import("./data/image-EN763OZS.js")).decodePngMetadata(blob);
24540
+ return await (await import("./data/image-NQXTDRIN.js")).decodePngMetadata(blob);
24246
24541
  } catch (error) {
24247
24542
  if (error.message === "INVALID") {
24248
24543
  throw new ImageSceneDataError(
@@ -25316,4 +25611,4 @@ export {
25316
25611
  getNormalizedZoom,
25317
25612
  getNormalizedGridStep
25318
25613
  };
25319
- //# sourceMappingURL=chunk-3O3BNMYV.js.map
25614
+ //# sourceMappingURL=chunk-UGZAZPWM.js.map