@cardenelabs/cdl 0.28.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/react.cjs CHANGED
@@ -8393,16 +8393,112 @@ function separateSharedStraightRuns(edges, nodes) {
8393
8393
  e.d = verticesToPath(verts.get(e.id));
8394
8394
  }
8395
8395
  }
8396
+ function pullOutgoingFirstCorner(edges, nodes) {
8397
+ if (edges.length < 2) return;
8398
+ const \u675F = /* @__PURE__ */ new Map();
8399
+ const \u540C\u3058\u7D44\u306E\u6570 = /* @__PURE__ */ new Map();
8400
+ for (const e of edges) {
8401
+ const key = `${e.from}::${e.fromSide}`;
8402
+ const list = \u675F.get(key) ?? [];
8403
+ list.push(e);
8404
+ \u675F.set(key, list);
8405
+ const pair = `${e.from}->${e.to}`;
8406
+ \u540C\u3058\u7D44\u306E\u6570.set(pair, (\u540C\u3058\u7D44\u306E\u6570.get(pair) ?? 0) + 1);
8407
+ }
8408
+ let \u672D\u3092\u65E7\u7D4C\u8DEF\u3078\u8FFD\u5F93\u6E08\u307F = false;
8409
+ for (const list of \u675F.values()) {
8410
+ if (list.length < 2) continue;
8411
+ const \u4E26\u3073 = list.flatMap((e) => {
8412
+ const pts = pathVertices(e.d);
8413
+ if (!pts || pts.length < 2) return [];
8414
+ return [{ e, pts, \u6700\u521D\u306E\u9577\u3055: Math.hypot(pts[1].x - pts[0].x, pts[1].y - pts[0].y) }];
8415
+ }).sort((a, b) => b.\u6700\u521D\u306E\u9577\u3055 - a.\u6700\u521D\u306E\u9577\u3055);
8416
+ for (const { e, pts, \u6700\u521D\u306E\u9577\u3055 } of \u4E26\u3073.slice(1)) {
8417
+ if ((\u540C\u3058\u7D44\u306E\u6570.get(`${e.from}->${e.to}`) ?? 0) > 1) continue;
8418
+ if (pts.length < 3 || \u6700\u521D\u306E\u9577\u3055 <= EDGE_STUB_OUT + VERTICAL_DETOUR_CORNER) continue;
8419
+ const \u6A2A = e.fromSide === "left" || e.fromSide === "right";
8420
+ if (!runIsAligned(pts, 0, \u6A2A ? 1 : 0)) continue;
8421
+ const \u79FB\u52D5\u91CF = \u6700\u521D\u306E\u9577\u3055 - (EDGE_STUB_OUT + VERTICAL_DETOUR_CORNER);
8422
+ const ux = (pts[1].x - pts[0].x) / \u6700\u521D\u306E\u9577\u3055;
8423
+ const uy = (pts[1].y - pts[0].y) / \u6700\u521D\u306E\u9577\u3055;
8424
+ const \u8A66\u3057 = pts.map(
8425
+ (p, i) => i === 1 || i === 2 ? { x: p.x - ux * \u79FB\u52D5\u91CF, y: p.y - uy * \u79FB\u52D5\u91CF } : p
8426
+ );
8427
+ const \u8A66\u3057D = verticesToPath(\u8A66\u3057);
8428
+ const \u8A66\u3057\u533A\u9593 = flattenPathSegments(extractPathSegments(\u8A66\u3057D));
8429
+ if (nodes.some(
8430
+ (n) => n.id !== e.from && n.id !== e.to && segmentsCrossRect(\u8A66\u3057\u533A\u9593, nodeRect(n))
8431
+ )) {
8432
+ continue;
8433
+ }
8434
+ const \u524D = e.d;
8435
+ const \u524D\u306E\u4EA4\u5DEE = countEdgeCrossings(edges).count;
8436
+ e.d = \u8A66\u3057D;
8437
+ if (countEdgeCrossings(edges).count > \u524D\u306E\u4EA4\u5DEE) {
8438
+ e.d = \u524D;
8439
+ continue;
8440
+ }
8441
+ e.d = \u524D;
8442
+ if (!\u672D\u3092\u65E7\u7D4C\u8DEF\u3078\u8FFD\u5F93\u6E08\u307F) {
8443
+ slideLabelsAlongOwnPath(edges, nodes);
8444
+ \u672D\u3092\u65E7\u7D4C\u8DEF\u3078\u8FFD\u5F93\u6E08\u307F = true;
8445
+ }
8446
+ const labelBox = computeLabelBBoxWorld(e);
8447
+ const label = { x: labelBox.x + labelBox.w / 2, y: labelBox.y + labelBox.h / 2 };
8448
+ const \u7DDA\u5206\u307E\u3067\u306E\u8DDD\u96E22 = (a, b) => {
8449
+ const dx = b.x - a.x;
8450
+ const dy = b.y - a.y;
8451
+ const len2 = dx * dx + dy * dy;
8452
+ const t = len2 === 0 ? 0 : Math.max(0, Math.min(1, ((label.x - a.x) * dx + (label.y - a.y) * dy) / len2));
8453
+ return (label.x - (a.x + dx * t)) ** 2 + (label.y - (a.y + dy * t)) ** 2;
8454
+ };
8455
+ const \u52D5\u304F\u533A\u9593\u3078\u306E\u8DDD\u96E2 = \u7DDA\u5206\u307E\u3067\u306E\u8DDD\u96E22(pts[1], pts[2]);
8456
+ 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);
8457
+ e.d = \u8A66\u3057D;
8458
+ if (label\u3082\u52D5\u304B\u3059) {
8459
+ e.labelX -= ux * \u79FB\u52D5\u91CF;
8460
+ e.labelY -= uy * \u79FB\u52D5\u91CF;
8461
+ }
8462
+ }
8463
+ }
8464
+ }
8396
8465
  var ENDPOINT_FAN_STEP = 56;
8397
8466
  var ENDPOINT_FAN_MIN = 20;
8398
8467
  var ENDPOINT_FAN_RUNUP = 40;
8468
+ var MIXED_ROOT_OVERLAP_MIN = 24;
8399
8469
  function fanIncomingEndpoints(edges, nodes) {
8400
8470
  if (edges.length < 2) return;
8401
8471
  const nmap = new Map(nodes.map((n) => [n.id, n]));
8472
+ const \u5E73\u5766\u306A\u533A\u9593 = new Map(edges.map((e) => [e.id, flattenPathSegments(extractPathSegments(e.d))]));
8473
+ const \u8EF8\u306B\u5E73\u884C\u306A\u91CD\u306A\u308A\u9577\u3055 = (\u4E00\u65B9, \u4ED6\u65B9) => {
8474
+ let \u5408\u8A08 = 0;
8475
+ for (const a of \u5E73\u5766\u306A\u533A\u9593.get(\u4E00\u65B9.id) ?? []) {
8476
+ const a\u306F\u6C34\u5E73 = Math.abs(a.y2 - a.y1) <= 1;
8477
+ const a\u306F\u5782\u76F4 = Math.abs(a.x2 - a.x1) <= 1;
8478
+ for (const b of \u5E73\u5766\u306A\u533A\u9593.get(\u4ED6\u65B9.id) ?? []) {
8479
+ const b\u306F\u6C34\u5E73 = Math.abs(b.y2 - b.y1) <= 1;
8480
+ const b\u306F\u5782\u76F4 = Math.abs(b.x2 - b.x1) <= 1;
8481
+ if (a\u306F\u6C34\u5E73 && b\u306F\u6C34\u5E73 && Math.abs(a.y1 - b.y1) <= 1) {
8482
+ \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)));
8483
+ }
8484
+ if (a\u306F\u5782\u76F4 && b\u306F\u5782\u76F4 && Math.abs(a.x1 - b.x1) <= 1) {
8485
+ \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)));
8486
+ }
8487
+ }
8488
+ }
8489
+ return \u5408\u8A08;
8490
+ };
8402
8491
  const \u540C\u3058\u7D44\u306E\u6570 = /* @__PURE__ */ new Map();
8403
8492
  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);
8404
8493
  const \u675F = /* @__PURE__ */ new Map();
8494
+ const \u51FA\u308B\u7DDA = /* @__PURE__ */ new Map();
8405
8495
  for (const e of edges) {
8496
+ if (nmap.has(e.from)) {
8497
+ const key2 = `${e.from}::${e.fromSide}`;
8498
+ const list2 = \u51FA\u308B\u7DDA.get(key2) ?? [];
8499
+ list2.push(e);
8500
+ \u51FA\u308B\u7DDA.set(key2, list2);
8501
+ }
8406
8502
  if (!nmap.has(e.to)) continue;
8407
8503
  if ((\u540C\u3058\u7D44\u306E\u6570.get(`${e.from}->${e.to}`) ?? 0) > 1) continue;
8408
8504
  const key = `${e.to}::${e.toSide}`;
@@ -8410,27 +8506,48 @@ function fanIncomingEndpoints(edges, nodes) {
8410
8506
  list.push(e);
8411
8507
  \u675F.set(key, list);
8412
8508
  }
8413
- for (const [, list] of \u675F) {
8414
- if (list.length < 2) continue;
8509
+ for (const [key, list] of \u675F) {
8510
+ const \u4E2D\u592E\u304C\u585E\u304C\u3063\u3066\u3044\u308B = (\u51FA\u308B\u7DDA.get(key) ?? []).some(
8511
+ (\u51FA\u7DDA) => list.some(
8512
+ (\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
8513
+ )
8514
+ );
8515
+ if (list.length < 2 && !\u4E2D\u592E\u304C\u585E\u304C\u3063\u3066\u3044\u308B) continue;
8415
8516
  const n = nmap.get(list[0].to);
8416
8517
  const \u6A2A = list[0].toSide === "left" || list[0].toSide === "right";
8417
8518
  const \u8FBA\u306E\u9577\u3055 = \u6A2A ? n.h : n.w;
8418
8519
  const \u4F7F\u3048\u308B\u5E452 = \u8FBA\u306E\u9577\u3055 - 2 * ARROW_ENDPOINT_CENTER_TOL;
8419
8520
  if (\u4F7F\u3048\u308B\u5E452 <= 0) continue;
8420
- const \u9593\u9694 = Math.min(ENDPOINT_FAN_STEP, \u4F7F\u3048\u308B\u5E452 / (list.length - 1));
8521
+ const \u5E2D\u306E\u9593 = \u4E2D\u592E\u304C\u585E\u304C\u3063\u3066\u3044\u308B ? list.length : list.length - 1;
8522
+ const \u9593\u9694 = Math.min(ENDPOINT_FAN_STEP, \u4F7F\u3048\u308B\u5E452 / \u5E2D\u306E\u9593);
8421
8523
  if (\u9593\u9694 < ENDPOINT_FAN_MIN) continue;
8422
- 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));
8524
+ const \u8FBA\u306E\u4E2D\u5FC3 = \u6A2A ? n.cy : n.cx;
8525
+ const \u4E26\u3073 = list.map((e) => {
8526
+ const \u533A\u9593 = extractPathSegments(e.d);
8527
+ const last = \u533A\u9593[\u533A\u9593.length - 1];
8528
+ const \u9577\u3044\u52A9\u8D70 = last === void 0 ? 0 : Math.hypot(last.x2 - last.x1, last.y2 - last.y1);
8529
+ const \u4E2D\u5FC3\u3092\u88DC\u3046 = \u4E2D\u592E\u304C\u585E\u304C\u3063\u3066\u3044\u308B || list.length === 2;
8530
+ 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);
8531
+ return { e, \u9577\u3044\u52A9\u8D70, \u6DF1\u3055 };
8532
+ }).sort((a, b) => a.\u6DF1\u3055 - b.\u6DF1\u3055 || (a.e.id < b.e.id ? -1 : 1));
8423
8533
  const \u4E2D\u5FC3 = (\u4E26\u3073.length - 1) * \u9593\u9694 / 2;
8534
+ let \u8CA0\u5074\u306E\u5E2D = 0;
8535
+ let \u6B63\u5074\u306E\u5E2D = 0;
8424
8536
  for (let k = 0; k < \u4E26\u3073.length; k++) {
8425
- const d = k * \u9593\u9694 - \u4E2D\u5FC3;
8537
+ 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;
8426
8538
  if (Math.abs(d) < 1e-3) continue;
8427
8539
  const e = \u4E26\u3073[k].e;
8428
- const \u5DEE\u66FF = \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \u6A2A, d, nodes);
8429
- if (\u5DEE\u66FF === null) continue;
8430
8540
  const \u524D = e.d;
8431
8541
  const \u524D\u306E\u4EA4\u5DEE = countEdgeCrossings(edges).count;
8432
- e.d = \u5DEE\u66FF;
8433
- if (countEdgeCrossings(edges).count > \u524D\u306E\u4EA4\u5DEE) e.d = \u524D;
8542
+ const \u9577\u3044\u52A9\u8D70 = \u4E26\u3073[k].\u9577\u3044\u52A9\u8D70;
8543
+ for (const \u52A9\u8D70 of [\u9577\u3044\u52A9\u8D70, ENDPOINT_FAN_RUNUP]) {
8544
+ e.d = \u524D;
8545
+ const \u5DEE\u66FF = \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \u6A2A, d, \u52A9\u8D70, nodes);
8546
+ if (\u5DEE\u66FF === null) continue;
8547
+ e.d = \u5DEE\u66FF;
8548
+ if (countEdgeCrossings(edges).count <= \u524D\u306E\u4EA4\u5DEE) break;
8549
+ e.d = \u524D;
8550
+ }
8434
8551
  }
8435
8552
  }
8436
8553
  }
@@ -8443,7 +8560,7 @@ function \u8FBA\u304B\u3089\u96E2\u308C\u305F\u5074\u306E\u4F4D\u7F6E(e, \u6A2A)
8443
8560
  }
8444
8561
  return null;
8445
8562
  }
8446
- function \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \u6A2A, d, nodes) {
8563
+ function \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \u6A2A, d, \u52A9\u8D70, nodes) {
8447
8564
  if ((e.d.match(/M/g) ?? []).length !== 1) return null;
8448
8565
  const segs = extractPathSegments(e.d);
8449
8566
  if (segs.length === 0) return null;
@@ -8456,7 +8573,8 @@ function \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \
8456
8573
  if (\u9577\u3055 < ENDPOINT_FAN_RUNUP + 1) return null;
8457
8574
  const ux = (last.x1 - last.x2) / \u9577\u3055;
8458
8575
  const uy = (last.y1 - last.y2) / \u9577\u3055;
8459
- const \u6298\u308C1 = { x: last.x2 + ux * ENDPOINT_FAN_RUNUP, y: last.y2 + uy * ENDPOINT_FAN_RUNUP };
8576
+ const \u4E38\u3081\u305F\u52A9\u8D70 = Math.min(\u52A9\u8D70, \u9577\u3055);
8577
+ const \u6298\u308C1 = { x: last.x2 + ux * \u4E38\u3081\u305F\u52A9\u8D70, y: last.y2 + uy * \u4E38\u3081\u305F\u52A9\u8D70 };
8460
8578
  const \u6298\u308C2 = \u6A2A ? { x: \u6298\u308C1.x, y: \u6298\u308C1.y + d } : { x: \u6298\u308C1.x + d, y: \u6298\u308C1.y };
8461
8579
  const \u7D42\u70B9 = \u6A2A ? { x: last.x2, y: last.y2 + d } : { x: last.x2 + d, y: last.y2 };
8462
8580
  const \u65B0\u533A\u9593 = [
@@ -8478,7 +8596,8 @@ function \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \
8478
8596
  }
8479
8597
  parts.push(`L ${s.x2} ${s.y2}`);
8480
8598
  }
8481
- parts.push(`L ${round1(\u6298\u308C1.x)} ${round1(\u6298\u308C1.y)}`);
8599
+ 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;
8600
+ if (!\u6298\u308C1\u306F\u76F4\u524D\u306E\u6298\u308C) parts.push(`L ${round1(\u6298\u308C1.x)} ${round1(\u6298\u308C1.y)}`);
8482
8601
  parts.push(`L ${round1(\u6298\u308C2.x)} ${round1(\u6298\u308C2.y)}`);
8483
8602
  parts.push(`L ${round1(\u7D42\u70B9.x)} ${round1(\u7D42\u70B9.y)}`);
8484
8603
  return parts.join(" ");
@@ -8961,6 +9080,7 @@ function layout(diag) {
8961
9080
  diag.edges.filter((e) => e.posX1 !== void 0 && e.posY1 !== void 0 && e.posX2 !== void 0 && e.posY2 !== void 0).map((e) => e.id)
8962
9081
  );
8963
9082
  bowSharedStraightPaths(edges, nodesFinal, positionedEdgeIds);
9083
+ pullOutgoingFirstCorner(edges, nodesFinal);
8964
9084
  fanIncomingEndpoints(edges, nodesFinal);
8965
9085
  separateSharedStraightRuns(edges, nodesFinal);
8966
9086
  hopEdgeCrossings(edges);
@@ -9002,6 +9122,8 @@ function layout(diag) {
9002
9122
  // **遮断はここだけに置く**。 描画は必ず組み立てを通り、組み立て API も `er` も
9003
9123
  // 素通しにしてある。 上流にも置くと、どの入力でも通らない分岐が残る
9004
9124
  ...diag.palette ? { palette: diag.palette } : {},
9125
+ // 種類も配色と同じく空の目印を出さない。 遮断をここに揃えると手書きの図にも効く
9126
+ ...diag.type ? { type: diag.type } : {},
9005
9127
  bboxes,
9006
9128
  collisions,
9007
9129
  nearCollisions,
@@ -17204,6 +17326,7 @@ function CdlStage({
17204
17326
  "data-cdl-stage": "",
17205
17327
  "data-cdl-scale": diagramScale === 1 ? void 0 : diagramScale,
17206
17328
  "data-cdl-palette": laid.palette,
17329
+ "data-cdl-type": laid.type,
17207
17330
  children: [
17208
17331
  /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
17209
17332
  Object.entries(TONE).flatMap(