@cardenelabs/cdl 0.52.0 → 0.53.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cardenelabs/cdl",
3
- "version": "0.52.0",
3
+ "version": "0.53.0",
4
4
  "description": "CDL (Chainome Diagram Language). Mermaid-like declarative DSL that compiles to animated SVG diagrams. Built for blockchain / Solidity flows, generic enough for sequence / flow / state / ER / topology diagrams.",
5
5
  "license": "MIT",
6
6
  "author": "cardene777",
@@ -42,6 +42,30 @@ const 箱の高さ = Math.round(端の字の大きさ * 1.2);
42
42
  /** 字の大きさに対する baseline の深さ。 等幅の字の ascent が字の大きさの 8 割ほど */
43
43
  const BASELINE_RATIO = 0.8;
44
44
 
45
+ /**
46
+ * 両端に字がある線で、2 つの字の間に空ける長さ (world)。
47
+ *
48
+ * 字と自分の端の間 (`端の字を戻す距離`) の 2 倍にする = 字が自分の端より相手の字の近くに
49
+ * 見えなくなる。 実測で、間が 10 だった短い縦の線 (長さ 100) は 2 つの字が 2 行の札のように
50
+ * 読まれ、どちらの端の数かが分からなかった (#829)。
51
+ */
52
+ export const 両端の字の間 = 端の字を戻す距離 * 2;
53
+
54
+ /**
55
+ * 端の字を線の同じ側に並べた時、線に沿って要る長さ (world)。 字が無い線は 0。
56
+ *
57
+ * 字は端から `端の字を戻す距離` 戻った所から、線に沿って `箱の高さ` だけ占める (縦向きの時)。
58
+ * 両端にあれば、その 2 つの間に `両端の字の間` を足す。 縦に隣り合う箱の間隔を決める
59
+ * `layout/nodes.ts` が使う = 間隔が線の長さそのものになる形だけが対象。
60
+ */
61
+ export function 端の字に要る線の長さ(edge: { headLabel?: string; tailLabel?: string }): number {
62
+ const 一つ分 = 端の字を戻す距離 + 箱の高さ;
63
+ const 数 = [edge.headLabel, edge.tailLabel].filter((t) => t?.trim()).length;
64
+ if (数 === 0) return 0;
65
+ if (数 === 1) return 一つ分;
66
+ return 一つ分 * 2 + 両端の字の間;
67
+ }
68
+
45
69
  /** どちらの端か。 `head` = 行き先 (`to`)、 `tail` = 出どころ (`from`) */
46
70
  export type 線の端 = "head" | "tail";
47
71
 
@@ -1,5 +1,6 @@
1
1
  import { requiredRowsWidth } from "../kinds/row-align";
2
2
  import type { CdlDiagram, LaidLane, LaidNode } from "../types";
3
+ import { 端の字に要る線の長さ } from "./head-label";
3
4
  import {
4
5
  hasRenderedLabel,
5
6
  labelPillH,
@@ -138,9 +139,9 @@ function requiredStackGapForEdgeLabels(diag: CdlDiagram, allStacks: readonly num
138
139
 
139
140
  // 同じ隙間 (lane + 上側 row の rank) を通る label の pill 高を集める。
140
141
  const pillHsByGap = new Map<string, number[]>();
142
+ // 端の字 (#829) は線の端から測るので、隙間ごとに集めず線 1 本ずつの長さで足りる
143
+ let 端の字の要求 = 0;
141
144
  for (const e of diag.edges) {
142
- // `label` が空でも `sub` があれば pill は描かれ、 その高さ (68) の分だけ隙間が要る (Issue #224)。
143
- if (!hasRenderedLabel(e)) continue;
144
145
  const from = byId.get(e.from);
145
146
  const to = byId.get(e.to);
146
147
  if (!from || !to) continue;
@@ -149,11 +150,14 @@ function requiredStackGapForEdgeLabels(diag: CdlDiagram, allStacks: readonly num
149
150
  const toRank = rankOf.get(to.stack);
150
151
  if (fromRank === undefined || toRank === undefined) continue;
151
152
  if (Math.abs(fromRank - toRank) !== 1) continue;
153
+ 端の字の要求 = Math.max(端の字の要求, 端の字に要る線の長さ(e));
154
+ // `label` が空でも `sub` があれば pill は描かれ、 その高さ (68) の分だけ隙間が要る (Issue #224)。
155
+ if (!hasRenderedLabel(e)) continue;
152
156
  const key = `${from.lane}::${Math.min(fromRank, toRank)}`;
153
157
  pillHsByGap.set(key, [...(pillHsByGap.get(key) ?? []), labelPillH(e.sub)]);
154
158
  }
155
159
 
156
- let required = 0;
160
+ let required = 端の字の要求;
157
161
  for (const pillHs of pillHsByGap.values()) {
158
162
  required = Math.max(required, requiredVerticalLabelGap(pillHs));
159
163
  }