@cardenelabs/cdl 0.52.0 → 0.54.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 +42 -1
- package/README.md +2 -2
- package/dist/index.cjs +138 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +138 -105
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +88 -78
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +88 -78
- package/dist/react.js.map +1 -1
- package/dist/{render-C0PJ2weJ.d.cts → render-Cp41meYv.d.cts} +7 -6
- package/dist/{render-C0PJ2weJ.d.ts → render-Cp41meYv.d.ts} +7 -6
- package/package.json +1 -1
- package/src/layout/head-label.ts +26 -2
- package/src/layout/nodes.ts +7 -3
- package/src/presets.ts +67 -34
- package/src/render/relation-focus.ts +1 -1
- package/src/types.ts +7 -6
|
@@ -105,7 +105,7 @@ type Side = "top" | "right" | "bottom" | "left";
|
|
|
105
105
|
* - "dashed" ... 刻んだ線。 **光っていても刻みのまま**。
|
|
106
106
|
*
|
|
107
107
|
* `"dashed"` が要るのは、`"solid"` の刻みが「光っていない」 を表す合図に使われているため。
|
|
108
|
-
* 光ると実線に戻るので、線の種類として刻みを持たせられない。 UML
|
|
108
|
+
* 光ると実線に戻るので、線の種類として刻みを持たせられない。 UML の「実装」 と「依存」、
|
|
109
109
|
* ER の「識別しない」 のように **刻みが意味を持つ関係** はこちらを使う。
|
|
110
110
|
*/
|
|
111
111
|
type EdgeStyle = "solid" | "dotted-flow" | "dashed";
|
|
@@ -139,8 +139,8 @@ declare const EDGE_STYLES: readonly EdgeStyle[];
|
|
|
139
139
|
* 4 通りを 2 つの欄に分けないのは、**端の印は 1 つの記号として読まれる**ため。 欄を分けると
|
|
140
140
|
* 片方だけ書いた形 (個数はあるが任意かが無い) を許すことになり、描けない組み合わせが増える。
|
|
141
141
|
*
|
|
142
|
-
* 線の種類と分けて持つのは、両者が独立に組み合わさるため。 実線 × 三角 (
|
|
143
|
-
* 破線 × 三角 (
|
|
142
|
+
* 線の種類と分けて持つのは、両者が独立に組み合わさるため。 実線 × 三角 (継承) と
|
|
143
|
+
* 破線 × 三角 (実装) は線種で分かれ、実線 × 三角 (継承) と実線 × 菱 (集約) は端で分かれる。
|
|
144
144
|
* 1 つの欄に畳むと 2 軸の積を名前で列挙することになり、組合せが増えるたびに語が増える。
|
|
145
145
|
*/
|
|
146
146
|
type EdgeHead = "none" | "triangle" | "diamond" | "open" | "crow" | "one" | "zero-one" | "many" | "zero-many";
|
|
@@ -154,7 +154,8 @@ declare const EDGE_HEADS: readonly EdgeHead[];
|
|
|
154
154
|
* - `"solid"` ... 墨で塗る。 **既定**。 書かなければ形ごとの既定 (`EDGE_HEAD_SHAPE.filled`) に従う
|
|
155
155
|
* - `"hollow"` ... 紙の色で塗り、輪郭だけを線で描く
|
|
156
156
|
*
|
|
157
|
-
* UML は同じ形を塗りで分ける =
|
|
157
|
+
* UML は同じ形を塗りで分ける = 白抜きの菱が「集約」、塗った菱が「コンポジション」
|
|
158
|
+
* (部分が全体と寿命を共にする)。
|
|
158
159
|
* 形を増やして表そうとすると、塗りの軸を持つ全ての形について語が倍になる。
|
|
159
160
|
*
|
|
160
161
|
* 塗らない形 (`"open"` / `"crow"`) には効かない。 元から輪郭しか無いため。
|
|
@@ -664,8 +665,8 @@ type CdlEdge = {
|
|
|
664
665
|
/**
|
|
665
666
|
* 端の印の塗り方 (#578)。 書かなければ形ごとの既定。 塗らない形には効かない。
|
|
666
667
|
*
|
|
667
|
-
* 形と分けて持つのは、UML が同じ形を塗りで分けるため (白抜きの菱 =
|
|
668
|
-
* 塗った菱 =
|
|
668
|
+
* 形と分けて持つのは、UML が同じ形を塗りで分けるため (白抜きの菱 = 集約 /
|
|
669
|
+
* 塗った菱 = コンポジション)。
|
|
669
670
|
*/
|
|
670
671
|
headFill?: EdgeHeadFill;
|
|
671
672
|
/**
|
|
@@ -105,7 +105,7 @@ type Side = "top" | "right" | "bottom" | "left";
|
|
|
105
105
|
* - "dashed" ... 刻んだ線。 **光っていても刻みのまま**。
|
|
106
106
|
*
|
|
107
107
|
* `"dashed"` が要るのは、`"solid"` の刻みが「光っていない」 を表す合図に使われているため。
|
|
108
|
-
* 光ると実線に戻るので、線の種類として刻みを持たせられない。 UML
|
|
108
|
+
* 光ると実線に戻るので、線の種類として刻みを持たせられない。 UML の「実装」 と「依存」、
|
|
109
109
|
* ER の「識別しない」 のように **刻みが意味を持つ関係** はこちらを使う。
|
|
110
110
|
*/
|
|
111
111
|
type EdgeStyle = "solid" | "dotted-flow" | "dashed";
|
|
@@ -139,8 +139,8 @@ declare const EDGE_STYLES: readonly EdgeStyle[];
|
|
|
139
139
|
* 4 通りを 2 つの欄に分けないのは、**端の印は 1 つの記号として読まれる**ため。 欄を分けると
|
|
140
140
|
* 片方だけ書いた形 (個数はあるが任意かが無い) を許すことになり、描けない組み合わせが増える。
|
|
141
141
|
*
|
|
142
|
-
* 線の種類と分けて持つのは、両者が独立に組み合わさるため。 実線 × 三角 (
|
|
143
|
-
* 破線 × 三角 (
|
|
142
|
+
* 線の種類と分けて持つのは、両者が独立に組み合わさるため。 実線 × 三角 (継承) と
|
|
143
|
+
* 破線 × 三角 (実装) は線種で分かれ、実線 × 三角 (継承) と実線 × 菱 (集約) は端で分かれる。
|
|
144
144
|
* 1 つの欄に畳むと 2 軸の積を名前で列挙することになり、組合せが増えるたびに語が増える。
|
|
145
145
|
*/
|
|
146
146
|
type EdgeHead = "none" | "triangle" | "diamond" | "open" | "crow" | "one" | "zero-one" | "many" | "zero-many";
|
|
@@ -154,7 +154,8 @@ declare const EDGE_HEADS: readonly EdgeHead[];
|
|
|
154
154
|
* - `"solid"` ... 墨で塗る。 **既定**。 書かなければ形ごとの既定 (`EDGE_HEAD_SHAPE.filled`) に従う
|
|
155
155
|
* - `"hollow"` ... 紙の色で塗り、輪郭だけを線で描く
|
|
156
156
|
*
|
|
157
|
-
* UML は同じ形を塗りで分ける =
|
|
157
|
+
* UML は同じ形を塗りで分ける = 白抜きの菱が「集約」、塗った菱が「コンポジション」
|
|
158
|
+
* (部分が全体と寿命を共にする)。
|
|
158
159
|
* 形を増やして表そうとすると、塗りの軸を持つ全ての形について語が倍になる。
|
|
159
160
|
*
|
|
160
161
|
* 塗らない形 (`"open"` / `"crow"`) には効かない。 元から輪郭しか無いため。
|
|
@@ -664,8 +665,8 @@ type CdlEdge = {
|
|
|
664
665
|
/**
|
|
665
666
|
* 端の印の塗り方 (#578)。 書かなければ形ごとの既定。 塗らない形には効かない。
|
|
666
667
|
*
|
|
667
|
-
* 形と分けて持つのは、UML が同じ形を塗りで分けるため (白抜きの菱 =
|
|
668
|
-
* 塗った菱 =
|
|
668
|
+
* 形と分けて持つのは、UML が同じ形を塗りで分けるため (白抜きの菱 = 集約 /
|
|
669
|
+
* 塗った菱 = コンポジション)。
|
|
669
670
|
*/
|
|
670
671
|
headFill?: EdgeHeadFill;
|
|
671
672
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cardenelabs/cdl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.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",
|
package/src/layout/head-label.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 端での線の向きで決める。 端から `端の字を戻す距離` だけ線を戻った点を基準に、線の脇へ置く。
|
|
8
8
|
* 字は端に近い側の縁を基準点に揃える = 字の長さが変わっても、端から字までの隙間は変わらない。
|
|
9
9
|
*
|
|
10
|
-
* **線の札の反対側に置く**。 札と同じ側に置くと、札の語と多重度が続けて読まれる (
|
|
10
|
+
* **線の札の反対側に置く**。 札と同じ側に置くと、札の語と多重度が続けて読まれる (「集約」 の
|
|
11
11
|
* 隣に `1..*`、 英字の頃は「HAS1」)。 実測で、札と同じ側 (横向きなら上、縦向きなら右) に
|
|
12
12
|
* 置く形は見本帳のクラス図で 1 本が札と重なり、 もう 1 本が札と 2 world まで寄った。
|
|
13
13
|
* 札を持たない線は、横向きなら下、縦向きなら左に置く (engine が札を置く既定の側の反対)。
|
|
@@ -25,7 +25,7 @@ import { measureTextWidth } from "./text-width";
|
|
|
25
25
|
* 端から字までの、線に沿った距離 (world)。
|
|
26
26
|
*
|
|
27
27
|
* 端の印の長さの最大 (光っている時の 14、 `render/stage.tsx` の marker の大きさ) に隙間 8 を足す。
|
|
28
|
-
* 印を持たない端 (
|
|
28
|
+
* 印を持たない端 (菱が出どころ側にある「集約」 「コンポジション」 の行き先) でも同じ距離にする = 端ごとに
|
|
29
29
|
* 距離が変わると、図の中で多重度の位置が揃わない。
|
|
30
30
|
*/
|
|
31
31
|
export const 端の字を戻す距離 = 22;
|
|
@@ -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
|
|
package/src/layout/nodes.ts
CHANGED
|
@@ -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 =
|
|
160
|
+
let required = 端の字の要求;
|
|
157
161
|
for (const pillHs of pillHsByGap.values()) {
|
|
158
162
|
required = Math.max(required, requiredVerticalLabelGap(pillHs));
|
|
159
163
|
}
|
package/src/presets.ts
CHANGED
|
@@ -345,7 +345,7 @@ export function flow(preset: FlowPreset): FlowBuilder {
|
|
|
345
345
|
build() {
|
|
346
346
|
b.phase(
|
|
347
347
|
"flow",
|
|
348
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
348
|
+
{ duration: 2400, title: preset.topic, body: "すべての段を上から順に通った流れ。" },
|
|
349
349
|
(p) => p.activate(...phaseActivate).badge("flow"),
|
|
350
350
|
);
|
|
351
351
|
return b.build();
|
|
@@ -366,7 +366,7 @@ export function flow(preset: FlowPreset): FlowBuilder {
|
|
|
366
366
|
* | `return` | 破線 | 開いた矢 | 呼ばれた側から戻る。 新しい仕事ではないので線を切る |
|
|
367
367
|
* | `fire` | 実線 | 開いた矢 | 返事を待たない。 実線だが矢を閉じないことで待たないと示す |
|
|
368
368
|
*
|
|
369
|
-
*
|
|
369
|
+
* 印の形はクラス図の「継承」 と「関連」 で使った形そのもの。 **意味は違う** (あちらは親を
|
|
370
370
|
* 指す / こちらは返事を待つか) が、形の並びは共有できる。
|
|
371
371
|
*/
|
|
372
372
|
export type SequenceMessageKind = "call" | "return" | "fire";
|
|
@@ -517,7 +517,7 @@ export function sequence(preset: SequencePreset): SequenceBuilder {
|
|
|
517
517
|
});
|
|
518
518
|
b.phase(
|
|
519
519
|
"sequence",
|
|
520
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
520
|
+
{ duration: 2400, title: preset.topic, body: "すべてのやり取りを時間の順に並べた姿。" },
|
|
521
521
|
(p) => p.activate(preset.id).badge("sequence"),
|
|
522
522
|
);
|
|
523
523
|
return b.build();
|
|
@@ -653,7 +653,7 @@ export function topology(preset: TopologyPreset): TopologyBuilder {
|
|
|
653
653
|
build() {
|
|
654
654
|
b.phase(
|
|
655
655
|
"topo",
|
|
656
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
656
|
+
{ duration: 2400, title: preset.topic, body: "すべての構成要素と接続を並べた構成。" },
|
|
657
657
|
(p) => p.activate(...phaseActivate).badge("topology"),
|
|
658
658
|
);
|
|
659
659
|
return b.build();
|
|
@@ -883,7 +883,7 @@ export function er(preset: ErPreset): ErBuilder {
|
|
|
883
883
|
build() {
|
|
884
884
|
b.phase(
|
|
885
885
|
"er",
|
|
886
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
886
|
+
{ duration: 2400, title: preset.topic, body: "すべての表と関係を並べた構造。" },
|
|
887
887
|
(p) => p.activate(...phaseActivate).badge("er"),
|
|
888
888
|
);
|
|
889
889
|
return b.build();
|
|
@@ -1158,7 +1158,7 @@ export function stateMachine(preset: StateMachinePreset): StateMachineBuilder {
|
|
|
1158
1158
|
|
|
1159
1159
|
b.phase(
|
|
1160
1160
|
"fsm",
|
|
1161
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
1161
|
+
{ duration: 2400, title: preset.topic, body: "すべての状態と遷移を並べた姿。" },
|
|
1162
1162
|
(p) => p.activate(...phaseActivate).badge("fsm"),
|
|
1163
1163
|
);
|
|
1164
1164
|
return b.build();
|
|
@@ -1291,7 +1291,7 @@ export function infrastructure(preset: InfrastructurePreset): InfrastructureBuil
|
|
|
1291
1291
|
build() {
|
|
1292
1292
|
b.phase(
|
|
1293
1293
|
"infra",
|
|
1294
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
1294
|
+
{ duration: 2400, title: preset.topic, body: "すべての構成要素と接続を並べた構成。" },
|
|
1295
1295
|
(p) => p.activate(...phaseActivate).badge("infrastructure"),
|
|
1296
1296
|
);
|
|
1297
1297
|
return b.build();
|
|
@@ -1322,12 +1322,12 @@ export type ClassRelationType =
|
|
|
1322
1322
|
*
|
|
1323
1323
|
* | 種類 | 線 | 形 | 塗り | 側 | 意味 |
|
|
1324
1324
|
* |---|---|---|---|---|---|
|
|
1325
|
-
* | `extends` | 実線 | 三角 | 白抜き | 行き先 |
|
|
1326
|
-
* | `implements` | 破線 | 三角 | 白抜き | 行き先 |
|
|
1327
|
-
* | `aggregates` | 実線 | 菱 | 白抜き | 出どころ |
|
|
1328
|
-
* | `composes` | 実線 | 菱 | 塗る | 出どころ |
|
|
1329
|
-
* | `associates` | 実線 | 開いた矢 | — | 行き先 |
|
|
1330
|
-
* | `uses` | 破線 | 開いた矢 | — | 行き先 |
|
|
1325
|
+
* | `extends` | 実線 | 三角 | 白抜き | 行き先 | 継承 |
|
|
1326
|
+
* | `implements` | 破線 | 三角 | 白抜き | 行き先 | 実装 |
|
|
1327
|
+
* | `aggregates` | 実線 | 菱 | 白抜き | 出どころ | 集約 |
|
|
1328
|
+
* | `composes` | 実線 | 菱 | 塗る | 出どころ | コンポジション |
|
|
1329
|
+
* | `associates` | 実線 | 開いた矢 | — | 行き先 | 関連 |
|
|
1330
|
+
* | `uses` | 破線 | 開いた矢 | — | 行き先 | 依存 |
|
|
1331
1331
|
*
|
|
1332
1332
|
* **側が種で割れるのが要点**。 三角は「この先が親」 を指すので行き先に立ち、菱は
|
|
1333
1333
|
* 「この箱が持っている」 を指すので出どころに立つ。 1 つの決まりで書こうとするとどちらかが
|
|
@@ -1594,7 +1594,7 @@ export function classDiagram(preset: ClassDiagramPreset): ClassDiagramBuilder {
|
|
|
1594
1594
|
|
|
1595
1595
|
b.phase(
|
|
1596
1596
|
"class",
|
|
1597
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
1597
|
+
{ duration: 2400, title: preset.topic, body: "すべてのクラスと関係を並べた構造。" },
|
|
1598
1598
|
(p) => p.activate(...phaseActivate).badge("class"),
|
|
1599
1599
|
);
|
|
1600
1600
|
return b.build();
|
|
@@ -1673,7 +1673,7 @@ export function tree(preset: TreePreset): TreeBuilder {
|
|
|
1673
1673
|
});
|
|
1674
1674
|
b.phase(
|
|
1675
1675
|
"tree",
|
|
1676
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
1676
|
+
{ duration: 2400, title: preset.topic, body: "すべての項目を親子の階層で並べた木。" },
|
|
1677
1677
|
(p) => p.activate(nodeId).badge("tree"),
|
|
1678
1678
|
);
|
|
1679
1679
|
return b.build();
|
|
@@ -1756,7 +1756,7 @@ export function userJourney(preset: UserJourneyPreset): UserJourneyBuilder {
|
|
|
1756
1756
|
});
|
|
1757
1757
|
b.phase(
|
|
1758
1758
|
"journey",
|
|
1759
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
1759
|
+
{ duration: 2400, title: preset.topic, body: "すべての段階を、気持ちの曲線と接点で並べた体験。" },
|
|
1760
1760
|
(p) => p.activate(nodeId).badge("journey"),
|
|
1761
1761
|
);
|
|
1762
1762
|
return b.build();
|
|
@@ -1844,7 +1844,7 @@ export function mindMap(preset: MindMapPreset): MindMapBuilder {
|
|
|
1844
1844
|
});
|
|
1845
1845
|
b.phase(
|
|
1846
1846
|
"mindmap",
|
|
1847
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
1847
|
+
{ duration: 2400, title: preset.topic, body: "中心の主題から、すべての枝を放射状に広げた姿。" },
|
|
1848
1848
|
(p) => p.activate(nodeId).badge("mindmap"),
|
|
1849
1849
|
);
|
|
1850
1850
|
return b.build();
|
|
@@ -1920,7 +1920,7 @@ export function funnel(preset: FunnelPreset): FunnelBuilder {
|
|
|
1920
1920
|
});
|
|
1921
1921
|
b.phase(
|
|
1922
1922
|
"funnel",
|
|
1923
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
1923
|
+
{ duration: 2400, title: preset.topic, body: "すべての段階を、人数とともに上から絞り込んだ姿。" },
|
|
1924
1924
|
(p) => p.activate(nodeId).badge("funnel"),
|
|
1925
1925
|
);
|
|
1926
1926
|
return b.build();
|
|
@@ -2018,7 +2018,7 @@ export function quadrant(preset: QuadrantPreset): QuadrantBuilder {
|
|
|
2018
2018
|
});
|
|
2019
2019
|
b.phase(
|
|
2020
2020
|
"quadrant",
|
|
2021
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
2021
|
+
{ duration: 2400, title: preset.topic, body: "2 本の軸で分けた 4 つの枠に、すべての項目を置いた姿。" },
|
|
2022
2022
|
(p) => p.activate(nodeId).badge("quadrant"),
|
|
2023
2023
|
);
|
|
2024
2024
|
return b.build();
|
|
@@ -2134,7 +2134,7 @@ export function chart(preset: ChartPreset): ChartBuilder {
|
|
|
2134
2134
|
});
|
|
2135
2135
|
b.phase(
|
|
2136
2136
|
"chart",
|
|
2137
|
-
{ duration: 2400, title: preset.topic, body:
|
|
2137
|
+
{ duration: 2400, title: preset.topic, body: "すべての値を描いたグラフ。" },
|
|
2138
2138
|
(p) => p.activate(nodeId).badge(preset.type),
|
|
2139
2139
|
);
|
|
2140
2140
|
return b.build();
|
|
@@ -2254,7 +2254,7 @@ export function gantt(preset: GanttPreset): GanttBuilder {
|
|
|
2254
2254
|
});
|
|
2255
2255
|
b.phase(
|
|
2256
2256
|
"gantt",
|
|
2257
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
2257
|
+
{ duration: 2400, title: preset.topic, body: "すべての作業を、期間の帯と前後関係の矢印で並べた工程。" },
|
|
2258
2258
|
(p) => p.activate(nodeId).badge("gantt"),
|
|
2259
2259
|
);
|
|
2260
2260
|
return b.build();
|
|
@@ -2307,12 +2307,16 @@ const SHAPE_KIND: Record<FlowchartNodeShape, NodeKind> = {
|
|
|
2307
2307
|
loop: "card",
|
|
2308
2308
|
};
|
|
2309
2309
|
|
|
2310
|
+
/**
|
|
2311
|
+
* 箱の上に出す形の名前 (#835)。 流れ図の記号の呼び方 (JIS X 0121 の 処理 / 判断 / 端子) に合わせる。
|
|
2312
|
+
* 端子は始まりと終わりで分けて書く = 同じ「端子」 では、どちらの端かが読めない。
|
|
2313
|
+
*/
|
|
2310
2314
|
const SHAPE_EYEBROW: Record<FlowchartNodeShape, string> = {
|
|
2311
|
-
process: "
|
|
2312
|
-
decision: "
|
|
2313
|
-
start: "
|
|
2314
|
-
end: "
|
|
2315
|
-
loop: "
|
|
2315
|
+
process: "処理",
|
|
2316
|
+
decision: "判断",
|
|
2317
|
+
start: "開始",
|
|
2318
|
+
end: "終了",
|
|
2319
|
+
loop: "繰り返し",
|
|
2316
2320
|
};
|
|
2317
2321
|
|
|
2318
2322
|
/**
|
|
@@ -2381,7 +2385,7 @@ export function flowchart(preset: FlowchartPreset): FlowchartBuilder {
|
|
|
2381
2385
|
build() {
|
|
2382
2386
|
b.phase(
|
|
2383
2387
|
"flowchart",
|
|
2384
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
2388
|
+
{ duration: 2400, title: preset.topic, body: "すべての処理と分岐を、担当ごとのレーンに並べた流れ。" },
|
|
2385
2389
|
(p) => p.activate(...phaseActivate).badge("flowchart"),
|
|
2386
2390
|
);
|
|
2387
2391
|
return b.build();
|
|
@@ -2434,6 +2438,15 @@ const NET_KIND_MAP: Record<NetworkDeviceKind, NodeKind> = {
|
|
|
2434
2438
|
client: "actor",
|
|
2435
2439
|
};
|
|
2436
2440
|
|
|
2441
|
+
/** 箱の上に出す機器の呼び名 (#835)。 種類の英語をそのまま出すと、日本語の図の中で浮く */
|
|
2442
|
+
const NET_KIND_LABEL: Record<NetworkDeviceKind, string> = {
|
|
2443
|
+
router: "ルーター",
|
|
2444
|
+
switch: "スイッチ",
|
|
2445
|
+
firewall: "ファイアウォール",
|
|
2446
|
+
server: "サーバー",
|
|
2447
|
+
client: "端末",
|
|
2448
|
+
};
|
|
2449
|
+
|
|
2437
2450
|
/**
|
|
2438
2451
|
* network preset ... NW topology (router / switch / firewall / server / client) を col × row 配置、
|
|
2439
2452
|
* link で接続 (protocol / VLAN を label)。 On-prem / hybrid NW 構成図向け。
|
|
@@ -2464,7 +2477,7 @@ export function network(preset: NetworkPreset): NetworkBuilder {
|
|
|
2464
2477
|
b.lane(laneId, { width: laneW });
|
|
2465
2478
|
colLaneIds.set(d.col, laneId);
|
|
2466
2479
|
}
|
|
2467
|
-
const eyebrowParts: string[] = [d.kind];
|
|
2480
|
+
const eyebrowParts: string[] = [NET_KIND_LABEL[d.kind]];
|
|
2468
2481
|
if (d.segment) eyebrowParts.push(d.segment);
|
|
2469
2482
|
b.node(d.id, {
|
|
2470
2483
|
lane: laneId,
|
|
@@ -2490,7 +2503,7 @@ export function network(preset: NetworkPreset): NetworkBuilder {
|
|
|
2490
2503
|
build() {
|
|
2491
2504
|
b.phase(
|
|
2492
2505
|
"network",
|
|
2493
|
-
{ duration: 2400, title: preset.topic, body: "
|
|
2506
|
+
{ duration: 2400, title: preset.topic, body: "すべての機器と接続を並べた構成。" },
|
|
2494
2507
|
(p) => p.activate(...phaseActivate).badge("network"),
|
|
2495
2508
|
);
|
|
2496
2509
|
return b.build();
|
|
@@ -2572,19 +2585,25 @@ export function stateMachine2(preset: StateMachine2Preset): StateMachine2Builder
|
|
|
2572
2585
|
const stateOrder = new Map<string, number>();
|
|
2573
2586
|
const phaseActivate: string[] = [];
|
|
2574
2587
|
let transIdx = 0;
|
|
2588
|
+
// 状態の題と親 (#835)。 入れ子の札は親の題で書くので、親が後から宣言されても引けるよう
|
|
2589
|
+
// 札は `build()` で決める
|
|
2590
|
+
const 題 = new Map<string, string>();
|
|
2591
|
+
const 親 = new Map<string, string>();
|
|
2575
2592
|
|
|
2576
2593
|
const api: StateMachine2Builder = {
|
|
2577
2594
|
state(s) {
|
|
2578
2595
|
const laneId = `lane-${s.id}`;
|
|
2579
2596
|
b.lane(laneId, { width: laneW });
|
|
2597
|
+
題.set(s.id, s.title);
|
|
2598
|
+
if (s.parent) 親.set(s.id, s.parent);
|
|
2580
2599
|
const eyebrowParts: string[] = [];
|
|
2581
2600
|
if (s.initial) eyebrowParts.push("初期");
|
|
2582
2601
|
else if (s.final) eyebrowParts.push("最終");
|
|
2583
2602
|
else eyebrowParts.push("状態");
|
|
2584
|
-
|
|
2603
|
+
// 入る時と出る時の呼び方は `types.ts` の行頭の印の説明と揃える
|
|
2585
2604
|
const subtitleParts: string[] = [];
|
|
2586
|
-
if (s.entry) subtitleParts.push(
|
|
2587
|
-
if (s.exit) subtitleParts.push(
|
|
2605
|
+
if (s.entry) subtitleParts.push(`入る時: ${s.entry}`);
|
|
2606
|
+
if (s.exit) subtitleParts.push(`出る時: ${s.exit}`);
|
|
2588
2607
|
b.node(s.id, {
|
|
2589
2608
|
lane: laneId,
|
|
2590
2609
|
stack: 0,
|
|
@@ -2620,10 +2639,24 @@ export function stateMachine2(preset: StateMachine2Preset): StateMachine2Builder
|
|
|
2620
2639
|
build() {
|
|
2621
2640
|
b.phase(
|
|
2622
2641
|
"sm2",
|
|
2623
|
-
{
|
|
2642
|
+
{
|
|
2643
|
+
duration: 2400,
|
|
2644
|
+
title: preset.topic,
|
|
2645
|
+
body: "入れ子の状態と、入る時・出る時の処理を含めた、すべての状態と遷移。",
|
|
2646
|
+
},
|
|
2624
2647
|
(p) => p.activate(...phaseActivate).badge("statemachine2"),
|
|
2625
2648
|
);
|
|
2626
|
-
|
|
2649
|
+
const d = b.build();
|
|
2650
|
+
// 入れ子の札に親の題を足す。 識別子 (`active`) を出すと、図のどこにも無い字になる
|
|
2651
|
+
return {
|
|
2652
|
+
...d,
|
|
2653
|
+
nodes: d.nodes.map((n) => {
|
|
2654
|
+
const 親の識別子 = 親.get(n.id);
|
|
2655
|
+
if (親の識別子 === undefined) return n;
|
|
2656
|
+
const 親の題 = 題.get(親の識別子) ?? 親の識別子;
|
|
2657
|
+
return { ...n, eyebrow: `${n.eyebrow ?? "状態"} / ${親の題}の中` };
|
|
2658
|
+
}),
|
|
2659
|
+
};
|
|
2627
2660
|
},
|
|
2628
2661
|
};
|
|
2629
2662
|
|
package/src/types.ts
CHANGED
|
@@ -130,7 +130,7 @@ export type Side = "top" | "right" | "bottom" | "left";
|
|
|
130
130
|
* - "dashed" ... 刻んだ線。 **光っていても刻みのまま**。
|
|
131
131
|
*
|
|
132
132
|
* `"dashed"` が要るのは、`"solid"` の刻みが「光っていない」 を表す合図に使われているため。
|
|
133
|
-
* 光ると実線に戻るので、線の種類として刻みを持たせられない。 UML
|
|
133
|
+
* 光ると実線に戻るので、線の種類として刻みを持たせられない。 UML の「実装」 と「依存」、
|
|
134
134
|
* ER の「識別しない」 のように **刻みが意味を持つ関係** はこちらを使う。
|
|
135
135
|
*/
|
|
136
136
|
export type EdgeStyle = "solid" | "dotted-flow" | "dashed";
|
|
@@ -167,8 +167,8 @@ export const EDGE_STYLES: readonly EdgeStyle[] = ["solid", "dotted-flow", "dashe
|
|
|
167
167
|
* 4 通りを 2 つの欄に分けないのは、**端の印は 1 つの記号として読まれる**ため。 欄を分けると
|
|
168
168
|
* 片方だけ書いた形 (個数はあるが任意かが無い) を許すことになり、描けない組み合わせが増える。
|
|
169
169
|
*
|
|
170
|
-
* 線の種類と分けて持つのは、両者が独立に組み合わさるため。 実線 × 三角 (
|
|
171
|
-
* 破線 × 三角 (
|
|
170
|
+
* 線の種類と分けて持つのは、両者が独立に組み合わさるため。 実線 × 三角 (継承) と
|
|
171
|
+
* 破線 × 三角 (実装) は線種で分かれ、実線 × 三角 (継承) と実線 × 菱 (集約) は端で分かれる。
|
|
172
172
|
* 1 つの欄に畳むと 2 軸の積を名前で列挙することになり、組合せが増えるたびに語が増える。
|
|
173
173
|
*/
|
|
174
174
|
export type EdgeHead =
|
|
@@ -204,7 +204,8 @@ export const EDGE_HEADS: readonly EdgeHead[] = [
|
|
|
204
204
|
* - `"solid"` ... 墨で塗る。 **既定**。 書かなければ形ごとの既定 (`EDGE_HEAD_SHAPE.filled`) に従う
|
|
205
205
|
* - `"hollow"` ... 紙の色で塗り、輪郭だけを線で描く
|
|
206
206
|
*
|
|
207
|
-
* UML は同じ形を塗りで分ける =
|
|
207
|
+
* UML は同じ形を塗りで分ける = 白抜きの菱が「集約」、塗った菱が「コンポジション」
|
|
208
|
+
* (部分が全体と寿命を共にする)。
|
|
208
209
|
* 形を増やして表そうとすると、塗りの軸を持つ全ての形について語が倍になる。
|
|
209
210
|
*
|
|
210
211
|
* 塗らない形 (`"open"` / `"crow"`) には効かない。 元から輪郭しか無いため。
|
|
@@ -736,8 +737,8 @@ export type CdlEdge = {
|
|
|
736
737
|
/**
|
|
737
738
|
* 端の印の塗り方 (#578)。 書かなければ形ごとの既定。 塗らない形には効かない。
|
|
738
739
|
*
|
|
739
|
-
* 形と分けて持つのは、UML が同じ形を塗りで分けるため (白抜きの菱 =
|
|
740
|
-
* 塗った菱 =
|
|
740
|
+
* 形と分けて持つのは、UML が同じ形を塗りで分けるため (白抜きの菱 = 集約 /
|
|
741
|
+
* 塗った菱 = コンポジション)。
|
|
741
742
|
*/
|
|
742
743
|
headFill?: EdgeHeadFill;
|
|
743
744
|
/**
|