@cardenelabs/cdl 0.50.0 → 0.52.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 +33 -1
- package/dist/index.cjs +125 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -3
- package/dist/index.d.ts +13 -3
- package/dist/index.js +125 -5
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +117 -4
- 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 +117 -4
- package/dist/react.js.map +1 -1
- package/dist/{render-C53-PeJZ.d.cts → render-C0PJ2weJ.d.cts} +13 -0
- package/dist/{render-C53-PeJZ.d.ts → render-C0PJ2weJ.d.ts} +13 -0
- package/package.json +1 -1
- package/src/builder.ts +12 -0
- package/src/layout/head-label.ts +156 -0
- package/src/presets.ts +7 -2
- package/src/render/edges.tsx +41 -0
- package/src/render/stage.tsx +15 -1
- package/src/types.ts +13 -0
|
@@ -686,6 +686,19 @@ type CdlEdge = {
|
|
|
686
686
|
* compileEr 経路で edge label に "(1:N)" 形式で併記、 他 preset では透過。
|
|
687
687
|
*/
|
|
688
688
|
cardinality?: string;
|
|
689
|
+
/**
|
|
690
|
+
* 行き先の端に添える短い字 (#821)。 クラス図の多重度 (`1..*`) に使う。
|
|
691
|
+
*
|
|
692
|
+
* 線の中ほどの札 (`label` / `sub`) に入れると、どちらの端の数かが読めない。
|
|
693
|
+
* 置き場所は線の最後の区間から決まる (`layout/head-label.ts`)。
|
|
694
|
+
*/
|
|
695
|
+
headLabel?: string;
|
|
696
|
+
/**
|
|
697
|
+
* 出どころの端に添える短い字 (#825)。 `headLabel` と対。 クラス図の出どころ側の多重度に使う。
|
|
698
|
+
*
|
|
699
|
+
* UML は関係の両端に多重度を書く。 置き場所の計算は `headLabel` と同じ (`layout/head-label.ts`)。
|
|
700
|
+
*/
|
|
701
|
+
tailLabel?: string;
|
|
689
702
|
/** label の x 方向 fine offset (default 0)、 著者が細かく位置調整するための逃げ道 */
|
|
690
703
|
labelOffsetX?: number;
|
|
691
704
|
/** label の y 方向 fine offset (default 0、 + で下、 - で上) */
|
|
@@ -686,6 +686,19 @@ type CdlEdge = {
|
|
|
686
686
|
* compileEr 経路で edge label に "(1:N)" 形式で併記、 他 preset では透過。
|
|
687
687
|
*/
|
|
688
688
|
cardinality?: string;
|
|
689
|
+
/**
|
|
690
|
+
* 行き先の端に添える短い字 (#821)。 クラス図の多重度 (`1..*`) に使う。
|
|
691
|
+
*
|
|
692
|
+
* 線の中ほどの札 (`label` / `sub`) に入れると、どちらの端の数かが読めない。
|
|
693
|
+
* 置き場所は線の最後の区間から決まる (`layout/head-label.ts`)。
|
|
694
|
+
*/
|
|
695
|
+
headLabel?: string;
|
|
696
|
+
/**
|
|
697
|
+
* 出どころの端に添える短い字 (#825)。 `headLabel` と対。 クラス図の出どころ側の多重度に使う。
|
|
698
|
+
*
|
|
699
|
+
* UML は関係の両端に多重度を書く。 置き場所の計算は `headLabel` と同じ (`layout/head-label.ts`)。
|
|
700
|
+
*/
|
|
701
|
+
tailLabel?: string;
|
|
689
702
|
/** label の x 方向 fine offset (default 0)、 著者が細かく位置調整するための逃げ道 */
|
|
690
703
|
labelOffsetX?: number;
|
|
691
704
|
/** label の y 方向 fine offset (default 0、 + で下、 - で上) */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cardenelabs/cdl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.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/builder.ts
CHANGED
|
@@ -1452,6 +1452,10 @@ export type DiagramBuilder = {
|
|
|
1452
1452
|
guard?: string;
|
|
1453
1453
|
/** ER 関係 cardinality、 text-dsl v0.5 inline option (`cardinality: "1:N"`) を CdlEdge.cardinality へ透過 */
|
|
1454
1454
|
cardinality?: string;
|
|
1455
|
+
/** 行き先の端に添える字 (#821)。 クラス図の多重度に使う */
|
|
1456
|
+
headLabel?: string;
|
|
1457
|
+
/** 出どころの端に添える字 (#825)。 クラス図の出どころ側の多重度に使う */
|
|
1458
|
+
tailLabel?: string;
|
|
1455
1459
|
labelOffsetX?: number;
|
|
1456
1460
|
labelOffsetY?: number;
|
|
1457
1461
|
routing?: "default" | "back-detour";
|
|
@@ -1560,6 +1564,10 @@ export type DiagramBuilder = {
|
|
|
1560
1564
|
tailHeadFill?: EdgeHeadFill;
|
|
1561
1565
|
guard?: string;
|
|
1562
1566
|
cardinality?: string;
|
|
1567
|
+
/** 行き先の端に添える字 (#821)。 クラス図の多重度に使う */
|
|
1568
|
+
headLabel?: string;
|
|
1569
|
+
/** 出どころの端に添える字 (#825)。 クラス図の出どころ側の多重度に使う */
|
|
1570
|
+
tailLabel?: string;
|
|
1563
1571
|
labelOffsetX?: number;
|
|
1564
1572
|
labelOffsetY?: number;
|
|
1565
1573
|
routing?: "default" | "back-detour";
|
|
@@ -1776,6 +1784,8 @@ export function diagram(
|
|
|
1776
1784
|
tailHeadFill: opts.tailHeadFill,
|
|
1777
1785
|
guard: opts.guard,
|
|
1778
1786
|
cardinality: opts.cardinality,
|
|
1787
|
+
headLabel: opts.headLabel,
|
|
1788
|
+
tailLabel: opts.tailLabel,
|
|
1779
1789
|
labelOffsetX: opts.labelOffsetX,
|
|
1780
1790
|
labelOffsetY: opts.labelOffsetY,
|
|
1781
1791
|
routing: opts.routing,
|
|
@@ -1910,6 +1920,8 @@ export function diagram(
|
|
|
1910
1920
|
tailHeadFill: d.tailHeadFill,
|
|
1911
1921
|
guard: d.guard,
|
|
1912
1922
|
cardinality: d.cardinality,
|
|
1923
|
+
headLabel: d.headLabel,
|
|
1924
|
+
tailLabel: d.tailLabel,
|
|
1913
1925
|
labelOffsetX: d.labelOffsetX,
|
|
1914
1926
|
labelOffsetY: d.labelOffsetY,
|
|
1915
1927
|
routing: d.routing,
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 線の端に添える字 (`headLabel` / `tailLabel`) の置き場所 (#821 / #825)。
|
|
3
|
+
*
|
|
4
|
+
* 描く側 (`render/edges.tsx`) と検査が同じ値を使うため、計算をここに 1 つだけ置く。
|
|
5
|
+
* 行き先の端 (`head`) と出どころの端 (`tail`) は、端での線の向きの取り方だけが違う。
|
|
6
|
+
*
|
|
7
|
+
* 端での線の向きで決める。 端から `端の字を戻す距離` だけ線を戻った点を基準に、線の脇へ置く。
|
|
8
|
+
* 字は端に近い側の縁を基準点に揃える = 字の長さが変わっても、端から字までの隙間は変わらない。
|
|
9
|
+
*
|
|
10
|
+
* **線の札の反対側に置く**。 札と同じ側に置くと、札の語と多重度が続けて読まれる (「持つ」 の
|
|
11
|
+
* 隣に `1..*`、 英字の頃は「HAS1」)。 実測で、札と同じ側 (横向きなら上、縦向きなら右) に
|
|
12
|
+
* 置く形は見本帳のクラス図で 1 本が札と重なり、 もう 1 本が札と 2 world まで寄った。
|
|
13
|
+
* 札を持たない線は、横向きなら下、縦向きなら左に置く (engine が札を置く既定の側の反対)。
|
|
14
|
+
*
|
|
15
|
+
* 斜めの線と曲線は、向きの大きいほうの軸で横向き / 縦向きに振り分ける。 曲線の向きは
|
|
16
|
+
* 端の接線 (行き先の端なら最後の制御点から終点へ、出どころの端なら最初の制御点から始点へ) を
|
|
17
|
+
* 使う。 弦の向きを使うと、大きく膨らむ曲線で線が端へ入ってくる向きと別の向きが出る。
|
|
18
|
+
*/
|
|
19
|
+
import { EDGE_LABEL_TEXT } from "../label-text";
|
|
20
|
+
import { extractPathSegments } from "./collisions";
|
|
21
|
+
import { hasRenderedLabel } from "./spec";
|
|
22
|
+
import { measureTextWidth } from "./text-width";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 端から字までの、線に沿った距離 (world)。
|
|
26
|
+
*
|
|
27
|
+
* 端の印の長さの最大 (光っている時の 14、 `render/stage.tsx` の marker の大きさ) に隙間 8 を足す。
|
|
28
|
+
* 印を持たない端 (菱が出どころ側にある「持つ」 「抱える」 の行き先) でも同じ距離にする = 端ごとに
|
|
29
|
+
* 距離が変わると、図の中で多重度の位置が揃わない。
|
|
30
|
+
*/
|
|
31
|
+
export const 端の字を戻す距離 = 22;
|
|
32
|
+
|
|
33
|
+
/** 線と字の間の隙間 (world) */
|
|
34
|
+
export const 端の字と線の隙間 = 8;
|
|
35
|
+
|
|
36
|
+
/** 端の字の大きさ。 札の下の行と同じ等幅の字 = 多重度を札に入れていた頃と同じ見え方 */
|
|
37
|
+
export const 端の字の大きさ = EDGE_LABEL_TEXT.sub.fontSize;
|
|
38
|
+
|
|
39
|
+
/** 字の箱の高さ。 字の大きさに上下の余白を足す */
|
|
40
|
+
const 箱の高さ = Math.round(端の字の大きさ * 1.2);
|
|
41
|
+
|
|
42
|
+
/** 字の大きさに対する baseline の深さ。 等幅の字の ascent が字の大きさの 8 割ほど */
|
|
43
|
+
const BASELINE_RATIO = 0.8;
|
|
44
|
+
|
|
45
|
+
/** どちらの端か。 `head` = 行き先 (`to`)、 `tail` = 出どころ (`from`) */
|
|
46
|
+
export type 線の端 = "head" | "tail";
|
|
47
|
+
|
|
48
|
+
export interface 端の字の置き場所 {
|
|
49
|
+
/** `text` の x。 どちらの縁かは `anchor` が決める */
|
|
50
|
+
x: number;
|
|
51
|
+
/** `text` の baseline の y */
|
|
52
|
+
y: number;
|
|
53
|
+
anchor: "start" | "end";
|
|
54
|
+
/** 字が占める箱 (world)。 重なりの検査に使う */
|
|
55
|
+
box: { x: number; y: number; w: number; h: number };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
type 点 = { x: number; y: number };
|
|
59
|
+
|
|
60
|
+
/** 端の点と、線がその端へ入ってくる向き (単位ベクトル)。 取れない時は `null` */
|
|
61
|
+
function 向きを取る(end: 点, 候補: ReadonlyArray<点 | undefined>): { end: 点; ux: number; uy: number } | null {
|
|
62
|
+
for (const p of 候補) {
|
|
63
|
+
if (!p) continue;
|
|
64
|
+
const dx = end.x - p.x;
|
|
65
|
+
const dy = end.y - p.y;
|
|
66
|
+
const len = Math.hypot(dx, dy);
|
|
67
|
+
if (len > 1e-6) return { end, ux: dx / len, uy: dy / len };
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 端の点と、線がその端へ入ってくる向き。
|
|
74
|
+
*
|
|
75
|
+
* 行き先の端は最後の区間から、出どころの端は最初の区間を逆にたどって取る。 端の区間の長さが
|
|
76
|
+
* 0 の時は隣の区間へ進む。 向きが取れない (区間が無い / 全て長さ 0) 時は `null`。
|
|
77
|
+
*/
|
|
78
|
+
function 端での向き(d: string, 端: 線の端): { end: 点; ux: number; uy: number } | null {
|
|
79
|
+
const segs = extractPathSegments(d);
|
|
80
|
+
if (segs.length === 0) return null;
|
|
81
|
+
if (端 === "head") {
|
|
82
|
+
const last = segs[segs.length - 1]!;
|
|
83
|
+
const end = { x: last.x2, y: last.y2 };
|
|
84
|
+
const 候補 = segs
|
|
85
|
+
.slice()
|
|
86
|
+
.reverse()
|
|
87
|
+
.flatMap((s) => [s.cmd === "Q" ? s.ctrl?.[0] : s.cmd === "C" ? s.ctrl?.[1] : undefined, { x: s.x1, y: s.y1 }]);
|
|
88
|
+
return 向きを取る(end, 候補);
|
|
89
|
+
}
|
|
90
|
+
const first = segs[0]!;
|
|
91
|
+
const end = { x: first.x1, y: first.y1 };
|
|
92
|
+
const 候補 = segs.flatMap((s) => [...(s.ctrl ?? []), { x: s.x2, y: s.y2 }]);
|
|
93
|
+
return 向きを取る(end, 候補);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** 端の字を描く位置。 字が空か、線の向きが取れない時は `null` (描かない) */
|
|
97
|
+
export function 端の字を置く(
|
|
98
|
+
edge: {
|
|
99
|
+
d: string;
|
|
100
|
+
headLabel?: string;
|
|
101
|
+
tailLabel?: string;
|
|
102
|
+
label?: string;
|
|
103
|
+
sub?: string;
|
|
104
|
+
labelX?: number;
|
|
105
|
+
labelY?: number;
|
|
106
|
+
},
|
|
107
|
+
端: 線の端 = "head",
|
|
108
|
+
): 端の字の置き場所 | null {
|
|
109
|
+
const text = (端 === "head" ? edge.headLabel : edge.tailLabel)?.trim();
|
|
110
|
+
if (!text) return null;
|
|
111
|
+
const 向き = 端での向き(edge.d, 端);
|
|
112
|
+
if (!向き) return null;
|
|
113
|
+
const { end, ux, uy } = 向き;
|
|
114
|
+
const bx = end.x - ux * 端の字を戻す距離;
|
|
115
|
+
const by = end.y - uy * 端の字を戻す距離;
|
|
116
|
+
const w = measureTextWidth(text, {
|
|
117
|
+
fontSize: 端の字の大きさ,
|
|
118
|
+
fontWeight: EDGE_LABEL_TEXT.sub.fontWeight,
|
|
119
|
+
fontFamily: "mono",
|
|
120
|
+
});
|
|
121
|
+
const h = 箱の高さ;
|
|
122
|
+
// 札の中心。 札を描かない線と、位置がまだ無い線は `null`
|
|
123
|
+
const 札 =
|
|
124
|
+
hasRenderedLabel(edge) && edge.labelX !== undefined && edge.labelY !== undefined
|
|
125
|
+
? { x: edge.labelX, y: edge.labelY }
|
|
126
|
+
: null;
|
|
127
|
+
|
|
128
|
+
let anchor: "start" | "end";
|
|
129
|
+
let box: { x: number; y: number; w: number; h: number };
|
|
130
|
+
if (Math.abs(ux) >= Math.abs(uy)) {
|
|
131
|
+
// 横向き。 右へ進む線は字が端の手前 (左) に伸びるので右の縁を揃える
|
|
132
|
+
const 右へ進む = ux > 0;
|
|
133
|
+
const 上に置く = 札 !== null && 札.y > by;
|
|
134
|
+
anchor = 右へ進む ? "end" : "start";
|
|
135
|
+
box = {
|
|
136
|
+
x: 右へ進む ? bx - w : bx,
|
|
137
|
+
y: 上に置く ? by - 端の字と線の隙間 - h : by + 端の字と線の隙間,
|
|
138
|
+
w,
|
|
139
|
+
h,
|
|
140
|
+
};
|
|
141
|
+
} else {
|
|
142
|
+
// 縦向き。 下へ進む線は字が端の手前 (上) に来るので下の辺を揃える
|
|
143
|
+
const 下へ進む = uy > 0;
|
|
144
|
+
const 右に置く = 札 !== null && 札.x < bx;
|
|
145
|
+
anchor = 右に置く ? "start" : "end";
|
|
146
|
+
box = {
|
|
147
|
+
x: 右に置く ? bx + 端の字と線の隙間 : bx - 端の字と線の隙間 - w,
|
|
148
|
+
y: 下へ進む ? by - h : by,
|
|
149
|
+
w,
|
|
150
|
+
h,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const x = anchor === "start" ? box.x : box.x + box.w;
|
|
154
|
+
const y = box.y + (h - 端の字の大きさ) / 2 + 端の字の大きさ * BASELINE_RATIO;
|
|
155
|
+
return { x, y, anchor, box };
|
|
156
|
+
}
|
package/src/presets.ts
CHANGED
|
@@ -1430,8 +1430,10 @@ export type UmlRelation = {
|
|
|
1430
1430
|
type: ClassRelationType;
|
|
1431
1431
|
/** 関係 label (default は type 名) */
|
|
1432
1432
|
label?: string;
|
|
1433
|
-
/** 多重度 (例 "1..*" / "0..1") */
|
|
1433
|
+
/** 多重度 (例 "1..*" / "0..1")。 行き先 (`to`) の端に添える (#821) */
|
|
1434
1434
|
cardinality?: string;
|
|
1435
|
+
/** 出どころ (`from`) 側の多重度 (例 "1")。 出どころの端に添える (#825) */
|
|
1436
|
+
tailCardinality?: string;
|
|
1435
1437
|
tone?: Tone;
|
|
1436
1438
|
/**
|
|
1437
1439
|
* 矢印の先の形 (cdl#574)。 書かなければ種類から決まる (`CLASS_RELATION_LOOK`)。
|
|
@@ -1573,7 +1575,10 @@ export function classDiagram(preset: ClassDiagramPreset): ClassDiagramBuilder {
|
|
|
1573
1575
|
b.edge(r.from, r.to, {
|
|
1574
1576
|
id: edgeId,
|
|
1575
1577
|
label: r.label ?? r.type,
|
|
1576
|
-
|
|
1578
|
+
// 多重度は行き先の端に添える (#821)。 札の下の行に入れると語と続けて読まれ
|
|
1579
|
+
// (英字の頃は「HAS 1..*」 が「HAS1」)、 どちらの端の数かも読めない
|
|
1580
|
+
...(r.cardinality ? { headLabel: r.cardinality } : {}),
|
|
1581
|
+
...(r.tailCardinality ? { tailLabel: r.tailCardinality } : {}),
|
|
1577
1582
|
tone: r.tone ?? 図の既定 ?? CLASS_RELATION_TONE[r.type],
|
|
1578
1583
|
// 関係の種類から線と端の形を決める (cdl#574 / #578)。 書いた値が勝つ
|
|
1579
1584
|
style: r.style ?? 見た目.style,
|
package/src/render/edges.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { 等幅の字 } from "./mono-text";
|
|
2
2
|
import type { JSX } from "react";
|
|
3
3
|
import { computeLabelBBoxWorld, hasRenderedLabel, LABEL_PILL_PAD_X } from "../layout/spec";
|
|
4
|
+
import { 端の字の大きさ, 端の字を置く, type 線の端 } from "../layout/head-label";
|
|
4
5
|
import type { EdgeRole, LaidEdge, Tone } from "../types";
|
|
5
6
|
import { edgeHeadMarkerName } from "./edge-head";
|
|
6
7
|
import { toneColor } from "./tone";
|
|
@@ -394,3 +395,43 @@ export function CdlEdgeLabelView({
|
|
|
394
395
|
</g>
|
|
395
396
|
);
|
|
396
397
|
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* 線の端に添える字 (#821 / #825)。 札と同じく最前面の pass で描く。 `端` で行き先か出どころかを選ぶ。
|
|
401
|
+
*
|
|
402
|
+
* 下地の四角は敷かず、字の周りに下地色の縁取りを付ける (`paint-order: stroke`)。 字は線の脇、
|
|
403
|
+
* 箱の角の近くに置くので、四角い下地だと箱の角や線に被って小さな箱に見える。
|
|
404
|
+
*/
|
|
405
|
+
export function CdlEdgeEndLabelView({
|
|
406
|
+
edge,
|
|
407
|
+
active,
|
|
408
|
+
端,
|
|
409
|
+
}: {
|
|
410
|
+
edge: LaidEdge;
|
|
411
|
+
active: boolean;
|
|
412
|
+
端: 線の端;
|
|
413
|
+
}): JSX.Element | null {
|
|
414
|
+
const 置き場所 = 端の字を置く(edge, 端);
|
|
415
|
+
if (!置き場所) return null;
|
|
416
|
+
const color = edgeColor(edge);
|
|
417
|
+
return (
|
|
418
|
+
<text
|
|
419
|
+
data-cdl-role="edge-end-label"
|
|
420
|
+
data-cdl-edge-end-label-for={edge.id}
|
|
421
|
+
data-cdl-edge-end={端}
|
|
422
|
+
x={置き場所.x}
|
|
423
|
+
y={置き場所.y}
|
|
424
|
+
fontSize={端の字の大きさ}
|
|
425
|
+
fontWeight={EDGE_LABEL_TEXT.sub.fontWeight}
|
|
426
|
+
textAnchor={置き場所.anchor}
|
|
427
|
+
fill={active ? color : "var(--cdl-text-dim, #5a6270)"}
|
|
428
|
+
stroke="var(--cdl-label-bg, #ffffff)"
|
|
429
|
+
strokeWidth={4}
|
|
430
|
+
strokeLinejoin="round"
|
|
431
|
+
paintOrder="stroke"
|
|
432
|
+
style={{ fontFamily: fontFamilyAttr("sub") }}
|
|
433
|
+
>
|
|
434
|
+
{等幅の字(端 === "head" ? edge.headLabel : edge.tailLabel, 端の字の大きさ)}
|
|
435
|
+
</text>
|
|
436
|
+
);
|
|
437
|
+
}
|
package/src/render/stage.tsx
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
edgeHeadMarkerName,
|
|
21
21
|
edgeHeadPaint,
|
|
22
22
|
} from "./edge-head";
|
|
23
|
-
import { CdlEdgeView, CdlEdgeGlowView, CdlEdgeLabelView } from "./edges";
|
|
23
|
+
import { CdlEdgeView, CdlEdgeGlowView, CdlEdgeEndLabelView, CdlEdgeLabelView } from "./edges";
|
|
24
24
|
import { CdlNodeView } from "./nodes";
|
|
25
25
|
import { resolveChartData } from "./payload-binding";
|
|
26
26
|
import { relatedFocusSet } from "./relation-focus";
|
|
@@ -453,6 +453,20 @@ export function CdlStage({
|
|
|
453
453
|
/>
|
|
454
454
|
))}
|
|
455
455
|
|
|
456
|
+
{/* 線の端に添える字 (#821 / #825)。 札と同じ最前面の pass */}
|
|
457
|
+
{laid.edges
|
|
458
|
+
.filter((edge) => (edge.headLabel || edge.tailLabel) && 矢印の出番.出るか(edge.id))
|
|
459
|
+
.flatMap((edge) =>
|
|
460
|
+
(["head", "tail"] as const).map((端) => (
|
|
461
|
+
<CdlEdgeEndLabelView
|
|
462
|
+
key={`${端}-label-${edge.id}`}
|
|
463
|
+
edge={edge}
|
|
464
|
+
active={activeSet.has(edge.id)}
|
|
465
|
+
端={端}
|
|
466
|
+
/>
|
|
467
|
+
)),
|
|
468
|
+
)}
|
|
469
|
+
|
|
456
470
|
{/* debug overlay = engine が把握している bbox + collision を半透明で重ね描き */}
|
|
457
471
|
{debug && (
|
|
458
472
|
<g pointerEvents="none">
|
package/src/types.ts
CHANGED
|
@@ -758,6 +758,19 @@ export type CdlEdge = {
|
|
|
758
758
|
* compileEr 経路で edge label に "(1:N)" 形式で併記、 他 preset では透過。
|
|
759
759
|
*/
|
|
760
760
|
cardinality?: string;
|
|
761
|
+
/**
|
|
762
|
+
* 行き先の端に添える短い字 (#821)。 クラス図の多重度 (`1..*`) に使う。
|
|
763
|
+
*
|
|
764
|
+
* 線の中ほどの札 (`label` / `sub`) に入れると、どちらの端の数かが読めない。
|
|
765
|
+
* 置き場所は線の最後の区間から決まる (`layout/head-label.ts`)。
|
|
766
|
+
*/
|
|
767
|
+
headLabel?: string;
|
|
768
|
+
/**
|
|
769
|
+
* 出どころの端に添える短い字 (#825)。 `headLabel` と対。 クラス図の出どころ側の多重度に使う。
|
|
770
|
+
*
|
|
771
|
+
* UML は関係の両端に多重度を書く。 置き場所の計算は `headLabel` と同じ (`layout/head-label.ts`)。
|
|
772
|
+
*/
|
|
773
|
+
tailLabel?: string;
|
|
761
774
|
/** label の x 方向 fine offset (default 0)、 著者が細かく位置調整するための逃げ道 */
|
|
762
775
|
labelOffsetX?: number;
|
|
763
776
|
/** label の y 方向 fine offset (default 0、 + で下、 - で上) */
|