@cardenelabs/cdl 0.37.0 → 0.38.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 +25 -1
- package/dist/index.cjs +32 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +32 -13
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +32 -13
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +32 -13
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/src/anim/core/timeline.ts +28 -10
- package/src/anim/core/types.ts +12 -0
- package/src/render/stage.tsx +17 -3
- package/src/render.tsx +8 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cardenelabs/cdl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.38.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",
|
|
@@ -60,6 +60,8 @@ export class Timeline {
|
|
|
60
60
|
private rafHandle: number | null = null;
|
|
61
61
|
private phaseIndex = 0;
|
|
62
62
|
private phaseProgress = 0;
|
|
63
|
+
/** 曲線を通す前の進み (cdl#711)。 経過時間そのものの割合で、 描く動きが読む */
|
|
64
|
+
private phaseLinearProgress = 0;
|
|
63
65
|
private phaseStartedAt = 0;
|
|
64
66
|
private status: TimelineStatus = "idle";
|
|
65
67
|
/**
|
|
@@ -75,7 +77,7 @@ export class Timeline {
|
|
|
75
77
|
*/
|
|
76
78
|
private readonly initialState: {
|
|
77
79
|
phaseIndex: number;
|
|
78
|
-
|
|
80
|
+
phaseLinearProgress: number;
|
|
79
81
|
status: TimelineStatus;
|
|
80
82
|
};
|
|
81
83
|
|
|
@@ -94,12 +96,12 @@ export class Timeline {
|
|
|
94
96
|
const initial = options.initialPhaseIndex;
|
|
95
97
|
if (initial != null && initial > 0 && initial < phases.length) {
|
|
96
98
|
this.phaseIndex = initial;
|
|
97
|
-
this.
|
|
99
|
+
this.setProgress(1);
|
|
98
100
|
this.status = initial === phases.length - 1 ? "settled" : "paused";
|
|
99
101
|
}
|
|
100
102
|
this.initialState = {
|
|
101
103
|
phaseIndex: this.phaseIndex,
|
|
102
|
-
|
|
104
|
+
phaseLinearProgress: this.phaseLinearProgress,
|
|
103
105
|
status: this.status,
|
|
104
106
|
};
|
|
105
107
|
}
|
|
@@ -133,6 +135,7 @@ export class Timeline {
|
|
|
133
135
|
cached.status === this.status &&
|
|
134
136
|
cached.phaseIndex === this.phaseIndex &&
|
|
135
137
|
cached.phaseProgress === this.phaseProgress &&
|
|
138
|
+
cached.phaseLinearProgress === this.phaseLinearProgress &&
|
|
136
139
|
cached.totalPhases === this.phases.length
|
|
137
140
|
) {
|
|
138
141
|
return cached;
|
|
@@ -141,6 +144,7 @@ export class Timeline {
|
|
|
141
144
|
status: this.status,
|
|
142
145
|
phaseIndex: this.phaseIndex,
|
|
143
146
|
phaseProgress: this.phaseProgress,
|
|
147
|
+
phaseLinearProgress: this.phaseLinearProgress,
|
|
144
148
|
totalPhases: this.phases.length,
|
|
145
149
|
};
|
|
146
150
|
this.cachedSnapshot = next;
|
|
@@ -168,7 +172,7 @@ export class Timeline {
|
|
|
168
172
|
const clamped = Math.max(0, Math.min(this.phases.length - 1, index));
|
|
169
173
|
this.cancelRaf();
|
|
170
174
|
this.phaseIndex = clamped;
|
|
171
|
-
this.
|
|
175
|
+
this.setProgress(1);
|
|
172
176
|
this.status = clamped === this.phases.length - 1 ? "settled" : "paused";
|
|
173
177
|
this.emit();
|
|
174
178
|
}
|
|
@@ -212,7 +216,7 @@ export class Timeline {
|
|
|
212
216
|
if (this.phaseIndex <= 0) return;
|
|
213
217
|
this.cancelRaf();
|
|
214
218
|
this.phaseIndex -= 1;
|
|
215
|
-
this.
|
|
219
|
+
this.setProgress(1);
|
|
216
220
|
this.status = "paused";
|
|
217
221
|
this.emit();
|
|
218
222
|
}
|
|
@@ -220,7 +224,7 @@ export class Timeline {
|
|
|
220
224
|
reset(): void {
|
|
221
225
|
this.cancelRaf();
|
|
222
226
|
this.phaseIndex = 0;
|
|
223
|
-
this.
|
|
227
|
+
this.setProgress(0);
|
|
224
228
|
this.status = "idle";
|
|
225
229
|
this.emit();
|
|
226
230
|
}
|
|
@@ -242,7 +246,7 @@ export class Timeline {
|
|
|
242
246
|
this.subscribers.clear();
|
|
243
247
|
this.status = this.initialState.status;
|
|
244
248
|
this.phaseIndex = this.initialState.phaseIndex;
|
|
245
|
-
this.
|
|
249
|
+
this.setProgress(this.initialState.phaseLinearProgress);
|
|
246
250
|
}
|
|
247
251
|
|
|
248
252
|
// ─── internals ───────────────────────────────────────────────
|
|
@@ -284,7 +288,7 @@ export class Timeline {
|
|
|
284
288
|
}
|
|
285
289
|
|
|
286
290
|
private beginPhaseTransition(): void {
|
|
287
|
-
this.
|
|
291
|
+
this.setProgress(0);
|
|
288
292
|
this.phaseStartedAt = performance.now();
|
|
289
293
|
this.cancelRaf();
|
|
290
294
|
const step = (now: number) => {
|
|
@@ -292,13 +296,13 @@ export class Timeline {
|
|
|
292
296
|
this.autoAdvanceMsOverride ?? this.getPhase().durationMs ?? 600;
|
|
293
297
|
const elapsed = now - this.phaseStartedAt;
|
|
294
298
|
const linearT = clamp01(elapsed / duration);
|
|
295
|
-
this.
|
|
299
|
+
this.setProgress(linearT);
|
|
296
300
|
this.emit();
|
|
297
301
|
if (linearT < 1) {
|
|
298
302
|
this.rafHandle = requestAnimationFrame(step);
|
|
299
303
|
return;
|
|
300
304
|
}
|
|
301
|
-
this.
|
|
305
|
+
this.setProgress(1);
|
|
302
306
|
this.emit();
|
|
303
307
|
if (this.status === "playing") {
|
|
304
308
|
// 自動進行中は次 Phase へ
|
|
@@ -315,6 +319,20 @@ export class Timeline {
|
|
|
315
319
|
this.rafHandle = requestAnimationFrame(step);
|
|
316
320
|
}
|
|
317
321
|
|
|
322
|
+
/**
|
|
323
|
+
* 段の進みを 2 つ同時に置く (cdl#711)。
|
|
324
|
+
*
|
|
325
|
+
* **代入する場所を 1 つに閉じる**。 曲げた進みと曲げる前の進みを別々に書くと、
|
|
326
|
+
* どちらかを更新し忘れた経路が「前の段の値のまま」 で残る。
|
|
327
|
+
*
|
|
328
|
+
* 両端 (0 と 1) は曲線を通さず、 そのまま置く。 曲線は差し替えられる欄なので、
|
|
329
|
+
* `easing(1)` が 1 を返す保証がない。 段の始まりと終わりの値は曲線に委ねない。
|
|
330
|
+
*/
|
|
331
|
+
private setProgress(linear: number): void {
|
|
332
|
+
this.phaseLinearProgress = linear;
|
|
333
|
+
this.phaseProgress = linear <= 0 ? 0 : linear >= 1 ? 1 : this.easing(linear);
|
|
334
|
+
}
|
|
335
|
+
|
|
318
336
|
private cancelRaf(): void {
|
|
319
337
|
if (this.rafHandle != null) {
|
|
320
338
|
cancelAnimationFrame(this.rafHandle);
|
package/src/anim/core/types.ts
CHANGED
|
@@ -37,6 +37,18 @@ export type TimelineState = {
|
|
|
37
37
|
phaseIndex: number;
|
|
38
38
|
/** 現在 Phase 内の進行度 (0..1)、 視覚要素の補間に使う */
|
|
39
39
|
phaseProgress: number;
|
|
40
|
+
/**
|
|
41
|
+
* 曲線を通す前の進行度 (0..1、 cdl#711)。 経過時間そのものの割合。
|
|
42
|
+
*
|
|
43
|
+
* `phaseProgress` は既定で `easeOutQuint` を通るため前半に動きが寄る。
|
|
44
|
+
* **値が落ち着く動きには合うが、 線を引く動きには合わない** =
|
|
45
|
+
* `1.2s` の段で半分に達するのが 158 ms になり、 折れ線の 5 点のうち 4 点が
|
|
46
|
+
* 292 ms の間に出てしまう (実測)。
|
|
47
|
+
*
|
|
48
|
+
* 描く動き (`draw` の node と伸ばす edge) はこちらを読む。
|
|
49
|
+
* 両端 (0 と 1) は 2 つとも同じ値になる。
|
|
50
|
+
*/
|
|
51
|
+
phaseLinearProgress: number;
|
|
40
52
|
/** 全 Phase 数 */
|
|
41
53
|
totalPhases: number;
|
|
42
54
|
};
|
package/src/render/stage.tsx
CHANGED
|
@@ -28,6 +28,7 @@ export function CdlStage({
|
|
|
28
28
|
laid,
|
|
29
29
|
currentPhase,
|
|
30
30
|
progress,
|
|
31
|
+
drawProgress,
|
|
31
32
|
stateValues,
|
|
32
33
|
debug,
|
|
33
34
|
compact = false,
|
|
@@ -36,6 +37,13 @@ export function CdlStage({
|
|
|
36
37
|
laid: LaidDiagram;
|
|
37
38
|
currentPhase: CdlPhase | undefined;
|
|
38
39
|
progress: number;
|
|
40
|
+
/**
|
|
41
|
+
* 描く動きが読む進み (cdl#711)。 曲線を通す前の値で、 経過時間そのものの割合。
|
|
42
|
+
*
|
|
43
|
+
* 書かない呼出は `progress` と同じ値になる = 曲線を通した進みで描く従来の形。
|
|
44
|
+
* 検査から直接呼ぶ経路が既に多数あり、 そこでは 2 つを分ける意味がない。
|
|
45
|
+
*/
|
|
46
|
+
drawProgress?: number;
|
|
39
47
|
stateValues: Record<string, string>;
|
|
40
48
|
debug: boolean;
|
|
41
49
|
compact?: boolean;
|
|
@@ -112,9 +120,15 @@ export function CdlStage({
|
|
|
112
120
|
}
|
|
113
121
|
return scales;
|
|
114
122
|
}, [laid]);
|
|
115
|
-
|
|
123
|
+
/**
|
|
124
|
+
* 描く動きの素の進み (cdl#711)。 渡されなければ従来どおり曲線を通した進みを使う。
|
|
125
|
+
*
|
|
126
|
+
* **`??` で受ける** = 0 は正しい進み (段の始まり) なので、 偽としては落とせない。
|
|
127
|
+
*/
|
|
128
|
+
const 描く素の進み = drawProgress ?? progress;
|
|
129
|
+
// 描く対象から見た進み (cdl#570)。 `drawRatio` を書かない phase では `描く素の進み` と同値で、
|
|
116
130
|
// 描く速さを phase の長さから切り離すためだけに使う
|
|
117
|
-
const 描く進み = 描く進みに直す(
|
|
131
|
+
const 描く進み = 描く進みに直す(描く素の進み, currentPhase?.drawRatio);
|
|
118
132
|
// 縦線の終点は全 lane で 1 つに揃える (等長保証)。 値の決め方と、 1 lane の異常が図全体から
|
|
119
133
|
// 縦線を消していた形の対処は `uniformLifelineEndY` の説明。
|
|
120
134
|
//
|
|
@@ -345,7 +359,7 @@ export function CdlStage({
|
|
|
345
359
|
edge={edge}
|
|
346
360
|
active={activeSet.has(edge.id)}
|
|
347
361
|
drawing={矢印の出番.伸ばすか(edge.id)}
|
|
348
|
-
progress={progress}
|
|
362
|
+
progress={矢印の出番.伸ばすか(edge.id) ? 描く進み : progress}
|
|
349
363
|
stateValues={stateValues}
|
|
350
364
|
/>
|
|
351
365
|
))}
|
package/src/render.tsx
CHANGED
|
@@ -133,6 +133,13 @@ export function CdlDiagramView({ diagram, laid: laidProp, hideHeader = false, hi
|
|
|
133
133
|
: state.phaseIndex;
|
|
134
134
|
const currentPhase = laid.phases[Math.max(0, phaseIdx)] ?? laid.phases[0];
|
|
135
135
|
const progress = reduced ? 1 : state.phaseProgress;
|
|
136
|
+
/**
|
|
137
|
+
* 描く動きが読む進み (cdl#711)。 曲線を通さない = 経過時間そのものの割合。
|
|
138
|
+
*
|
|
139
|
+
* 線を引く動きに `easeOutQuint` を当てると前半に寄り、 折れ線の 5 点のうち 4 点が
|
|
140
|
+
* 292 ms の間に出る。 ペンの速さは一定であるほど「1 つずつ現れる」 が読める。
|
|
141
|
+
*/
|
|
142
|
+
const drawProgress = reduced ? 1 : state.phaseLinearProgress;
|
|
136
143
|
|
|
137
144
|
// state 値を計算 (現在 phase + これまでの phase の最終 tween 値を集約)
|
|
138
145
|
const baseStateValues = computeStateValues(laid, phaseIdx, progress);
|
|
@@ -184,7 +191,7 @@ export function CdlDiagramView({ diagram, laid: laidProp, hideHeader = false, hi
|
|
|
184
191
|
{/* interactive panel = input widget / formula readout / scroll readout (SVG の上に配置)、
|
|
185
192
|
diagram に interactive primitive がなければ null (SSR / render 影響なし) */}
|
|
186
193
|
{isInteractive && interactive.panel}
|
|
187
|
-
<CdlStage laid={laid} currentPhase={currentPhase} progress={progress} stateValues={stateValues} debug={debug} compact={hideHeader} svgRef={isInteractive ? interactive.svgRef : undefined} />
|
|
194
|
+
<CdlStage laid={laid} currentPhase={currentPhase} progress={progress} drawProgress={drawProgress} stateValues={stateValues} debug={debug} compact={hideHeader} svgRef={isInteractive ? interactive.svgRef : undefined} />
|
|
188
195
|
{/* hideHeader + multi-phase 時、 phase indicator が消えると動きが読めないため
|
|
189
196
|
mini indicator (dot 列 + 現在 phase title + badge) を bottom に追加 */}
|
|
190
197
|
{hideHeader && !hideMiniPhaseIndicator && currentPhase && laid.phases.length > 1 && (
|