@cardenelabs/cdl 0.40.2 → 0.40.4

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.40.2",
3
+ "version": "0.40.4",
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",
@@ -1,4 +1,4 @@
1
- import { clamp01, easeOutQuint } from "./easing";
1
+ import { clamp01, easeOut } from "./easing";
2
2
  import type {
3
3
  EasingFn,
4
4
  PhaseDescriptor,
@@ -30,7 +30,7 @@ import type {
30
30
  export type TimelineOptions = {
31
31
  /** 自動進行時の Phase 間 wait (ms)、 デフォルト Phase の durationMs に従う */
32
32
  autoAdvanceMs?: number;
33
- /** Phase 内補間の easing、 デフォルト easeOutQuint */
33
+ /** Phase 内補間の easing、 デフォルト easeOut */
34
34
  easing?: EasingFn;
35
35
  /** loop 再生するか (settled 後に最初に戻る)、 デフォルト false */
36
36
  loop?: boolean;
@@ -86,7 +86,17 @@ export class Timeline {
86
86
  throw new Error("Timeline requires at least one phase");
87
87
  }
88
88
  this.phases = phases;
89
- this.easing = options.easing ?? easeOutQuint;
89
+ /**
90
+ * 既定の曲線 (cdl#736)。
91
+ *
92
+ * **`easeOutQuint` は動きが前半に寄りすぎる**。 実測で、段の長さ 1.2 秒の tween は
93
+ * 9 割が最初の 0.449 秒で終わり、残りの 0.75 秒はほとんど止まって見えた
94
+ * (半分に達するのが段の 13.1% の時点)。 段を長くしても形は変わらず、止まって
95
+ * 見える時間だけが伸びる。
96
+ *
97
+ * `easeOut` は半分に達するのが 34.2% の時点で、段の終わりまで動き続ける。
98
+ */
99
+ this.easing = options.easing ?? easeOut;
90
100
  this.loop = options.loop ?? false;
91
101
  this.autoAdvanceMsOverride = options.autoAdvanceMs;
92
102
  this.phaseHoldMs = options.phaseHoldMs ?? 0;
@@ -40,7 +40,7 @@ export type TimelineState = {
40
40
  /**
41
41
  * 曲線を通す前の進行度 (0..1、 cdl#711)。 経過時間そのものの割合。
42
42
  *
43
- * `phaseProgress` は既定で `easeOutQuint` を通るため前半に動きが寄る。
43
+ * `phaseProgress` は既定で `easeOut` を通るため素の進みより先に出る。
44
44
  * **値が落ち着く動きには合うが、 線を引く動きには合わない** =
45
45
  * `1.2s` の段で半分に達するのが 158 ms になり、 折れ線の 5 点のうち 4 点が
46
46
  * 292 ms の間に出てしまう (実測)。
@@ -65,10 +65,43 @@ export function ChartGaugeNode({
65
65
 
66
66
  const 名前の級 = 14;
67
67
  const 数値の級 = 13;
68
- /** 内訳の 1 件が縦に使う高さ (印 + 名前 + 数値) */
69
- const 内訳の高さ = 56;
68
+ /** 内訳の 1 段が縦に使う高さ (印 + 名前 + 数値) */
69
+ const 段の高さ = 56;
70
70
  /** 弧と内訳の間 */
71
71
  const 弧と内訳の間 = 16;
72
+ /** 色の印の幅と、区画どうしの間 */
73
+ const 印の幅 = 30;
74
+ const 区画の間 = 12;
75
+
76
+ /**
77
+ * 内訳の割付 (cdl#731)。
78
+ *
79
+ * **件数で等分するだけでは足りない**。 名前は区画に収まるまで切り詰めていたが数値は
80
+ * そのままだったので、件数が増えると数字が隣へはみ出してくっついた
81
+ * (実測で件数 10 から重なり始め、12 で 10 組)。
82
+ *
83
+ * 区画の幅を **中身から決めて**、1 行に置ける件数を出す。 余りは次の段へ送る。
84
+ * 段が増えたぶん弧は低くなる = 弧の高さは残りから決めているので自動で縮む。
85
+ *
86
+ * 級を下げて 1 行に収める案は採らない = 件数 12 では級 7.7 が要り、この repo が
87
+ * 他の図で使っている下限の 9 を下回る。
88
+ */
89
+ const 内訳の数値 = data.map((d) => `${実値表記(d.value)} ${割合表記(d.value / total)}`);
90
+
91
+ /**
92
+ * 内訳 1 件が横に要る幅。 数値の行と色の印の広い方に、区画どうしの間を足す。
93
+ *
94
+ * **印の幅が広い方になる入力は組めない** = 数値の行は最も短い形 (`1 50%`) でも級 13 で
95
+ * 幅 56.7 あり、印の 30 を必ず上回る。 件数 0 の図で `Math.max` の引数が空になるのを
96
+ * 防ぐ下限として置いている。 万一この関係が崩れても印は区画に合わせて縮む (下の `Math.min`)。
97
+ */
98
+ const 件に要る幅 = Math.max(印の幅, ...内訳の数値.map((t) => textWidth(t, 数値の級))) + 区画の間;
99
+ const 行の件数 = Math.min(
100
+ Math.max(1, Math.floor(使える幅 / Math.max(件に要る幅, 1))),
101
+ Math.max(data.length, 1),
102
+ );
103
+ const 内訳の段数 = Math.ceil(Math.max(data.length, 1) / 行の件数);
104
+ const 内訳の高さ = 段の高さ * 内訳の段数;
72
105
 
73
106
  /**
74
107
  * 弧の外半径。
@@ -123,8 +156,8 @@ export function ChartGaugeNode({
123
156
  const 合計の級 = Math.max(11, Math.round(級の候補));
124
157
  const 見出しの級 = Math.max(9, Math.round(合計の級 * 0.38));
125
158
 
126
- /** 内訳 1 件あたりの幅。 等分して左から並べる */
127
- const 内訳の幅 = 使える幅 / Math.max(data.length, 1);
159
+ /** 内訳 1 件あたりの幅。 1 行に置く件数で等分する */
160
+ const 内訳の幅 = 使える幅 / 行の件数;
128
161
  const 内訳のy = cy + 弧と内訳の間;
129
162
 
130
163
  /** 弧がどこまで伸びたか (0..1、 cdl#715)。 畳み方は `draw-progress.ts` が持つ */
@@ -207,22 +240,34 @@ export function ChartGaugeNode({
207
240
  字は区画の左端に揃える。 中央揃えにすると名前の長さで位置が動き、 縦の列が揃わない。
208
241
  */}
209
242
  {data.map((d, idx) => {
210
- const x = PAD_SIDE + 内訳の幅 * idx;
211
- const 数値 = `${実値表記(d.value)} ${割合表記(d.value / total)}`;
243
+ const 列 = idx % 行の件数;
244
+ const 段 = Math.floor(idx / 行の件数);
245
+ const x = PAD_SIDE + 内訳の幅 * 列;
246
+ const y = 内訳のy + 段の高さ * 段;
247
+ /** 区画に収まる字幅。 名前も数値も同じ幅で切る */
248
+ const 収まる幅 = 内訳の幅 - 区画の間;
212
249
  return (
213
250
  <g key={`legend-${idx}`} data-cdl-role="chart-gauge-item">
214
- <rect x={x} y={内訳のy} width={30} height={4} rx={2} fill={arcColor(d.tone, idx)} />
251
+ <rect
252
+ x={x}
253
+ y={y}
254
+ width={Math.max(4, Math.min(印の幅, 収まる幅))}
255
+ height={4}
256
+ rx={2}
257
+ fill={arcColor(d.tone, idx)}
258
+ />
215
259
  <text
216
260
  x={x}
217
- y={内訳のy + 26}
261
+ y={y + 26}
218
262
  fontSize={名前の級}
219
263
  fontWeight={700}
220
264
  fill="var(--cdl-text, #1a1f2a)"
221
265
  >
222
- {切り詰める(d.label ?? "", 内訳の幅 - 12, 名前の級)}
266
+ {切り詰める(d.label ?? "", 収まる幅, 名前の級)}
223
267
  </text>
224
- <text x={x} y={内訳のy + 46} fontSize={数値の級} fill="var(--cdl-text-dim, #5a6270)">
225
- {数値}
268
+ {/* **数値も切り詰める** = 切らないと隣の区画の字とくっつく (cdl#731) */}
269
+ <text x={x} y={y + 46} fontSize={数値の級} fill="var(--cdl-text-dim, #5a6270)">
270
+ {切り詰める(内訳の数値[idx] ?? "", 収まる幅, 数値の級)}
226
271
  </text>
227
272
  </g>
228
273
  );
package/src/render.tsx CHANGED
@@ -136,8 +136,10 @@ export function CdlDiagramView({ diagram, laid: laidProp, hideHeader = false, hi
136
136
  /**
137
137
  * 描く動きが読む進み (cdl#711)。 曲線を通さない = 経過時間そのものの割合。
138
138
  *
139
- * 線を引く動きに `easeOutQuint` を当てると前半に寄り、 折れ線の 5 点のうち 4 点が
140
- * 292 ms の間に出る。 ペンの速さは一定であるほど「1 つずつ現れる」 が読める。
139
+ * 線を引く動きに段の曲線を当てると前半に寄る。 当時の既定 (`easeOutQuint`) では
140
+ * 折れ線の 5 点のうち 4 点が 292 ms の間に出た。 曲線をゆるめた後 (`cdl#736` の
141
+ * `easeOut`) も寄る向きは同じなので、 描く動きは曲線を通さないままにする。
142
+ * ペンの速さは一定であるほど「1 つずつ現れる」 が読める。
141
143
  */
142
144
  const drawProgress = reduced ? 1 : state.phaseLinearProgress;
143
145