@cardenelabs/cdl 0.30.1 → 0.30.3

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/react.cjs CHANGED
@@ -2015,6 +2015,234 @@ function resolveEdgeLabelOverlapsWithChainAndPropagate(edges, obstacles, minClea
2015
2015
  edgePathShifts: edgePathShiftMap
2016
2016
  };
2017
2017
  }
2018
+ function resolveLabelClearanceAfterPathPasses(edges, obstacles, maxIter = 8) {
2019
+ if (edges.length === 0) return edges;
2020
+ const labeledIds = new Set(
2021
+ edges.filter((e) => e.label?.trim() || e.sub?.trim()).map((e) => e.id)
2022
+ );
2023
+ if (labeledIds.size === 0) return edges;
2024
+ const \u7BB1\u305F\u3061 = obstacles.filter((o) => o.kind === "node" || o.kind === "lane-label");
2025
+ const edgeById = /* @__PURE__ */ new Map();
2026
+ for (const e of edges) edgeById.set(e.id, e);
2027
+ const \u533A\u9593cache = /* @__PURE__ */ new Map();
2028
+ const \u533A\u9593 = (id, d) => {
2029
+ const hit = \u533A\u9593cache.get(id);
2030
+ if (hit) return hit;
2031
+ const segs = flattenPathSegments(extractPathSegments(d));
2032
+ \u533A\u9593cache.set(id, segs);
2033
+ return segs;
2034
+ };
2035
+ const \u5916\u63A5cache = /* @__PURE__ */ new Map();
2036
+ const \u5916\u63A5 = (id, d) => {
2037
+ const hit = \u5916\u63A5cache.get(id);
2038
+ if (hit !== void 0) return hit;
2039
+ const segs = \u533A\u9593(id, d);
2040
+ if (segs.length === 0) {
2041
+ \u5916\u63A5cache.set(id, null);
2042
+ return null;
2043
+ }
2044
+ let x1 = Infinity, y1 = Infinity, x2 = -Infinity, y2 = -Infinity;
2045
+ for (const g of segs) {
2046
+ x1 = Math.min(x1, g.x1, g.x2);
2047
+ y1 = Math.min(y1, g.y1, g.y2);
2048
+ x2 = Math.max(x2, g.x1, g.x2);
2049
+ y2 = Math.max(y2, g.y1, g.y2);
2050
+ }
2051
+ const box = { x: x1, y: y1, w: x2 - x1, h: y2 - y1 };
2052
+ \u5916\u63A5cache.set(id, box);
2053
+ return box;
2054
+ };
2055
+ const \u9060\u3044 = (box, edgeId, d, \u4F59\u88D5) => {
2056
+ const b = \u5916\u63A5(edgeId, d);
2057
+ if (!b) return true;
2058
+ const dx = Math.max(0, Math.max(box.x - (b.x + b.w), b.x - (box.x + box.w)));
2059
+ const dy = Math.max(0, Math.max(box.y - (b.y + b.h), b.y - (box.y + box.h)));
2060
+ return Math.hypot(dx, dy) >= \u4F59\u88D5;
2061
+ };
2062
+ const \u6700\u5927\u79FB\u52D5 = CHAIN_SHIFT_MAX_ACCUMULATED * 2;
2063
+ const shiftMap = /* @__PURE__ */ new Map();
2064
+ const getShift = (id) => shiftMap.get(id) ?? { dx: 0, dy: 0 };
2065
+ const labelBBoxes = () => {
2066
+ const out = [];
2067
+ for (const e of edges) {
2068
+ if (!labeledIds.has(e.id)) continue;
2069
+ const base = computeLabelBBoxWorld(e);
2070
+ const s = getShift(e.id);
2071
+ out.push({ kind: "edge-label", id: e.id, x: base.x + s.dx, y: base.y + s.dy, w: base.w, h: base.h });
2072
+ }
2073
+ return out;
2074
+ };
2075
+ const \u96E2\u308C\u91CF = (a, b) => ({
2076
+ x: Math.max(a.x - (b.x + b.w), b.x - (a.x + a.w)),
2077
+ y: Math.max(a.y - (b.y + b.h), b.y - (a.y + a.h))
2078
+ });
2079
+ const \u52D5\u304B\u3057\u305F\u7BB1 = (box, axis, sign, amount) => ({
2080
+ ...box,
2081
+ x: box.x + (axis === "x" ? sign * amount : 0),
2082
+ y: box.y + (axis === "y" ? sign * amount : 0)
2083
+ });
2084
+ for (let iter = 0; iter < maxIter; iter += 1) {
2085
+ const labels = labelBBoxes();
2086
+ const \u672D\u306E\u8981\u6C42 = requiredNearClearance("edge-label", "edge-label");
2087
+ let \u52D5\u3044\u305F = false;
2088
+ const \u4ECA\u56DE\u52D5\u304B\u3057\u305F = /* @__PURE__ */ new Set();
2089
+ const \u5B89\u5168\u304B = (label, \u884C\u304D\u5148) => {
2090
+ for (const obs of \u7BB1\u305F\u3061) {
2091
+ const \u524D = computeGap(label, obs);
2092
+ const \u5F8C = computeGap(\u884C\u304D\u5148, obs);
2093
+ if (\u5F8C < Math.min(\u524D, requiredNearClearance("edge-label", obs.kind))) return false;
2094
+ }
2095
+ for (const \u4ED6 of labels) {
2096
+ if (\u4ED6.id === label.id) continue;
2097
+ const \u524D = computeGap(label, \u4ED6);
2098
+ const \u5F8C = computeGap(\u884C\u304D\u5148, \u4ED6);
2099
+ if (\u5F8C < Math.min(\u524D, \u672D\u306E\u8981\u6C42)) return false;
2100
+ }
2101
+ const \u81EA\u5206 = edgeById.get(label.id);
2102
+ const \u81EA\u5206\u306E\u533A\u9593 = \u81EA\u5206 ? \u533A\u9593(\u81EA\u5206.id, \u81EA\u5206.d) : [];
2103
+ if (\u81EA\u5206\u306E\u533A\u9593.length > 0) {
2104
+ const \u524D = measurePathLabelGapSegs(\u81EA\u5206\u306E\u533A\u9593, label);
2105
+ const \u5F8C = measurePathLabelGapSegs(\u81EA\u5206\u306E\u533A\u9593, \u884C\u304D\u5148);
2106
+ if (\u5F8C > Math.max(\u524D, DIST_LABEL_PATH_MAX)) return false;
2107
+ }
2108
+ for (const \u76F8\u624B of edges) {
2109
+ if (\u76F8\u624B.id === label.id) continue;
2110
+ if (\u9060\u3044(label, \u76F8\u624B.id, \u76F8\u624B.d, LABEL_TO_PATH_CLEARANCE) && \u9060\u3044(\u884C\u304D\u5148, \u76F8\u624B.id, \u76F8\u624B.d, LABEL_TO_PATH_CLEARANCE)) continue;
2111
+ const segs = segmentsExcludingOwnPath(\u533A\u9593(\u76F8\u624B.id, \u76F8\u624B.d), \u81EA\u5206\u306E\u533A\u9593);
2112
+ if (segs.length === 0) continue;
2113
+ const \u524D = measurePathLabelGapSegs(segs, label);
2114
+ const \u5F8C = measurePathLabelGapSegs(segs, \u884C\u304D\u5148);
2115
+ if (\u5F8C < Math.min(\u524D, LABEL_TO_PATH_CLEARANCE)) return false;
2116
+ }
2117
+ return true;
2118
+ };
2119
+ const \u9003\u304C\u3059 = (label, \u5019\u88DC) => {
2120
+ for (const c of \u5019\u88DC.slice().sort((a, b) => a.amount - b.amount)) {
2121
+ if (c.amount <= 0) continue;
2122
+ const \u884C\u304D\u5148 = \u52D5\u304B\u3057\u305F\u7BB1(label, c.axis, c.sign, c.amount);
2123
+ if (!\u5B89\u5168\u304B(label, \u884C\u304D\u5148)) continue;
2124
+ const cur = getShift(label.id);
2125
+ const dx = c.axis === "x" ? cur.dx + c.sign * c.amount : cur.dx;
2126
+ const dy = c.axis === "y" ? cur.dy + c.sign * c.amount : cur.dy;
2127
+ if (Math.hypot(dx, dy) > \u6700\u5927\u79FB\u52D5) continue;
2128
+ shiftMap.set(label.id, { dx, dy });
2129
+ \u4ECA\u56DE\u52D5\u304B\u3057\u305F.add(label.id);
2130
+ return true;
2131
+ }
2132
+ return false;
2133
+ };
2134
+ const \u77E9\u5F62\u306E\u5019\u88DC = (label, static\u7BB1, required) => {
2135
+ const sep = \u96E2\u308C\u91CF(label, static\u7BB1);
2136
+ const \u5411\u304D = (axis) => {
2137
+ const a = axis === "x" ? label.x + label.w / 2 : label.y + label.h / 2;
2138
+ const b = axis === "x" ? static\u7BB1.x + static\u7BB1.w / 2 : static\u7BB1.y + static\u7BB1.h / 2;
2139
+ return a >= b ? 1 : -1;
2140
+ };
2141
+ return [
2142
+ { axis: "x", sign: \u5411\u304D("x"), amount: required - sep.x + NEAR_MISS_MARGIN },
2143
+ { axis: "y", sign: \u5411\u304D("y"), amount: required - sep.y + NEAR_MISS_MARGIN }
2144
+ ];
2145
+ };
2146
+ for (const label of labels) {
2147
+ if (\u4ECA\u56DE\u52D5\u304B\u3057\u305F.has(label.id)) continue;
2148
+ for (const obs of \u7BB1\u305F\u3061) {
2149
+ const required = requiredNearClearance(label.kind, obs.kind);
2150
+ if (required <= 0) continue;
2151
+ if (computeGap(label, obs) >= required) continue;
2152
+ if (\u9003\u304C\u3059(label, \u77E9\u5F62\u306E\u5019\u88DC(label, obs, required))) {
2153
+ \u52D5\u3044\u305F = true;
2154
+ break;
2155
+ }
2156
+ }
2157
+ }
2158
+ const \u672D\u9806 = /* @__PURE__ */ new Map();
2159
+ edges.forEach((e, i) => \u672D\u9806.set(e.id, i));
2160
+ for (let i = 0; i < labels.length; i += 1) {
2161
+ for (let j = i + 1; j < labels.length; j += 1) {
2162
+ const a = labels[i];
2163
+ const b = labels[j];
2164
+ if (computeGap(a, b) >= \u672D\u306E\u8981\u6C42) continue;
2165
+ const aIsLater = \u672D\u9806.get(a.id) > \u672D\u9806.get(b.id);
2166
+ const moveBox = aIsLater ? a : b;
2167
+ const staticBox = aIsLater ? b : a;
2168
+ if (\u4ECA\u56DE\u52D5\u304B\u3057\u305F.has(moveBox.id)) continue;
2169
+ if (\u9003\u304C\u3059(moveBox, \u77E9\u5F62\u306E\u5019\u88DC(moveBox, staticBox, \u672D\u306E\u8981\u6C42))) \u52D5\u3044\u305F = true;
2170
+ }
2171
+ }
2172
+ for (const label of labels) {
2173
+ if (\u4ECA\u56DE\u52D5\u304B\u3057\u305F.has(label.id)) continue;
2174
+ const \u81EA\u5206 = edgeById.get(label.id);
2175
+ if (!\u81EA\u5206) continue;
2176
+ const \u81EA\u5206\u306E\u533A\u9593 = \u533A\u9593(\u81EA\u5206.id, \u81EA\u5206.d);
2177
+ for (const \u4ED6 of edges) {
2178
+ if (\u4ED6.id === label.id) continue;
2179
+ if (\u81EA\u5206.from === \u4ED6.from && \u81EA\u5206.to === \u4ED6.to) continue;
2180
+ if (\u9060\u3044(label, \u4ED6.id, \u4ED6.d, LABEL_TO_PATH_CLEARANCE)) continue;
2181
+ const segs = segmentsExcludingOwnPath(\u533A\u9593(\u4ED6.id, \u4ED6.d), \u81EA\u5206\u306E\u533A\u9593);
2182
+ if (segs.length === 0) continue;
2183
+ const gap = measurePathLabelGapSegs(segs, label);
2184
+ if (gap >= LABEL_TO_PATH_CLEARANCE) continue;
2185
+ const \u82AF = { x: label.x + label.w / 2, y: label.y + label.h / 2 };
2186
+ let \u8FD1\u3044\u70B9 = null;
2187
+ let \u6700\u77ED = Infinity;
2188
+ for (const seg of segs) {
2189
+ for (const \u70B9 of [
2190
+ { x: seg.x1, y: seg.y1 },
2191
+ { x: seg.x2, y: seg.y2 },
2192
+ { x: (seg.x1 + seg.x2) / 2, y: (seg.y1 + seg.y2) / 2 }
2193
+ ]) {
2194
+ const d = Math.hypot(\u70B9.x - \u82AF.x, \u70B9.y - \u82AF.y);
2195
+ if (d < \u6700\u77ED) {
2196
+ \u6700\u77ED = d;
2197
+ \u8FD1\u3044\u70B9 = \u70B9;
2198
+ }
2199
+ }
2200
+ }
2201
+ if (!\u8FD1\u3044\u70B9) continue;
2202
+ const \u5FC5\u8981\u91CF = (axis, sign) => {
2203
+ const \u6E80\u305F\u3059 = (\u91CF) => measurePathLabelGapSegs(segs, \u52D5\u304B\u3057\u305F\u7BB1(label, axis, sign, \u91CF)) >= LABEL_TO_PATH_CLEARANCE;
2204
+ let lo = 0;
2205
+ let hi = Math.max(4, LABEL_TO_PATH_CLEARANCE - gap);
2206
+ while (!\u6E80\u305F\u3059(hi)) {
2207
+ if (hi >= \u6700\u5927\u79FB\u52D5) return null;
2208
+ lo = hi;
2209
+ hi = Math.min(hi * 2, \u6700\u5927\u79FB\u52D5);
2210
+ }
2211
+ for (let k = 0; k < 12; k += 1) {
2212
+ const mid = (lo + hi) / 2;
2213
+ if (\u6E80\u305F\u3059(mid)) hi = mid;
2214
+ else lo = mid;
2215
+ }
2216
+ return hi + NEAR_MISS_MARGIN;
2217
+ };
2218
+ const dx = \u82AF.x - \u8FD1\u3044\u70B9.x;
2219
+ const dy = \u82AF.y - \u8FD1\u3044\u70B9.y;
2220
+ const \u5019\u88DC = [];
2221
+ for (const c of [
2222
+ { axis: "x", sign: dx >= 0 ? 1 : -1 },
2223
+ { axis: "y", sign: dy >= 0 ? 1 : -1 },
2224
+ // 近い点から離れる向きが塞がれていることがある。 反対向きも候補に入れる。
2225
+ { axis: "x", sign: dx >= 0 ? -1 : 1 },
2226
+ { axis: "y", sign: dy >= 0 ? -1 : 1 }
2227
+ ]) {
2228
+ const \u91CF = \u5FC5\u8981\u91CF(c.axis, c.sign);
2229
+ if (\u91CF !== null) \u5019\u88DC.push({ ...c, amount: \u91CF });
2230
+ }
2231
+ if (\u9003\u304C\u3059(label, \u5019\u88DC)) {
2232
+ \u52D5\u3044\u305F = true;
2233
+ break;
2234
+ }
2235
+ }
2236
+ }
2237
+ if (!\u52D5\u3044\u305F) break;
2238
+ }
2239
+ if (shiftMap.size === 0) return edges;
2240
+ return edges.map((e) => {
2241
+ const s = shiftMap.get(e.id);
2242
+ if (!s || s.dx === 0 && s.dy === 0) return e;
2243
+ return { ...e, labelX: e.labelX + s.dx, labelY: e.labelY + s.dy };
2244
+ });
2245
+ }
2018
2246
  function applyEdgeLabelAndPathShifts(edges, labelShiftMap, edgePathShiftMap) {
2019
2247
  if (labelShiftMap.size === 0 && edgePathShiftMap.size === 0) return edges;
2020
2248
  return edges.map((e) => {
@@ -8600,11 +8828,66 @@ function \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \
8600
8828
  parts.push(`L ${s.x2} ${s.y2}`);
8601
8829
  }
8602
8830
  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;
8831
+ if (\u6298\u308C1\u306F\u76F4\u524D\u306E\u6298\u308C) {
8832
+ const \u6298\u308A\u8FD4\u3055\u306A\u3044 = \u76F4\u524D\u306E\u6298\u308C\u3054\u3068\u305A\u3089\u3059(segs, \u6A2A, d, nodes, e);
8833
+ if (\u6298\u308A\u8FD4\u3055\u306A\u3044) return \u6298\u308A\u8FD4\u3055\u306A\u3044;
8834
+ }
8603
8835
  if (!\u6298\u308C1\u306F\u76F4\u524D\u306E\u6298\u308C) parts.push(`L ${round1(\u6298\u308C1.x)} ${round1(\u6298\u308C1.y)}`);
8604
8836
  parts.push(`L ${round1(\u6298\u308C2.x)} ${round1(\u6298\u308C2.y)}`);
8605
8837
  parts.push(`L ${round1(\u7D42\u70B9.x)} ${round1(\u7D42\u70B9.y)}`);
8606
8838
  return parts.join(" ");
8607
8839
  }
8840
+ function \u76F4\u524D\u306E\u6298\u308C\u3054\u3068\u305A\u3089\u3059(segs, \u6A2A, d, nodes, e) {
8841
+ const \u5E73\u884C\u304B = (s) => \u6A2A ? Math.abs(s.x2 - s.x1) < 0.5 && Math.abs(s.y2 - s.y1) > 0.5 : Math.abs(s.y2 - s.y1) < 0.5 && Math.abs(s.x2 - s.x1) > 0.5;
8842
+ let \u5438\u53CE = -1;
8843
+ for (let i = segs.length - 2; i >= 0; i -= 1) {
8844
+ if (\u5E73\u884C\u304B(segs[i])) {
8845
+ \u5438\u53CE = i;
8846
+ break;
8847
+ }
8848
+ }
8849
+ if (\u5438\u53CE < 0) return null;
8850
+ const \u5143\u306E\u9577\u3055 = \u6A2A ? Math.abs(segs[\u5438\u53CE].y2 - segs[\u5438\u53CE].y1) : Math.abs(segs[\u5438\u53CE].x2 - segs[\u5438\u53CE].x1);
8851
+ const \u5411\u304D = \u6A2A ? Math.sign(segs[\u5438\u53CE].y2 - segs[\u5438\u53CE].y1) : Math.sign(segs[\u5438\u53CE].x2 - segs[\u5438\u53CE].x1);
8852
+ const \u5F8C\u306E\u9577\u3055 = \u5143\u306E\u9577\u3055 + \u5411\u304D * d;
8853
+ if (\u5F8C\u306E\u9577\u3055 < ENDPOINT_FAN_RUNUP) return null;
8854
+ const \u305A\u3089\u3059 = (p) => \u6A2A ? { ...p, y: p.y + d } : { ...p, x: p.x + d };
8855
+ const \u65B0segs = segs.map((s, i) => {
8856
+ if (i <= \u5438\u53CE) return s;
8857
+ return {
8858
+ ...s,
8859
+ x1: \u305A\u3089\u3059({ x: s.x1, y: s.y1 }).x,
8860
+ y1: \u305A\u3089\u3059({ x: s.x1, y: s.y1 }).y,
8861
+ x2: \u305A\u3089\u3059({ x: s.x2, y: s.y2 }).x,
8862
+ y2: \u305A\u3089\u3059({ x: s.x2, y: s.y2 }).y,
8863
+ ...s.ctrl ? { ctrl: s.ctrl.map((c) => \u305A\u3089\u3059(c)) } : {}
8864
+ };
8865
+ });
8866
+ \u65B0segs[\u5438\u53CE] = {
8867
+ ...segs[\u5438\u53CE],
8868
+ x2: \u6A2A ? segs[\u5438\u53CE].x2 : segs[\u5438\u53CE].x2 + d,
8869
+ y2: \u6A2A ? segs[\u5438\u53CE].y2 + d : segs[\u5438\u53CE].y2
8870
+ };
8871
+ if (nodes.some(
8872
+ (n) => n.id !== e.from && n.id !== e.to && segmentsCrossRect(
8873
+ \u65B0segs.slice(\u5438\u53CE).map((s) => ({ x1: s.x1, y1: s.y1, x2: s.x2, y2: s.y2 })),
8874
+ nodeRect(n)
8875
+ )
8876
+ )) {
8877
+ return null;
8878
+ }
8879
+ const head = \u65B0segs[0];
8880
+ const parts = [`M ${round1(head.x1)} ${round1(head.y1)}`];
8881
+ for (const s of \u65B0segs) {
8882
+ if (s.cmd === "Q") {
8883
+ const c = s.ctrl?.[0];
8884
+ parts.push(c ? `Q ${round1(c.x)} ${round1(c.y)}, ${round1(s.x2)} ${round1(s.y2)}` : `L ${round1(s.x2)} ${round1(s.y2)}`);
8885
+ continue;
8886
+ }
8887
+ parts.push(`L ${round1(s.x2)} ${round1(s.y2)}`);
8888
+ }
8889
+ return parts.join(" ");
8890
+ }
8608
8891
 
8609
8892
  // src/layout/lanes.ts
8610
8893
  var LANE_POSITION_EPSILON = 1e-9;
@@ -9089,6 +9372,14 @@ function layout(diag) {
9089
9372
  hopEdgeCrossings(edges);
9090
9373
  repositionParallelLabels(edges, nodesFinal);
9091
9374
  slideLabelsAlongOwnPath(edges, nodesFinal);
9375
+ if (!isChainEdgeLabelDisabled()) {
9376
+ edges = resolveLabelClearanceAfterPathPasses(
9377
+ edges,
9378
+ collectBBoxes(containedLanesFinal, nodesFinal, []).filter(
9379
+ (b) => b.kind === "node" || b.kind === "lane-label"
9380
+ )
9381
+ );
9382
+ }
9092
9383
  const bboxes = collectBBoxes(containedLanesFinal, nodesFinal, edges);
9093
9384
  const collisions = detectCollisions(bboxes, edges);
9094
9385
  const nearCollisions = detectNearCollisions(bboxes, edges);