@cardenelabs/cdl 0.29.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -19673,16 +19673,112 @@ function separateSharedStraightRuns(edges, nodes) {
19673
19673
  e.d = verticesToPath(verts.get(e.id));
19674
19674
  }
19675
19675
  }
19676
+ function pullOutgoingFirstCorner(edges, nodes) {
19677
+ if (edges.length < 2) return;
19678
+ const \u675F = /* @__PURE__ */ new Map();
19679
+ const \u540C\u3058\u7D44\u306E\u6570 = /* @__PURE__ */ new Map();
19680
+ for (const e of edges) {
19681
+ const key = `${e.from}::${e.fromSide}`;
19682
+ const list = \u675F.get(key) ?? [];
19683
+ list.push(e);
19684
+ \u675F.set(key, list);
19685
+ const pair = `${e.from}->${e.to}`;
19686
+ \u540C\u3058\u7D44\u306E\u6570.set(pair, (\u540C\u3058\u7D44\u306E\u6570.get(pair) ?? 0) + 1);
19687
+ }
19688
+ let \u672D\u3092\u65E7\u7D4C\u8DEF\u3078\u8FFD\u5F93\u6E08\u307F = false;
19689
+ for (const list of \u675F.values()) {
19690
+ if (list.length < 2) continue;
19691
+ const \u4E26\u3073 = list.flatMap((e) => {
19692
+ const pts = pathVertices(e.d);
19693
+ if (!pts || pts.length < 2) return [];
19694
+ return [{ e, pts, \u6700\u521D\u306E\u9577\u3055: Math.hypot(pts[1].x - pts[0].x, pts[1].y - pts[0].y) }];
19695
+ }).sort((a, b) => b.\u6700\u521D\u306E\u9577\u3055 - a.\u6700\u521D\u306E\u9577\u3055);
19696
+ for (const { e, pts, \u6700\u521D\u306E\u9577\u3055 } of \u4E26\u3073.slice(1)) {
19697
+ if ((\u540C\u3058\u7D44\u306E\u6570.get(`${e.from}->${e.to}`) ?? 0) > 1) continue;
19698
+ if (pts.length < 3 || \u6700\u521D\u306E\u9577\u3055 <= EDGE_STUB_OUT + VERTICAL_DETOUR_CORNER) continue;
19699
+ const \u6A2A = e.fromSide === "left" || e.fromSide === "right";
19700
+ if (!runIsAligned(pts, 0, \u6A2A ? 1 : 0)) continue;
19701
+ const \u79FB\u52D5\u91CF = \u6700\u521D\u306E\u9577\u3055 - (EDGE_STUB_OUT + VERTICAL_DETOUR_CORNER);
19702
+ const ux = (pts[1].x - pts[0].x) / \u6700\u521D\u306E\u9577\u3055;
19703
+ const uy = (pts[1].y - pts[0].y) / \u6700\u521D\u306E\u9577\u3055;
19704
+ const \u8A66\u3057 = pts.map(
19705
+ (p, i) => i === 1 || i === 2 ? { x: p.x - ux * \u79FB\u52D5\u91CF, y: p.y - uy * \u79FB\u52D5\u91CF } : p
19706
+ );
19707
+ const \u8A66\u3057D = verticesToPath(\u8A66\u3057);
19708
+ const \u8A66\u3057\u533A\u9593 = flattenPathSegments(extractPathSegments(\u8A66\u3057D));
19709
+ if (nodes.some(
19710
+ (n) => n.id !== e.from && n.id !== e.to && segmentsCrossRect(\u8A66\u3057\u533A\u9593, nodeRect(n))
19711
+ )) {
19712
+ continue;
19713
+ }
19714
+ const \u524D = e.d;
19715
+ const \u524D\u306E\u4EA4\u5DEE = countEdgeCrossings(edges).count;
19716
+ e.d = \u8A66\u3057D;
19717
+ if (countEdgeCrossings(edges).count > \u524D\u306E\u4EA4\u5DEE) {
19718
+ e.d = \u524D;
19719
+ continue;
19720
+ }
19721
+ e.d = \u524D;
19722
+ if (!\u672D\u3092\u65E7\u7D4C\u8DEF\u3078\u8FFD\u5F93\u6E08\u307F) {
19723
+ slideLabelsAlongOwnPath(edges, nodes);
19724
+ \u672D\u3092\u65E7\u7D4C\u8DEF\u3078\u8FFD\u5F93\u6E08\u307F = true;
19725
+ }
19726
+ const labelBox = computeLabelBBoxWorld(e);
19727
+ const label = { x: labelBox.x + labelBox.w / 2, y: labelBox.y + labelBox.h / 2 };
19728
+ const \u7DDA\u5206\u307E\u3067\u306E\u8DDD\u96E22 = (a, b) => {
19729
+ const dx = b.x - a.x;
19730
+ const dy = b.y - a.y;
19731
+ const len2 = dx * dx + dy * dy;
19732
+ const t = len2 === 0 ? 0 : Math.max(0, Math.min(1, ((label.x - a.x) * dx + (label.y - a.y) * dy) / len2));
19733
+ return (label.x - (a.x + dx * t)) ** 2 + (label.y - (a.y + dy * t)) ** 2;
19734
+ };
19735
+ const \u52D5\u304F\u533A\u9593\u3078\u306E\u8DDD\u96E2 = \u7DDA\u5206\u307E\u3067\u306E\u8DDD\u96E22(pts[1], pts[2]);
19736
+ const label\u3082\u52D5\u304B\u3059 = pts.slice(0, -1).every((p, i) => \u7DDA\u5206\u307E\u3067\u306E\u8DDD\u96E22(p, pts[i + 1]) >= \u52D5\u304F\u533A\u9593\u3078\u306E\u8DDD\u96E2 - 1e-6);
19737
+ e.d = \u8A66\u3057D;
19738
+ if (label\u3082\u52D5\u304B\u3059) {
19739
+ e.labelX -= ux * \u79FB\u52D5\u91CF;
19740
+ e.labelY -= uy * \u79FB\u52D5\u91CF;
19741
+ }
19742
+ }
19743
+ }
19744
+ }
19676
19745
  var ENDPOINT_FAN_STEP = 56;
19677
19746
  var ENDPOINT_FAN_MIN = 20;
19678
19747
  var ENDPOINT_FAN_RUNUP = 40;
19748
+ var MIXED_ROOT_OVERLAP_MIN = 24;
19679
19749
  function fanIncomingEndpoints(edges, nodes) {
19680
19750
  if (edges.length < 2) return;
19681
19751
  const nmap = new Map(nodes.map((n) => [n.id, n]));
19752
+ const \u5E73\u5766\u306A\u533A\u9593 = new Map(edges.map((e) => [e.id, flattenPathSegments(extractPathSegments(e.d))]));
19753
+ const \u8EF8\u306B\u5E73\u884C\u306A\u91CD\u306A\u308A\u9577\u3055 = (\u4E00\u65B9, \u4ED6\u65B9) => {
19754
+ let \u5408\u8A08 = 0;
19755
+ for (const a of \u5E73\u5766\u306A\u533A\u9593.get(\u4E00\u65B9.id) ?? []) {
19756
+ const a\u306F\u6C34\u5E73 = Math.abs(a.y2 - a.y1) <= 1;
19757
+ const a\u306F\u5782\u76F4 = Math.abs(a.x2 - a.x1) <= 1;
19758
+ for (const b of \u5E73\u5766\u306A\u533A\u9593.get(\u4ED6\u65B9.id) ?? []) {
19759
+ const b\u306F\u6C34\u5E73 = Math.abs(b.y2 - b.y1) <= 1;
19760
+ const b\u306F\u5782\u76F4 = Math.abs(b.x2 - b.x1) <= 1;
19761
+ if (a\u306F\u6C34\u5E73 && b\u306F\u6C34\u5E73 && Math.abs(a.y1 - b.y1) <= 1) {
19762
+ \u5408\u8A08 += Math.max(0, Math.min(Math.max(a.x1, a.x2), Math.max(b.x1, b.x2)) - Math.max(Math.min(a.x1, a.x2), Math.min(b.x1, b.x2)));
19763
+ }
19764
+ if (a\u306F\u5782\u76F4 && b\u306F\u5782\u76F4 && Math.abs(a.x1 - b.x1) <= 1) {
19765
+ \u5408\u8A08 += Math.max(0, Math.min(Math.max(a.y1, a.y2), Math.max(b.y1, b.y2)) - Math.max(Math.min(a.y1, a.y2), Math.min(b.y1, b.y2)));
19766
+ }
19767
+ }
19768
+ }
19769
+ return \u5408\u8A08;
19770
+ };
19682
19771
  const \u540C\u3058\u7D44\u306E\u6570 = /* @__PURE__ */ new Map();
19683
19772
  for (const e of edges) \u540C\u3058\u7D44\u306E\u6570.set(`${e.from}->${e.to}`, (\u540C\u3058\u7D44\u306E\u6570.get(`${e.from}->${e.to}`) ?? 0) + 1);
19684
19773
  const \u675F = /* @__PURE__ */ new Map();
19774
+ const \u51FA\u308B\u7DDA = /* @__PURE__ */ new Map();
19685
19775
  for (const e of edges) {
19776
+ if (nmap.has(e.from)) {
19777
+ const key2 = `${e.from}::${e.fromSide}`;
19778
+ const list2 = \u51FA\u308B\u7DDA.get(key2) ?? [];
19779
+ list2.push(e);
19780
+ \u51FA\u308B\u7DDA.set(key2, list2);
19781
+ }
19686
19782
  if (!nmap.has(e.to)) continue;
19687
19783
  if ((\u540C\u3058\u7D44\u306E\u6570.get(`${e.from}->${e.to}`) ?? 0) > 1) continue;
19688
19784
  const key = `${e.to}::${e.toSide}`;
@@ -19690,27 +19786,48 @@ function fanIncomingEndpoints(edges, nodes) {
19690
19786
  list.push(e);
19691
19787
  \u675F.set(key, list);
19692
19788
  }
19693
- for (const [, list] of \u675F) {
19694
- if (list.length < 2) continue;
19789
+ for (const [key, list] of \u675F) {
19790
+ const \u4E2D\u592E\u304C\u585E\u304C\u3063\u3066\u3044\u308B = (\u51FA\u308B\u7DDA.get(key) ?? []).some(
19791
+ (\u51FA\u7DDA) => list.some(
19792
+ (\u5165\u7DDA) => !(\u5165\u7DDA.from === \u51FA\u7DDA.to && \u5165\u7DDA.to === \u51FA\u7DDA.from) && \u8EF8\u306B\u5E73\u884C\u306A\u91CD\u306A\u308A\u9577\u3055(\u5165\u7DDA, \u51FA\u7DDA) >= MIXED_ROOT_OVERLAP_MIN
19793
+ )
19794
+ );
19795
+ if (list.length < 2 && !\u4E2D\u592E\u304C\u585E\u304C\u3063\u3066\u3044\u308B) continue;
19695
19796
  const n = nmap.get(list[0].to);
19696
19797
  const \u6A2A = list[0].toSide === "left" || list[0].toSide === "right";
19697
19798
  const \u8FBA\u306E\u9577\u3055 = \u6A2A ? n.h : n.w;
19698
19799
  const \u4F7F\u3048\u308B\u5E452 = \u8FBA\u306E\u9577\u3055 - 2 * ARROW_ENDPOINT_CENTER_TOL;
19699
19800
  if (\u4F7F\u3048\u308B\u5E452 <= 0) continue;
19700
- const \u9593\u9694 = Math.min(ENDPOINT_FAN_STEP, \u4F7F\u3048\u308B\u5E452 / (list.length - 1));
19801
+ const \u5E2D\u306E\u9593 = \u4E2D\u592E\u304C\u585E\u304C\u3063\u3066\u3044\u308B ? list.length : list.length - 1;
19802
+ const \u9593\u9694 = Math.min(ENDPOINT_FAN_STEP, \u4F7F\u3048\u308B\u5E452 / \u5E2D\u306E\u9593);
19701
19803
  if (\u9593\u9694 < ENDPOINT_FAN_MIN) continue;
19702
- const \u4E26\u3073 = list.map((e) => ({ e, \u6DF1\u3055: \u8FBA\u304B\u3089\u96E2\u308C\u305F\u5074\u306E\u4F4D\u7F6E(e, \u6A2A) ?? 0 })).sort((a, b) => a.\u6DF1\u3055 - b.\u6DF1\u3055 || (a.e.id < b.e.id ? -1 : 1));
19804
+ const \u8FBA\u306E\u4E2D\u5FC3 = \u6A2A ? n.cy : n.cx;
19805
+ const \u4E26\u3073 = list.map((e) => {
19806
+ const \u533A\u9593 = extractPathSegments(e.d);
19807
+ const last = \u533A\u9593[\u533A\u9593.length - 1];
19808
+ const \u9577\u3044\u52A9\u8D70 = last === void 0 ? 0 : Math.hypot(last.x2 - last.x1, last.y2 - last.y1);
19809
+ const \u4E2D\u5FC3\u3092\u88DC\u3046 = \u4E2D\u592E\u304C\u585E\u304C\u3063\u3066\u3044\u308B || list.length === 2;
19810
+ const \u6DF1\u3055 = \u8FBA\u304B\u3089\u96E2\u308C\u305F\u5074\u306E\u4F4D\u7F6E(e, \u6A2A) ?? (\u4E2D\u5FC3\u3092\u88DC\u3046 ? \u8FBA\u306E\u4E2D\u5FC3 : 0);
19811
+ return { e, \u9577\u3044\u52A9\u8D70, \u6DF1\u3055 };
19812
+ }).sort((a, b) => a.\u6DF1\u3055 - b.\u6DF1\u3055 || (a.e.id < b.e.id ? -1 : 1));
19703
19813
  const \u4E2D\u5FC3 = (\u4E26\u3073.length - 1) * \u9593\u9694 / 2;
19814
+ let \u8CA0\u5074\u306E\u5E2D = 0;
19815
+ let \u6B63\u5074\u306E\u5E2D = 0;
19704
19816
  for (let k = 0; k < \u4E26\u3073.length; k++) {
19705
- const d = k * \u9593\u9694 - \u4E2D\u5FC3;
19817
+ const d = \u4E2D\u592E\u304C\u585E\u304C\u3063\u3066\u3044\u308B ? \u4E26\u3073[k].\u6DF1\u3055 < \u8FBA\u306E\u4E2D\u5FC3 ? -(++\u8CA0\u5074\u306E\u5E2D * \u9593\u9694) : ++\u6B63\u5074\u306E\u5E2D * \u9593\u9694 : k * \u9593\u9694 - \u4E2D\u5FC3;
19706
19818
  if (Math.abs(d) < 1e-3) continue;
19707
19819
  const e = \u4E26\u3073[k].e;
19708
- const \u5DEE\u66FF = \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \u6A2A, d, nodes);
19709
- if (\u5DEE\u66FF === null) continue;
19710
19820
  const \u524D = e.d;
19711
19821
  const \u524D\u306E\u4EA4\u5DEE = countEdgeCrossings(edges).count;
19712
- e.d = \u5DEE\u66FF;
19713
- if (countEdgeCrossings(edges).count > \u524D\u306E\u4EA4\u5DEE) e.d = \u524D;
19822
+ const \u9577\u3044\u52A9\u8D70 = \u4E26\u3073[k].\u9577\u3044\u52A9\u8D70;
19823
+ for (const \u52A9\u8D70 of [\u9577\u3044\u52A9\u8D70, ENDPOINT_FAN_RUNUP]) {
19824
+ e.d = \u524D;
19825
+ const \u5DEE\u66FF = \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \u6A2A, d, \u52A9\u8D70, nodes);
19826
+ if (\u5DEE\u66FF === null) continue;
19827
+ e.d = \u5DEE\u66FF;
19828
+ if (countEdgeCrossings(edges).count <= \u524D\u306E\u4EA4\u5DEE) break;
19829
+ e.d = \u524D;
19830
+ }
19714
19831
  }
19715
19832
  }
19716
19833
  }
@@ -19723,7 +19840,7 @@ function \u8FBA\u304B\u3089\u96E2\u308C\u305F\u5074\u306E\u4F4D\u7F6E(e, \u6A2A)
19723
19840
  }
19724
19841
  return null;
19725
19842
  }
19726
- function \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \u6A2A, d, nodes) {
19843
+ function \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \u6A2A, d, \u52A9\u8D70, nodes) {
19727
19844
  if ((e.d.match(/M/g) ?? []).length !== 1) return null;
19728
19845
  const segs = extractPathSegments(e.d);
19729
19846
  if (segs.length === 0) return null;
@@ -19736,7 +19853,8 @@ function \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \
19736
19853
  if (\u9577\u3055 < ENDPOINT_FAN_RUNUP + 1) return null;
19737
19854
  const ux = (last.x1 - last.x2) / \u9577\u3055;
19738
19855
  const uy = (last.y1 - last.y2) / \u9577\u3055;
19739
- const \u6298\u308C1 = { x: last.x2 + ux * ENDPOINT_FAN_RUNUP, y: last.y2 + uy * ENDPOINT_FAN_RUNUP };
19856
+ const \u4E38\u3081\u305F\u52A9\u8D70 = Math.min(\u52A9\u8D70, \u9577\u3055);
19857
+ const \u6298\u308C1 = { x: last.x2 + ux * \u4E38\u3081\u305F\u52A9\u8D70, y: last.y2 + uy * \u4E38\u3081\u305F\u52A9\u8D70 };
19740
19858
  const \u6298\u308C2 = \u6A2A ? { x: \u6298\u308C1.x, y: \u6298\u308C1.y + d } : { x: \u6298\u308C1.x + d, y: \u6298\u308C1.y };
19741
19859
  const \u7D42\u70B9 = \u6A2A ? { x: last.x2, y: last.y2 + d } : { x: last.x2 + d, y: last.y2 };
19742
19860
  const \u65B0\u533A\u9593 = [
@@ -19758,7 +19876,8 @@ function \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \
19758
19876
  }
19759
19877
  parts.push(`L ${s.x2} ${s.y2}`);
19760
19878
  }
19761
- parts.push(`L ${round1(\u6298\u308C1.x)} ${round1(\u6298\u308C1.y)}`);
19879
+ const \u6298\u308C1\u306F\u76F4\u524D\u306E\u6298\u308C = Math.abs(\u6298\u308C1.x - last.x1) <= 0.5 && Math.abs(\u6298\u308C1.y - last.y1) <= 0.5;
19880
+ if (!\u6298\u308C1\u306F\u76F4\u524D\u306E\u6298\u308C) parts.push(`L ${round1(\u6298\u308C1.x)} ${round1(\u6298\u308C1.y)}`);
19762
19881
  parts.push(`L ${round1(\u6298\u308C2.x)} ${round1(\u6298\u308C2.y)}`);
19763
19882
  parts.push(`L ${round1(\u7D42\u70B9.x)} ${round1(\u7D42\u70B9.y)}`);
19764
19883
  return parts.join(" ");
@@ -20241,6 +20360,7 @@ function layout(diag) {
20241
20360
  diag.edges.filter((e) => e.posX1 !== void 0 && e.posY1 !== void 0 && e.posX2 !== void 0 && e.posY2 !== void 0).map((e) => e.id)
20242
20361
  );
20243
20362
  bowSharedStraightPaths(edges, nodesFinal, positionedEdgeIds);
20363
+ pullOutgoingFirstCorner(edges, nodesFinal);
20244
20364
  fanIncomingEndpoints(edges, nodesFinal);
20245
20365
  separateSharedStraightRuns(edges, nodesFinal);
20246
20366
  hopEdgeCrossings(edges);