@cardenelabs/cdl 0.42.0 → 0.44.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/CHANGELOG.md CHANGED
@@ -5,6 +5,77 @@ CDL (Chainome Diagram Language) の主要変更履歴。
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.44.0] - 2026-09-10
9
+
10
+ ### Fixed
11
+
12
+ - **読みにくさを図の幅でなく描かれる倍率で判定するようにした** (軸 23 `responsive-viewport`、#793)
13
+
14
+ 図は `preserveAspectRatio="xMidYMid meet"` で器に収まるよう中で縮む。 効く倍率は
15
+ `min(器の幅 ÷ viewBox 幅, 器の高さ ÷ viewBox 高さ)` で、横が余っていても縦が足りなければ
16
+ 縦が決める。 `#785` で縦横比から幅の上限へ移した時に、**高さの項が抜けていた**。
17
+
18
+ 下流の見本帳を Chromium で開いて実測した (画面 1440 × 900、拡大表示)。
19
+ 28 回の実測のうち 27 回で縦が倍率を決めていた。
20
+
21
+ | 図 | viewBox | 幅から出す見込み | 実測 |
22
+ |---|---|---|---|
23
+ | `多対多が-2-組-8-表-8-関係` | 1255x1700 | 19.3px | 8.2px |
24
+ | `interactive-price-candlestick` | 875x1256 | 27.7px | 11.0px |
25
+ | `fsm-demo` | 1413x1393 | 17.1px | 9.9px |
26
+ | `er-complex-demo` | 2190x2904 | 11.1px | 4.8px |
27
+ | `swim-demo` | 1848x285 | 13.1px | 13.7px |
28
+
29
+ 順位も逆を向いていた。 `er-complex-demo` は見込みで 14 枚中 9 位だが実測は最下位で、
30
+ 拡大すると並べて見る時 (8.8px) より小さくなる。
31
+
32
+ 判定を倍率の下限に置き換えた。 器は画面での実測から導く = 幅は拡大表示の枠
33
+ `min(1200px, 94vw)` から縁 1px × 2 と余白 24px × 2 を引いた 1150px、高さは
34
+ `90vh − 180px` を画面の高さ 900px で評価した 630px。 数は直接書かない。
35
+
36
+ この式に実測の器を入れると、上の 5 枚とも画面での実測と 0.1px まで一致する。
37
+
38
+ 注意の文面が変わる = viewBox の縦横の寸法、器の寸法、倍率、**どちらの辺が効いたか**、
39
+ その辺で下限に届く寸法を出す。 効いた辺を出さないと、幅を削っても直らない図で
40
+ 書き手が幅を削り続けることになる。
41
+
42
+ 下流では注意の件数が増える (実測 = 見本帳 444 枚で 12 件 → 20 件)。
43
+ 増える 10 枚はいずれも縦が長い図で、画面では 8.2-11.9px しかない。
44
+ 描画不能な寸法 (0 / 負値 / 非有限) の判定は変えていない。
45
+
46
+ ## [0.43.0] - 2026-09-10
47
+
48
+ ### Fixed
49
+
50
+ - **帯の間隔を箱の縁から数えるようにした** (#789)
51
+
52
+ 帯 (lane) の間隔は、辺の名札を入れるのに要る隙間から決まる。 その隙間の式は
53
+ `名札の幅 + 箱と名札の余白 32 × 2 + 経路の突き出し 40 × 2` で、内訳はどれも
54
+ **箱の縁** が起点になる。 それを 帯の縁 から数えていたため、
55
+ `(帯の幅 − 箱の幅) / 2` を 2 枚分 余計に空けていた。
56
+
57
+ ただし 2 対以上を跨ぐ辺は別で、名札が途中の帯の内側にも入りうる。 その帯は
58
+ 軸 64 `lane-border-clearance` の対象なので、跨ぐ辺だけは 帯の縁 のまま残す。
59
+ 隣り合う 2 帯を結ぶ辺の名札は発着の 2 帯に閉じるので、軸 64 は元から見ていない。
60
+
61
+ 下流の見本帳 444 枚での実測。
62
+
63
+ | 何を | 前 | 後 |
64
+ |---|---|---|
65
+ | 幅が変わった図 | — | 78 枚 (広がった図は 0 枚) |
66
+ | その 78 枚の幅の合計 | 126,204 | 118,721 |
67
+ | 軸 23 `responsive-viewport` | 16 件 | 12 件 |
68
+ | 軸 64 `lane-border-clearance` | 0 件 | 0 件 |
69
+ | 軸 65 `row-gap-uniform` | 0 件 | 0 件 |
70
+
71
+ 最も縮んだのは `swim-demo` の 2148 → 1848 で、親の幅 1100px での箱の題が
72
+ 11.3px から 13.1px になる。
73
+
74
+ **余りに頼っていた図が 2 枚出る**。 名札を 2 枚以上 同じ隙間に置く図は、
75
+ 1 枚分しか確保しない式では元から足りておらず、余りがそれを隠していた
76
+ (実測 = `interactive-traffic-sankey` で 3 件、`animation-rich-order-status-flow` で 1 件)。
77
+ 帯の位置を書き手が広げれば消える。
78
+
8
79
  ## [0.42.0] - 2026-09-10
9
80
 
10
81
  ### Fixed
@@ -2196,7 +2267,9 @@ Initial OSS release.
2196
2267
  使わない = annotated tag を push しても GitHub Release は作られず、 Release を作っていない版で
2197
2268
  行き止まりになる。
2198
2269
 
2199
- [Unreleased]: https://github.com/cardene777/cdl/compare/v0.42.0...HEAD
2270
+ [Unreleased]: https://github.com/cardene777/cdl/compare/v0.44.0...HEAD
2271
+ [0.44.0]: https://github.com/cardene777/cdl/compare/v0.43.0...v0.44.0
2272
+ [0.43.0]: https://github.com/cardene777/cdl/compare/v0.42.0...v0.43.0
2200
2273
  [0.42.0]: https://github.com/cardene777/cdl/compare/v0.41.1...v0.42.0
2201
2274
  [0.41.1]: https://github.com/cardene777/cdl/compare/v0.41.0...v0.41.1
2202
2275
  [0.41.0]: https://github.com/cardene777/cdl/compare/v0.40.12...v0.41.0
package/dist/index.cjs CHANGED
@@ -16929,10 +16929,16 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes) {
16929
16929
  } catch {
16930
16930
  }
16931
16931
  }
16932
- const RESPONSIVE_REF_CONTAINER_PX = 1100;
16932
+ const RESPONSIVE_REF_FRAME_W_PX = 1200;
16933
+ const RESPONSIVE_REF_FRAME_BORDER_PX = 1;
16934
+ const RESPONSIVE_REF_FRAME_PAD_PX = 24;
16935
+ const RESPONSIVE_REF_CONTAINER_W_PX = RESPONSIVE_REF_FRAME_W_PX - RESPONSIVE_REF_FRAME_BORDER_PX * 2 - RESPONSIVE_REF_FRAME_PAD_PX * 2;
16936
+ const RESPONSIVE_REF_VIEWPORT_H_PX = 900;
16937
+ const RESPONSIVE_REF_FRAME_H_RATIO = 0.9;
16938
+ const RESPONSIVE_REF_CHROME_H_PX = 180;
16939
+ const RESPONSIVE_REF_CONTAINER_H_PX = RESPONSIVE_REF_VIEWPORT_H_PX * RESPONSIVE_REF_FRAME_H_RATIO - RESPONSIVE_REF_CHROME_H_PX;
16933
16940
  const RESPONSIVE_MIN_ON_SCREEN_FONT_PX = 12;
16934
16941
  const RESPONSIVE_BASE_FONT_WORLD = 22;
16935
- const RESPONSIVE_MAX_VIEWBOX_W = RESPONSIVE_BASE_FONT_WORLD * RESPONSIVE_REF_CONTAINER_PX / RESPONSIVE_MIN_ON_SCREEN_FONT_PX;
16936
16942
  const vbResp = laid.viewBox;
16937
16943
  if (!(vbResp.w > 0) || !(vbResp.h > 0) || !Number.isFinite(vbResp.w) || !Number.isFinite(vbResp.h)) {
16938
16944
  push(
@@ -16940,13 +16946,20 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes) {
16940
16946
  `viewBox \u5BF8\u6CD5 ${vbResp.w}\xD7${vbResp.h} \u304C\u63CF\u753B\u4E0D\u80FD (\u6B63\u306E\u6709\u9650\u5024\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308B)`,
16941
16947
  "warn"
16942
16948
  );
16943
- } else if (vbResp.w > RESPONSIVE_MAX_VIEWBOX_W) {
16944
- const \u753B\u9762\u4E0A\u306E\u5B57 = RESPONSIVE_BASE_FONT_WORLD * RESPONSIVE_REF_CONTAINER_PX / vbResp.w;
16945
- push(
16946
- "responsive-viewport",
16947
- `viewBox width ${vbResp.w} \u304C\u4E0A\u9650 ${RESPONSIVE_MAX_VIEWBOX_W.toFixed(0)} \u8D85\u3048 (\u89AA\u5E45 ${RESPONSIVE_REF_CONTAINER_PX}px \u3067\u7BB1\u306E\u984C\u304C ${\u753B\u9762\u4E0A\u306E\u5B57.toFixed(1)}px\u3001 \u4E0B\u9650 ${RESPONSIVE_MIN_ON_SCREEN_FONT_PX}px)`,
16948
- "warn"
16949
- );
16949
+ } else {
16950
+ const \u6A2A\u306E\u500D\u7387 = RESPONSIVE_REF_CONTAINER_W_PX / vbResp.w;
16951
+ const \u7E26\u306E\u500D\u7387 = RESPONSIVE_REF_CONTAINER_H_PX / vbResp.h;
16952
+ const \u500D\u7387 = Math.min(\u6A2A\u306E\u500D\u7387, \u7E26\u306E\u500D\u7387);
16953
+ const \u753B\u9762\u4E0A\u306E\u5B57 = RESPONSIVE_BASE_FONT_WORLD * \u500D\u7387;
16954
+ if (\u753B\u9762\u4E0A\u306E\u5B57 < RESPONSIVE_MIN_ON_SCREEN_FONT_PX) {
16955
+ const \u52B9\u304F\u8FBA = \u6A2A\u306E\u500D\u7387 <= \u7E26\u306E\u500D\u7387 ? "\u6A2A" : "\u7E26";
16956
+ const \u53CE\u307E\u308B\u5BF8\u6CD5 = \u52B9\u304F\u8FBA === "\u6A2A" ? `\u5E45 ${(RESPONSIVE_REF_CONTAINER_W_PX * RESPONSIVE_BASE_FONT_WORLD / RESPONSIVE_MIN_ON_SCREEN_FONT_PX).toFixed(0)} \u4EE5\u4E0B` : `\u9AD8\u3055 ${(RESPONSIVE_REF_CONTAINER_H_PX * RESPONSIVE_BASE_FONT_WORLD / RESPONSIVE_MIN_ON_SCREEN_FONT_PX).toFixed(0)} \u4EE5\u4E0B`;
16957
+ push(
16958
+ "responsive-viewport",
16959
+ `viewBox ${vbResp.w}\xD7${vbResp.h} \u306F\u5668 ${RESPONSIVE_REF_CONTAINER_W_PX}\xD7${RESPONSIVE_REF_CONTAINER_H_PX}px \u3067 ${\u500D\u7387.toFixed(3)} \u500D\u306B\u7E2E\u307F\u3001 \u7BB1\u306E\u984C\u304C ${\u753B\u9762\u4E0A\u306E\u5B57.toFixed(1)}px \u306B\u306A\u308B (\u4E0B\u9650 ${RESPONSIVE_MIN_ON_SCREEN_FONT_PX}px\u3001 \u500D\u7387\u3092\u6C7A\u3081\u305F\u306E\u306F ${\u52B9\u304F\u8FBA}\u3001 ${\u53CE\u307E\u308B\u5BF8\u6CD5}\u306B\u3059\u308B\u3068\u5C4A\u304F)`,
16960
+ "warn"
16961
+ );
16962
+ }
16950
16963
  }
16951
16964
  if (!(diag.topic?.trim() ?? "")) {
16952
16965
  push(
@@ -20217,7 +20230,8 @@ function expandLaneGapsForEdgeLabels(lanes, nodes, edges) {
20217
20230
  const nodeById = new Map(nodes.map((n) => [n.id, n]));
20218
20231
  const sortedByX = [...layoutedLanes].sort((a, b) => a.x - b.x);
20219
20232
  const laneIndexById = new Map(sortedByX.map((lane, i) => [lane.id, i]));
20220
- const requiredBoxWByPair = new Array(Math.max(0, sortedByX.length - 1)).fill(0);
20233
+ const requiredBoxWAdjacent = new Array(Math.max(0, sortedByX.length - 1)).fill(0);
20234
+ const requiredBoxWSpanning = new Array(Math.max(0, sortedByX.length - 1)).fill(0);
20221
20235
  for (const edge of edges) {
20222
20236
  const fromLane = nodeById.get(edge.from)?.lane;
20223
20237
  const toLane = nodeById.get(edge.to)?.lane;
@@ -20229,23 +20243,33 @@ function expandLaneGapsForEdgeLabels(lanes, nodes, edges) {
20229
20243
  if (labelBoxW === 0) continue;
20230
20244
  const lo = Math.min(fi, ti);
20231
20245
  const hi = Math.max(fi, ti);
20246
+ const \u8981\u6C42 = hi - lo === 1 ? requiredBoxWAdjacent : requiredBoxWSpanning;
20232
20247
  for (let pair = lo; pair < hi; pair++) {
20233
- if (labelBoxW > requiredBoxWByPair[pair]) requiredBoxWByPair[pair] = labelBoxW;
20248
+ if (labelBoxW > \u8981\u6C42[pair]) \u8981\u6C42[pair] = labelBoxW;
20234
20249
  }
20235
20250
  }
20251
+ const \u7BB1\u306E\u534A\u5E45 = /* @__PURE__ */ new Map();
20252
+ for (const n of nodes) {
20253
+ const \u4ECA = \u7BB1\u306E\u534A\u5E45.get(n.lane) ?? 0;
20254
+ if (n.w / 2 > \u4ECA) \u7BB1\u306E\u534A\u5E45.set(n.lane, n.w / 2);
20255
+ }
20236
20256
  const requiredPitchByPair = [];
20237
20257
  for (let i = 0; i < sortedByX.length - 1; i++) {
20238
20258
  const lane = sortedByX[i];
20239
20259
  const rightLane = sortedByX[i + 1];
20240
- const halfSum = lane.width / 2 + rightLane.width / 2;
20260
+ const laneHalfSum = lane.width / 2 + rightLane.width / 2;
20261
+ const nodeHalfSum = (\u7BB1\u306E\u534A\u5E45.get(lane.id) ?? 0) + (\u7BB1\u306E\u534A\u5E45.get(rightLane.id) ?? 0);
20241
20262
  const currentPitch = rightLane.x + rightLane.width / 2 - (lane.x + lane.width / 2);
20242
- const maxLabelBoxW = requiredBoxWByPair[i];
20243
- if (maxLabelBoxW === 0) {
20263
+ const \u96A3 = requiredBoxWAdjacent[i];
20264
+ const \u8DE8 = requiredBoxWSpanning[i];
20265
+ if (\u96A3 === 0 && \u8DE8 === 0) {
20244
20266
  requiredPitchByPair.push(currentPitch);
20245
20267
  continue;
20246
20268
  }
20247
- const requiredGap = maxLabelBoxW + CLEARANCE_NODE_LABEL * 2 + EDGE_STUB_OUT * 2;
20248
- requiredPitchByPair.push(Math.max(currentPitch, requiredGap + halfSum));
20269
+ const \u4E0A\u4E57\u305B = CLEARANCE_NODE_LABEL * 2 + EDGE_STUB_OUT * 2;
20270
+ const \u96A3\u306E\u8981\u6C42 = \u96A3 === 0 ? 0 : \u96A3 + \u4E0A\u4E57\u305B + nodeHalfSum;
20271
+ const \u8DE8\u306E\u8981\u6C42 = \u8DE8 === 0 ? 0 : \u8DE8 + \u4E0A\u4E57\u305B + laneHalfSum;
20272
+ requiredPitchByPair.push(Math.max(currentPitch, \u96A3\u306E\u8981\u6C42, \u8DE8\u306E\u8981\u6C42));
20249
20273
  }
20250
20274
  const targetPitch = Math.ceil(Math.max(...requiredPitchByPair));
20251
20275
  const shiftedXById = /* @__PURE__ */ new Map();