@cardenelabs/cdl 0.124.0 → 0.125.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 +43 -1
- package/README.md +8 -0
- package/dist/index.cjs +873 -142
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +873 -143
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +858 -142
- 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 +858 -142
- package/dist/react.js.map +1 -1
- package/dist/{render-U6omSNH2.d.cts → render-7yEHIUK1.d.cts} +57 -3
- package/dist/{render-U6omSNH2.d.ts → render-7yEHIUK1.d.ts} +57 -3
- package/package.json +12 -9
- package/src/builder.ts +6 -0
- package/src/index.ts +4 -0
- package/src/kinds/card.tsx +12 -4
- package/src/kinds/generic.tsx +19 -9
- package/src/kinds/station.tsx +105 -19
- package/src/kinds/terminal-mark.tsx +36 -9
- package/src/layout/edges.ts +77 -24
- package/src/layout/lanes.ts +69 -5
- package/src/layout/legend.ts +68 -0
- package/src/layout/metro-path.ts +123 -30
- package/src/layout/nodes.ts +13 -2
- package/src/layout/spec.ts +17 -1
- package/src/layout/tokens.ts +8 -1
- package/src/layout.ts +20 -2
- package/src/render/edge-head.ts +6 -0
- package/src/render/edges.tsx +27 -6
- package/src/render/legend.tsx +120 -0
- package/src/render/nodes.tsx +21 -5
- package/src/render/stage.tsx +255 -10
- package/src/render/template-fields.ts +2 -0
- package/src/types.ts +106 -5
- package/src/validate.ts +5 -0
- package/src/visual-validate.ts +7 -7
package/dist/react.js
CHANGED
|
@@ -1004,7 +1004,7 @@ function drawsTitleOutsideBox(kind) {
|
|
|
1004
1004
|
}
|
|
1005
1005
|
var TITLE_FONT_SIZE_DEFAULT = 18;
|
|
1006
1006
|
var TITLE_FONT_SIZE = new Map([
|
|
1007
|
-
...["dyn-rect", "dyn-circle", "dyn-arc", "dyn-wave", "dyn-polygon"
|
|
1007
|
+
...["dyn-rect", "dyn-circle", "dyn-arc", "dyn-wave", "dyn-polygon"].map(
|
|
1008
1008
|
(k) => [k, 13]
|
|
1009
1009
|
),
|
|
1010
1010
|
...[
|
|
@@ -1049,8 +1049,10 @@ var TITLE_FONT_SIZE = new Map([
|
|
|
1049
1049
|
"webhook"
|
|
1050
1050
|
].map((k) => [k, 20]),
|
|
1051
1051
|
...["card", "event", "function"].map((k) => [k, 24]),
|
|
1052
|
+
["station", 25],
|
|
1052
1053
|
["actor", 32],
|
|
1053
|
-
["storage", 34]
|
|
1054
|
+
["storage", 34],
|
|
1055
|
+
["timeline-number", 18]
|
|
1054
1056
|
]);
|
|
1055
1057
|
function titleFontSize(kind) {
|
|
1056
1058
|
return TITLE_FONT_SIZE.get(kind ?? "") ?? TITLE_FONT_SIZE_DEFAULT;
|
|
@@ -1060,9 +1062,17 @@ function skipsNodeTitleWidthCheck(kind) {
|
|
|
1060
1062
|
return KINDS_WITH_TITLE_WIDTH_OUTSIDE_NODE.has(kind ?? "");
|
|
1061
1063
|
}
|
|
1062
1064
|
var TITLE_BOX_PADDING = 52;
|
|
1065
|
+
var TIMELINE_NUMBER_STROKE = 4;
|
|
1066
|
+
function titleUsableWidth(kind, w, h) {
|
|
1067
|
+
if (kind === "timeline-number") {
|
|
1068
|
+
return Math.min(w, h) - 2 * TIMELINE_NUMBER_STROKE;
|
|
1069
|
+
}
|
|
1070
|
+
return w - (drawsTitleOutsideBox(kind) ? 0 : TITLE_BOX_PADDING);
|
|
1071
|
+
}
|
|
1063
1072
|
var KINDS_SCALING_TITLE_WHEN_LOW = /* @__PURE__ */ new Set(["actor", "event", "function", "storage"]);
|
|
1064
1073
|
var KINDS_SCALING_TITLE_ALWAYS = /* @__PURE__ */ new Set([
|
|
1065
1074
|
"card",
|
|
1075
|
+
"timeline-number",
|
|
1066
1076
|
"shape-file",
|
|
1067
1077
|
"shape-folder",
|
|
1068
1078
|
"shape-cloud",
|
|
@@ -1146,14 +1156,16 @@ var KINDS_DRAWING_ONLY_SHAPE = [
|
|
|
1146
1156
|
];
|
|
1147
1157
|
var KINDS_WITHOUT_EYEBROW_TEXT = /* @__PURE__ */ new Set([
|
|
1148
1158
|
...KINDS_DRAWING_ONLY_SHAPE,
|
|
1149
|
-
...KINDS_WITHOUT_TITLE_TEXT
|
|
1159
|
+
...KINDS_WITHOUT_TITLE_TEXT,
|
|
1160
|
+
"timeline-number"
|
|
1150
1161
|
]);
|
|
1151
1162
|
function rendersEyebrow(kind) {
|
|
1152
1163
|
return !KINDS_WITHOUT_EYEBROW_TEXT.has(kind ?? "");
|
|
1153
1164
|
}
|
|
1154
1165
|
var KINDS_WITHOUT_SUBTITLE_TEXT = /* @__PURE__ */ new Set([
|
|
1155
1166
|
...KINDS_DRAWING_OWN_PAYLOAD,
|
|
1156
|
-
...KINDS_WITHOUT_TITLE_TEXT
|
|
1167
|
+
...KINDS_WITHOUT_TITLE_TEXT,
|
|
1168
|
+
"timeline-number"
|
|
1157
1169
|
]);
|
|
1158
1170
|
function rendersSubtitle(kind) {
|
|
1159
1171
|
return !KINDS_WITHOUT_SUBTITLE_TEXT.has(kind ?? "");
|
|
@@ -3087,6 +3099,14 @@ function curvePath(from, to, edge, labelMarginExtra = 0, textMetrics = "proporti
|
|
|
3087
3099
|
|
|
3088
3100
|
// src/layout/metro-path.ts
|
|
3089
3101
|
var METRO_CORNER_RADIUS = 24;
|
|
3102
|
+
var METRO_BRANCH_CORNER_RADIUS = 22;
|
|
3103
|
+
var METRO_BRANCH_STUB = 30;
|
|
3104
|
+
var METRO_DECISION_HEIGHT = 88;
|
|
3105
|
+
var METRO_DECISION_WIDTH = 116;
|
|
3106
|
+
var METRO_RETURN_END_OFFSET = 43;
|
|
3107
|
+
var METRO_RETURN_START_OFFSET = 24;
|
|
3108
|
+
var METRO_LINE_WIDTH = 10;
|
|
3109
|
+
var METRO_LINE_WIDTH_CSS = `var(--cdl-metro-line-width, ${METRO_LINE_WIDTH}px)`;
|
|
3090
3110
|
var T = Math.SQRT2 - 1;
|
|
3091
3111
|
function round2(v) {
|
|
3092
3112
|
return Math.round(v * 100) / 100;
|
|
@@ -3104,7 +3124,63 @@ function polyline(points) {
|
|
|
3104
3124
|
});
|
|
3105
3125
|
return distinct.map((p, i) => `${i === 0 ? "M" : "L"} ${point(p)}`).join(" ");
|
|
3106
3126
|
}
|
|
3107
|
-
function
|
|
3127
|
+
function quadraticCornerPath(start, corner, end, radius) {
|
|
3128
|
+
const horizontalDir = Math.sign(corner.x - start.x);
|
|
3129
|
+
const verticalDir = Math.sign(end.y - corner.y);
|
|
3130
|
+
const r = Math.min(
|
|
3131
|
+
radius,
|
|
3132
|
+
Math.abs(corner.x - start.x),
|
|
3133
|
+
Math.abs(end.y - corner.y)
|
|
3134
|
+
);
|
|
3135
|
+
const before = { x: corner.x - horizontalDir * r, y: corner.y };
|
|
3136
|
+
const after = { x: corner.x, y: corner.y + verticalDir * r };
|
|
3137
|
+
return [
|
|
3138
|
+
`M ${point(start)}`,
|
|
3139
|
+
`L ${point(before)}`,
|
|
3140
|
+
`Q ${point(corner)} ${point(after)}`,
|
|
3141
|
+
`L ${point(end)}`
|
|
3142
|
+
].join(" ");
|
|
3143
|
+
}
|
|
3144
|
+
function decisionBranchPath(start, end) {
|
|
3145
|
+
const horizontalDir = Math.sign(end.x - start.x);
|
|
3146
|
+
const verticalDir = Math.sign(end.y - start.y);
|
|
3147
|
+
const turnX = start.x + horizontalDir * (METRO_BRANCH_STUB + METRO_BRANCH_CORNER_RADIUS);
|
|
3148
|
+
const radius = Math.min(
|
|
3149
|
+
METRO_BRANCH_CORNER_RADIUS,
|
|
3150
|
+
Math.abs(end.y - start.y) / 2,
|
|
3151
|
+
Math.abs(end.x - turnX)
|
|
3152
|
+
);
|
|
3153
|
+
const firstCorner = { x: turnX, y: start.y };
|
|
3154
|
+
const secondCorner = { x: turnX, y: end.y };
|
|
3155
|
+
const beforeFirst = {
|
|
3156
|
+
x: turnX - horizontalDir * radius,
|
|
3157
|
+
y: start.y
|
|
3158
|
+
};
|
|
3159
|
+
const afterFirst = {
|
|
3160
|
+
x: turnX,
|
|
3161
|
+
y: start.y + verticalDir * radius
|
|
3162
|
+
};
|
|
3163
|
+
const beforeSecond = {
|
|
3164
|
+
x: turnX,
|
|
3165
|
+
y: end.y - verticalDir * radius
|
|
3166
|
+
};
|
|
3167
|
+
const afterSecond = {
|
|
3168
|
+
x: turnX + horizontalDir * radius,
|
|
3169
|
+
y: end.y
|
|
3170
|
+
};
|
|
3171
|
+
return {
|
|
3172
|
+
d: [
|
|
3173
|
+
`M ${point(start)}`,
|
|
3174
|
+
`L ${point(beforeFirst)}`,
|
|
3175
|
+
`Q ${point(firstCorner)} ${point(afterFirst)}`,
|
|
3176
|
+
`L ${point(beforeSecond)}`,
|
|
3177
|
+
`Q ${point(secondCorner)} ${point(afterSecond)}`,
|
|
3178
|
+
`L ${point(end)}`
|
|
3179
|
+
].join(" "),
|
|
3180
|
+
turnX
|
|
3181
|
+
};
|
|
3182
|
+
}
|
|
3183
|
+
function metroPath(from, to, edge, _labelMarginExtra = 0, _textMetrics = "proportional") {
|
|
3108
3184
|
const fromLeft = from.cx - from.w / 2;
|
|
3109
3185
|
const fromRight = from.cx + from.w / 2;
|
|
3110
3186
|
const toLeft = to.cx - to.w / 2;
|
|
@@ -3139,11 +3215,45 @@ function metroPath(from, to, edge, labelMarginExtra = 0, textMetrics = "proporti
|
|
|
3139
3215
|
const sgn = Math.sign(dy);
|
|
3140
3216
|
let d;
|
|
3141
3217
|
let mid;
|
|
3142
|
-
let
|
|
3143
|
-
if (Math.abs(dy)
|
|
3218
|
+
let metroReturn = false;
|
|
3219
|
+
if (from.kind === "decision" && Math.abs(dy) >= SAME_HEIGHT_THRESHOLD) {
|
|
3220
|
+
const verticalDir = Math.sign(dy);
|
|
3221
|
+
if (Math.abs(to.cx - from.cx) < SAME_HEIGHT_THRESHOLD) {
|
|
3222
|
+
const start = { x: from.cx, y: from.cy + verticalDir * from.h / 2 };
|
|
3223
|
+
const end = { x: to.cx, y: to.cy };
|
|
3224
|
+
d = polyline([start, end]);
|
|
3225
|
+
fromSide = verticalDir < 0 ? "top" : "bottom";
|
|
3226
|
+
toSide = verticalDir < 0 ? "bottom" : "top";
|
|
3227
|
+
mid = { x: start.x, y: (start.y + end.y) / 2 };
|
|
3228
|
+
} else {
|
|
3229
|
+
const horizontalDir = Math.sign(to.cx - from.cx);
|
|
3230
|
+
const start = {
|
|
3231
|
+
x: from.cx + horizontalDir * from.w / 2,
|
|
3232
|
+
y: from.cy
|
|
3233
|
+
};
|
|
3234
|
+
const end = {
|
|
3235
|
+
x: to.cx - horizontalDir * to.w / 2,
|
|
3236
|
+
y: to.cy
|
|
3237
|
+
};
|
|
3238
|
+
const branch = decisionBranchPath(start, end);
|
|
3239
|
+
d = branch.d;
|
|
3240
|
+
fromSide = horizontalDir > 0 ? "right" : "left";
|
|
3241
|
+
toSide = horizontalDir > 0 ? "left" : "right";
|
|
3242
|
+
mid = { x: branch.turnX, y: (start.y + end.y) / 2 };
|
|
3243
|
+
}
|
|
3244
|
+
} else if (edge?.style === "dashed" && from.kind === "station" && to.kind === "station" && to.cx < from.cx && Math.abs(dy) >= SAME_HEIGHT_THRESHOLD) {
|
|
3245
|
+
const verticalDir = Math.sign(to.cy - from.cy);
|
|
3246
|
+
const start = { x: from.cx - METRO_RETURN_START_OFFSET, y: from.cy };
|
|
3247
|
+
const end = { x: to.cx, y: to.cy - verticalDir * METRO_RETURN_END_OFFSET };
|
|
3248
|
+
const corner = { x: end.x, y: start.y };
|
|
3249
|
+
fromSide = "left";
|
|
3250
|
+
toSide = verticalDir < 0 ? "bottom" : "top";
|
|
3251
|
+
d = quadraticCornerPath(start, corner, end, METRO_BRANCH_CORNER_RADIUS);
|
|
3252
|
+
mid = { x: (start.x + corner.x) / 2, y: start.y };
|
|
3253
|
+
metroReturn = true;
|
|
3254
|
+
} else if (Math.abs(dy) < SAME_HEIGHT_THRESHOLD) {
|
|
3144
3255
|
d = `M ${point({ x: x1, y: y1 })} L ${point({ x: x2, y: y2 })}`;
|
|
3145
3256
|
mid = { x: (x1 + x2) / 2, y: (y1 + y2) / 2 };
|
|
3146
|
-
tangent = { x: x2 - x1, y: y2 - y1 };
|
|
3147
3257
|
} else if (fromSide !== toSide && Math.abs(x2 - x1) >= Math.abs(dy)) {
|
|
3148
3258
|
const horizontal = Math.abs(x2 - x1);
|
|
3149
3259
|
const s = (horizontal - Math.abs(dy)) / 2;
|
|
@@ -3173,7 +3283,6 @@ function metroPath(from, to, edge, labelMarginExtra = 0, textMetrics = "proporti
|
|
|
3173
3283
|
d = polyline([p0, p1, p2, p3]);
|
|
3174
3284
|
}
|
|
3175
3285
|
mid = { x: (x1 + x2) / 2, y: (y1 + y2) / 2 };
|
|
3176
|
-
tangent = w;
|
|
3177
3286
|
} else {
|
|
3178
3287
|
fromSide = "right";
|
|
3179
3288
|
toSide = "right";
|
|
@@ -3203,28 +3312,15 @@ function metroPath(from, to, edge, labelMarginExtra = 0, textMetrics = "proporti
|
|
|
3203
3312
|
`L ${point(p4)}`
|
|
3204
3313
|
].join(" ");
|
|
3205
3314
|
mid = { x: p2.x - T * r, y: p2.y };
|
|
3206
|
-
tangent = { x: 0, y: sgn };
|
|
3207
|
-
}
|
|
3208
|
-
if (edge?.overlay) {
|
|
3209
|
-
return { d, fromSide, toSide, labelX: mid.x, labelY: mid.y, labelAnchor: "middle" };
|
|
3210
|
-
}
|
|
3211
|
-
const tangentLength = Math.hypot(tangent.x, tangent.y);
|
|
3212
|
-
let normalX = tangent.y / tangentLength;
|
|
3213
|
-
let normalY = -tangent.x / tangentLength;
|
|
3214
|
-
if (normalY > Number.EPSILON || Math.abs(normalY) <= Number.EPSILON && normalX < 0) {
|
|
3215
|
-
normalX *= -1;
|
|
3216
|
-
normalY *= -1;
|
|
3217
3315
|
}
|
|
3218
|
-
const labelW = computeLabelBoxW(edge?.label, edge?.sub, textMetrics);
|
|
3219
|
-
const labelH = labelPillH(edge?.sub);
|
|
3220
|
-
const distance = labelPathClearanceHorizontal(edge) + (Math.abs(normalX) * labelW + Math.abs(normalY) * labelH) / 2 + labelMarginExtra;
|
|
3221
3316
|
return {
|
|
3222
3317
|
d,
|
|
3223
3318
|
fromSide,
|
|
3224
3319
|
toSide,
|
|
3225
|
-
labelX: mid.x
|
|
3226
|
-
labelY: mid.y
|
|
3227
|
-
labelAnchor: "middle"
|
|
3320
|
+
labelX: mid.x,
|
|
3321
|
+
labelY: mid.y,
|
|
3322
|
+
labelAnchor: "middle",
|
|
3323
|
+
...metroReturn ? { metroReturn: true } : {}
|
|
3228
3324
|
};
|
|
3229
3325
|
}
|
|
3230
3326
|
|
|
@@ -3351,12 +3447,14 @@ var NODE_KINDS = [
|
|
|
3351
3447
|
"shape-lawyer",
|
|
3352
3448
|
"shape-trader",
|
|
3353
3449
|
"shape-customer-service",
|
|
3354
|
-
// 流れの始まりと終わりの印 2 種 (#560) ...
|
|
3355
|
-
//
|
|
3450
|
+
// 流れの始まりと終わりの印 2 種 (#560) ... 始点と終点は線の端から推測せず、著者が
|
|
3451
|
+
// `kind: "mark-start"` / `kind: "mark-end"` の node を明示する。印は文字を描かない
|
|
3356
3452
|
"mark-start",
|
|
3357
3453
|
"mark-end",
|
|
3358
3454
|
// 路線図の駅 (#996) ... 線路上の点を小さな丸で示し、名前と説明は丸の外に置く
|
|
3359
3455
|
"station",
|
|
3456
|
+
// 時間軸の番号 (#1017) ... 実線の軸上に番号を入れた丸を置く。路線図の駅とは別の意味を持つ。
|
|
3457
|
+
"timeline-number",
|
|
3360
3458
|
// 時系列のやり取り (#578) ... 1 つの箱が図を丸ごと描く。 縦が時間で、参加者は箱を持たない
|
|
3361
3459
|
"sequence-board"
|
|
3362
3460
|
];
|
|
@@ -6548,7 +6646,7 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes, \u5
|
|
|
6548
6646
|
const LIFELINE_W_THRESHOLD = 8;
|
|
6549
6647
|
for (const n of laid.nodes) {
|
|
6550
6648
|
if (n.w < LIFELINE_W_THRESHOLD) continue;
|
|
6551
|
-
if (n.kind === "station") continue;
|
|
6649
|
+
if (n.kind === "station" || n.kind === "timeline-number") continue;
|
|
6552
6650
|
if (n.w < MIN_NODE_W || n.h < MIN_NODE_H) {
|
|
6553
6651
|
push(
|
|
6554
6652
|
"node-visibility",
|
|
@@ -6574,8 +6672,7 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes, \u5
|
|
|
6574
6672
|
if (!isRenderedNode(n)) continue;
|
|
6575
6673
|
const titleTrimmed = n.title?.trim() ?? "";
|
|
6576
6674
|
if (!titleTrimmed) continue;
|
|
6577
|
-
const \
|
|
6578
|
-
const \u4F7F\u3048\u308B\u5E452 = n.w - \u4F59\u767D;
|
|
6675
|
+
const \u4F7F\u3048\u308B\u5E452 = titleUsableWidth(n.kind, n.w, n.h);
|
|
6579
6676
|
const \u5B9F\u5E45 = measureTextWidth(titleTrimmed, {
|
|
6580
6677
|
fontSize: titleFontSize(n.kind),
|
|
6581
6678
|
bound: "drawn",
|
|
@@ -6594,7 +6691,7 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes, \u5
|
|
|
6594
6691
|
push(
|
|
6595
6692
|
"text-readability",
|
|
6596
6693
|
// 字ごとの実幅は小数になるので、読む人に出す時だけ丸める (判定は丸めない)
|
|
6597
|
-
`node "${n.id}" title "${n.title}" \u304C node \u5E45 ${n.w}px \u3092\u8D85\u904E\u3059\u308B\u53EF\u80FD\u6027 (\u671F\u5F85 ${Math.round(\u5B9F\u5E45 + \
|
|
6694
|
+
`node "${n.id}" title "${n.title}" \u304C node \u5E45 ${n.w}px \u3092\u8D85\u904E\u3059\u308B\u53EF\u80FD\u6027 (\u671F\u5F85 ${Math.round(\u5B9F\u5E45 + (n.w - \u4F7F\u3048\u308B\u5E452))}px)`,
|
|
6598
6695
|
"warn"
|
|
6599
6696
|
);
|
|
6600
6697
|
}
|
|
@@ -8154,6 +8251,8 @@ var TOKENS = {
|
|
|
8154
8251
|
lane_label_h: 40,
|
|
8155
8252
|
lane_top_pad: 100,
|
|
8156
8253
|
contain_pad: 28,
|
|
8254
|
+
stage_column_gap: 48,
|
|
8255
|
+
stage_card_text_inset: 18,
|
|
8157
8256
|
// node sizes (kind ごと、 unified row h は engine が max() で算出)
|
|
8158
8257
|
node: {
|
|
8159
8258
|
actor: { w: 340, h: 165 },
|
|
@@ -8280,7 +8379,10 @@ var TOKENS = {
|
|
|
8280
8379
|
"mark-start": { w: 96, h: 96 },
|
|
8281
8380
|
"mark-end": { w: 96, h: 96 },
|
|
8282
8381
|
// 路線図の駅 (#996) ... 正方形にして小さな丸が縦横どちらにも歪まないようにする。
|
|
8283
|
-
|
|
8382
|
+
// 半径 16 と縁 6 の外径を、線路との接点を含めて収める。
|
|
8383
|
+
station: { w: 38, h: 38 },
|
|
8384
|
+
// 時間軸の番号 (#1017) ... 半径 24 の丸と太さ 4 の縁を収める。
|
|
8385
|
+
"timeline-number": { w: 52, h: 52 },
|
|
8284
8386
|
// 時系列のやり取り (#578)。 実寸は中身から決まる (`sequenceBoardMetrics`) ので、
|
|
8285
8387
|
// ここは書かなかった時の受け皿
|
|
8286
8388
|
"sequence-board": { w: 960, h: 640 }
|
|
@@ -8295,6 +8397,8 @@ var LANE_TOP_PAD = TOKENS.lane_top_pad;
|
|
|
8295
8397
|
var STACK_GAP = TOKENS.row_gap;
|
|
8296
8398
|
var NODE_SIZE = TOKENS.node;
|
|
8297
8399
|
var CONTAIN_PAD = TOKENS.contain_pad;
|
|
8400
|
+
var STAGE_COLUMN_GAP = TOKENS.stage_column_gap;
|
|
8401
|
+
var STAGE_CARD_TEXT_INSET = TOKENS.stage_card_text_inset;
|
|
8298
8402
|
var VIEW_PAD = TOKENS.view_pad;
|
|
8299
8403
|
var HEADER_RESERVE = TOKENS.header_reserve;
|
|
8300
8404
|
var DEFAULT_LANE_GAP = 80;
|
|
@@ -8395,12 +8499,24 @@ function layoutEdges(diag, nodes, lanes = [], textMetrics = "proportional") {
|
|
|
8395
8499
|
if (!from) throw new Error(`cdl layout: edge "${e.id}" \u306E from "${e.from}" \u304C node \u306B\u7121\u3044`);
|
|
8396
8500
|
if (!to) throw new Error(`cdl layout: edge "${e.id}" \u306E to "${e.to}" \u304C node \u306B\u7121\u3044`);
|
|
8397
8501
|
const c = curvePath(from, to, e, labelMarginExtra, textMetrics);
|
|
8502
|
+
const fromLane = lmap.get(from.lane);
|
|
8503
|
+
const toLane = lmap.get(to.lane);
|
|
8504
|
+
let labelX = c.labelX;
|
|
8505
|
+
if (fromLane?.stage !== void 0 && toLane?.stage !== void 0 && fromLane.id !== toLane.id && (e.label || e.sub)) {
|
|
8506
|
+
const [leftLane, rightLane] = fromLane.x <= toLane.x ? [fromLane, toLane] : [toLane, fromLane];
|
|
8507
|
+
const gapLeft = leftLane.x + leftLane.width - STAGE_COLUMN_GAP / 2;
|
|
8508
|
+
const gapRight = rightLane.x + STAGE_COLUMN_GAP / 2;
|
|
8509
|
+
const labelHalfWidth = computeLabelBoxW(e.label, e.sub, textMetrics) / 2;
|
|
8510
|
+
const minX = gapLeft + labelHalfWidth;
|
|
8511
|
+
const maxX = gapRight - labelHalfWidth;
|
|
8512
|
+
if (minX <= maxX) labelX = Math.min(maxX, Math.max(minX, labelX));
|
|
8513
|
+
}
|
|
8398
8514
|
positionedEdges.push({
|
|
8399
8515
|
...e,
|
|
8400
8516
|
d: c.d,
|
|
8401
8517
|
fromSide: c.fromSide,
|
|
8402
8518
|
toSide: c.toSide,
|
|
8403
|
-
labelX:
|
|
8519
|
+
labelX: labelX + (e.labelOffsetX ?? 0),
|
|
8404
8520
|
labelY: c.labelY + (e.labelOffsetY ?? 0),
|
|
8405
8521
|
labelAnchor: c.labelAnchor
|
|
8406
8522
|
});
|
|
@@ -8417,7 +8533,8 @@ function layoutEdges(diag, nodes, lanes = [], textMetrics = "proportional") {
|
|
|
8417
8533
|
toSide: m.toSide,
|
|
8418
8534
|
labelX: m.labelX + (e.labelOffsetX ?? 0),
|
|
8419
8535
|
labelY: m.labelY + (e.labelOffsetY ?? 0),
|
|
8420
|
-
labelAnchor: m.labelAnchor
|
|
8536
|
+
labelAnchor: m.labelAnchor,
|
|
8537
|
+
...m.metroReturn ? { metroReturn: true } : {}
|
|
8421
8538
|
});
|
|
8422
8539
|
} else {
|
|
8423
8540
|
autoEdges.push(e);
|
|
@@ -9109,20 +9226,22 @@ function countPathObstacleCrossings(d, obstacles) {
|
|
|
9109
9226
|
const segments = flattenPathSegments(extractPathSegments(d));
|
|
9110
9227
|
return obstacles.filter((obstacle) => segmentsCrossRect(segments, nodeRect(obstacle))).length;
|
|
9111
9228
|
}
|
|
9112
|
-
function makeBackDetourCandidate(A, B, from, to, obstacles, detourY, side) {
|
|
9229
|
+
function makeBackDetourCandidate(A, B, from, to, obstacles, detourY, side, columnXOverride) {
|
|
9113
9230
|
const lowIsA = A.y >= B.y;
|
|
9114
9231
|
const low = lowIsA ? A : B;
|
|
9115
9232
|
const lowBendY = low.y - VERTICAL_DETOUR_EXIT;
|
|
9116
9233
|
const bandTop = Math.min(detourY, lowBendY);
|
|
9117
9234
|
const bandBottom = Math.max(detourY, lowBendY);
|
|
9118
9235
|
const bandObstacles = obstacles.map(nodeRect).filter((rect) => rect.y + rect.h >= bandTop && rect.y <= bandBottom);
|
|
9119
|
-
let columnX = detourColumnFor([from, to], side);
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
|
|
9236
|
+
let columnX = columnXOverride ?? detourColumnFor([from, to], side);
|
|
9237
|
+
if (columnXOverride === void 0) {
|
|
9238
|
+
while (true) {
|
|
9239
|
+
const blockers = bandObstacles.filter(
|
|
9240
|
+
(rect) => rect.x - VERTICAL_DETOUR_GAP < columnX && columnX < rect.x + rect.w + VERTICAL_DETOUR_GAP
|
|
9241
|
+
);
|
|
9242
|
+
if (blockers.length === 0) break;
|
|
9243
|
+
columnX = side === "left" ? Math.min(...blockers.map((rect) => rect.x - VERTICAL_DETOUR_GAP)) : Math.max(...blockers.map((rect) => rect.x + rect.w + VERTICAL_DETOUR_GAP));
|
|
9244
|
+
}
|
|
9126
9245
|
}
|
|
9127
9246
|
const bendAY = lowIsA ? lowBendY : detourY;
|
|
9128
9247
|
const bendBY = lowIsA ? detourY : lowBendY;
|
|
@@ -9231,7 +9350,7 @@ function sidePoint(n, side) {
|
|
|
9231
9350
|
return { x: n.cx + n.w / 2, y: n.cy };
|
|
9232
9351
|
}
|
|
9233
9352
|
}
|
|
9234
|
-
function routePath(from, to, fromSide, toSide, obstacles = [], detourSide,
|
|
9353
|
+
function routePath(from, to, fromSide, toSide, obstacles = [], detourSide, fromLane, toLane, edge, labelObstacles = obstacles, fromOffset = { x: 0, y: 0 }, toOffset = { x: 0, y: 0 }, avoidRects = [], textMetrics = "proportional") {
|
|
9235
9354
|
const labelBoxW = edge ? computeLabelBoxW(edge.label, edge.sub, textMetrics) : 0;
|
|
9236
9355
|
const labelHalfW = labelBoxW / 2;
|
|
9237
9356
|
const labelInit = labelInitClearance(edge);
|
|
@@ -9601,17 +9720,27 @@ function routePath(from, to, fromSide, toSide, obstacles = [], detourSide, _from
|
|
|
9601
9720
|
};
|
|
9602
9721
|
}
|
|
9603
9722
|
if (topTopPair) {
|
|
9604
|
-
const
|
|
9723
|
+
const stagePoint = (point2, node, lane) => lane?.stage === void 0 ? point2 : {
|
|
9724
|
+
x: Math.min(node.cx + node.w / 2 - 24, lane.x + lane.width - 24),
|
|
9725
|
+
y: point2.y
|
|
9726
|
+
};
|
|
9727
|
+
const backA = stagePoint(A, from, fromLane);
|
|
9728
|
+
const backB = stagePoint(B, to, toLane);
|
|
9729
|
+
const stageTops = [fromLane, toLane].filter((lane) => lane?.stage !== void 0).map((lane) => lane.y);
|
|
9730
|
+
const detourY = Math.min(
|
|
9731
|
+
Math.min(backA.y, backB.y) - 100,
|
|
9732
|
+
...stageTops.map((top) => top - VERTICAL_DETOUR_GAP)
|
|
9733
|
+
);
|
|
9605
9734
|
const corner = 14;
|
|
9606
|
-
const xDir =
|
|
9735
|
+
const xDir = backB.x > backA.x ? 1 : -1;
|
|
9607
9736
|
const existing = {
|
|
9608
|
-
d: `M ${
|
|
9609
|
-
L ${
|
|
9610
|
-
Q ${
|
|
9611
|
-
L ${
|
|
9612
|
-
Q ${
|
|
9613
|
-
L ${
|
|
9614
|
-
labelX: (
|
|
9737
|
+
d: `M ${backA.x} ${backA.y}
|
|
9738
|
+
L ${backA.x} ${detourY + corner}
|
|
9739
|
+
Q ${backA.x} ${detourY}, ${backA.x + xDir * corner} ${detourY}
|
|
9740
|
+
L ${backB.x - xDir * corner} ${detourY}
|
|
9741
|
+
Q ${backB.x} ${detourY}, ${backB.x} ${detourY + corner}
|
|
9742
|
+
L ${backB.x} ${backB.y}`,
|
|
9743
|
+
labelX: (backA.x + backB.x) / 2,
|
|
9615
9744
|
// CAR-468 SSOT ... 旧 detourY - 30 magic number を LABEL_INIT_CLEARANCE (26、 CAR-570 で 34 → 26 縮小) に置換。
|
|
9616
9745
|
// CAR-518 SSOT ... dotted-flow は 62 world (marker glow radius 分拡張) を labelInit で参照。
|
|
9617
9746
|
// top-top detour の水平 segment 上方 labelInit world = spec 準拠距離。
|
|
@@ -9620,7 +9749,16 @@ function routePath(from, to, fromSide, toSide, obstacles = [], detourSide, _from
|
|
|
9620
9749
|
};
|
|
9621
9750
|
const existingCrossings = countPathObstacleCrossings(existing.d, obstacles);
|
|
9622
9751
|
if (existingCrossings === 0) return existing;
|
|
9623
|
-
const candidate =
|
|
9752
|
+
const candidate = from.lane === to.lane && fromLane?.stage !== void 0 ? makeBackDetourCandidate(
|
|
9753
|
+
backA,
|
|
9754
|
+
backB,
|
|
9755
|
+
from,
|
|
9756
|
+
to,
|
|
9757
|
+
obstacles,
|
|
9758
|
+
detourY,
|
|
9759
|
+
"right",
|
|
9760
|
+
fromLane.x + fromLane.width
|
|
9761
|
+
) : chooseBackDetourCandidate(backA, backB, from, to, obstacles, detourY);
|
|
9624
9762
|
if (candidate.crossings >= existingCrossings) return existing;
|
|
9625
9763
|
return {
|
|
9626
9764
|
d: candidate.d,
|
|
@@ -10554,12 +10692,56 @@ function \u76F4\u524D\u306E\u6298\u308C\u3054\u3068\u305A\u3089\u3059(segs, \u6A
|
|
|
10554
10692
|
return parts.join(" ");
|
|
10555
10693
|
}
|
|
10556
10694
|
|
|
10695
|
+
// src/layout/legend.ts
|
|
10696
|
+
var LEGEND_FONT_SIZE = 17;
|
|
10697
|
+
var LEGEND_MARK_SCALE = LEGEND_FONT_SIZE / 21;
|
|
10698
|
+
var LEGEND_MARK_REFERENCE_WIDTH = 46;
|
|
10699
|
+
var LEGEND_MARK_WIDTH = LEGEND_MARK_REFERENCE_WIDTH * LEGEND_MARK_SCALE;
|
|
10700
|
+
var LEGEND_MARK_TEXT_GAP = 12 * LEGEND_MARK_SCALE;
|
|
10701
|
+
var LEGEND_ITEM_GAP_RATIO = 0.07;
|
|
10702
|
+
var LEGEND_BASELINE_GAP = 32;
|
|
10703
|
+
var LEGEND_BOTTOM_EXTENT = 10;
|
|
10704
|
+
function layoutLegend(items, viewBox, textMetrics, nodes) {
|
|
10705
|
+
const renderedNodes = nodes.filter(isRenderedNode);
|
|
10706
|
+
const startX = renderedNodes.length > 0 ? Math.min(...renderedNodes.map((node) => node.cx - node.w / 2)) : viewBox.x + VIEW_PAD;
|
|
10707
|
+
const diagramRight = renderedNodes.length > 0 ? Math.max(...renderedNodes.map((node) => node.cx + node.w / 2)) : viewBox.x + viewBox.w - VIEW_PAD;
|
|
10708
|
+
const itemGap = (diagramRight - startX) * LEGEND_ITEM_GAP_RATIO;
|
|
10709
|
+
const y = viewBox.y + viewBox.h - VIEW_PAD + LEGEND_BASELINE_GAP;
|
|
10710
|
+
let x = startX;
|
|
10711
|
+
const legend = items.map((item) => {
|
|
10712
|
+
const laid = { ...item, x, y };
|
|
10713
|
+
x += LEGEND_MARK_WIDTH + LEGEND_MARK_TEXT_GAP + textWidth(item.text, LEGEND_FONT_SIZE, 0, textMetrics) + itemGap;
|
|
10714
|
+
return laid;
|
|
10715
|
+
});
|
|
10716
|
+
const right = x - itemGap;
|
|
10717
|
+
const bottom = y + LEGEND_BOTTOM_EXTENT + VIEW_PAD;
|
|
10718
|
+
return {
|
|
10719
|
+
legend,
|
|
10720
|
+
viewBox: {
|
|
10721
|
+
...viewBox,
|
|
10722
|
+
w: Math.max(viewBox.w, right + VIEW_PAD - viewBox.x),
|
|
10723
|
+
h: Math.max(viewBox.h, bottom - viewBox.y)
|
|
10724
|
+
}
|
|
10725
|
+
};
|
|
10726
|
+
}
|
|
10727
|
+
|
|
10557
10728
|
// src/layout/lanes.ts
|
|
10558
10729
|
var LANE_POSITION_EPSILON = 1e-9;
|
|
10730
|
+
function equalizeStageColumns(lanes, nodes = []) {
|
|
10731
|
+
const stages = lanes.filter((lane) => lane.stage !== void 0);
|
|
10732
|
+
if (stages.length === 0) return lanes;
|
|
10733
|
+
const top = Math.min(...stages.map((lane) => lane.y));
|
|
10734
|
+
const stageIds = new Set(stages.map((lane) => lane.id));
|
|
10735
|
+
const nodeBottoms = nodes.filter((node) => stageIds.has(node.lane)).map((node) => node.cy + node.h / 2 + CONTAIN_PAD);
|
|
10736
|
+
const bottom = Math.max(...stages.map((lane) => lane.y + lane.height), ...nodeBottoms);
|
|
10737
|
+
return lanes.map(
|
|
10738
|
+
(lane) => lane.stage === void 0 ? lane : { ...lane, y: top, height: bottom - top }
|
|
10739
|
+
);
|
|
10740
|
+
}
|
|
10559
10741
|
function layoutLanes(diag) {
|
|
10560
10742
|
const laneGap = diag.viewport?.laneGap ?? diag.viewport?.gap ?? DEFAULT_LANE_GAP;
|
|
10561
10743
|
let cursorX = 0;
|
|
10562
|
-
|
|
10744
|
+
const lanes = diag.lanes.map((lane, index) => {
|
|
10563
10745
|
if (lane.posX !== void 0 && lane.posY !== void 0) {
|
|
10564
10746
|
return {
|
|
10565
10747
|
...lane,
|
|
@@ -10570,7 +10752,9 @@ function layoutLanes(diag) {
|
|
|
10570
10752
|
};
|
|
10571
10753
|
}
|
|
10572
10754
|
const resolvedX = lane.x ?? cursorX;
|
|
10573
|
-
|
|
10755
|
+
const nextLane = diag.lanes[index + 1];
|
|
10756
|
+
const gapAfter = lane.stage !== void 0 && nextLane?.stage !== void 0 ? 0 : laneGap;
|
|
10757
|
+
cursorX = resolvedX + lane.width + gapAfter;
|
|
10574
10758
|
return {
|
|
10575
10759
|
...lane,
|
|
10576
10760
|
x: resolvedX,
|
|
@@ -10578,6 +10762,7 @@ function layoutLanes(diag) {
|
|
|
10578
10762
|
height: LANE_LABEL_H
|
|
10579
10763
|
};
|
|
10580
10764
|
});
|
|
10765
|
+
return equalizeStageColumns(lanes);
|
|
10581
10766
|
}
|
|
10582
10767
|
function expandLanesForNodes(lanes, nodes) {
|
|
10583
10768
|
const targetNodeGap = targetNodeNodeClearance();
|
|
@@ -10606,7 +10791,8 @@ function expandLanesForNodes(lanes, nodes) {
|
|
|
10606
10791
|
if (lane.posX !== void 0 && lane.posY !== void 0) continue;
|
|
10607
10792
|
const inside = nodes.filter((n) => n.lane === lane.id);
|
|
10608
10793
|
const maxNodeW = inside.length > 0 ? Math.max(...inside.map((n) => n.w)) : 0;
|
|
10609
|
-
const
|
|
10794
|
+
const stageMinWidth = lane.stage === void 0 ? 0 : maxNodeW + CONTAIN_PAD + STAGE_COLUMN_GAP;
|
|
10795
|
+
const newWidth = Math.max(lane.width, maxNodeW + padFor(lane) * 2, stageMinWidth);
|
|
10610
10796
|
widthOf.set(lane.id, newWidth);
|
|
10611
10797
|
deltaOf.set(lane.id, newWidth - lane.width);
|
|
10612
10798
|
}
|
|
@@ -10631,6 +10817,34 @@ function expandLaneGapsForEdgeLabels(lanes, nodes, edges, textMetrics = "proport
|
|
|
10631
10817
|
if (lanes.length < 2) return lanes;
|
|
10632
10818
|
const layoutedLanes = lanes.filter((l) => !(l.posX !== void 0 && l.posY !== void 0));
|
|
10633
10819
|
if (layoutedLanes.length < 2) return lanes;
|
|
10820
|
+
if (layoutedLanes.length === lanes.length && layoutedLanes.every((lane) => lane.stage !== void 0)) {
|
|
10821
|
+
const sortedStages = [...layoutedLanes].sort((a, b) => a.x - b.x);
|
|
10822
|
+
const stageIndexById = new Map(sortedStages.map((lane, index) => [lane.id, index]));
|
|
10823
|
+
const nodeLaneById = new Map(nodes.map((node) => [node.id, node.lane]));
|
|
10824
|
+
const requiredSurfaceGaps = new Array(sortedStages.length - 1).fill(STAGE_COLUMN_GAP);
|
|
10825
|
+
for (const edge of edges) {
|
|
10826
|
+
if (edge.routing !== "curve" || !edge.label && !edge.sub) continue;
|
|
10827
|
+
const fromIndex = stageIndexById.get(nodeLaneById.get(edge.from) ?? "");
|
|
10828
|
+
const toIndex = stageIndexById.get(nodeLaneById.get(edge.to) ?? "");
|
|
10829
|
+
if (fromIndex === void 0 || toIndex === void 0 || fromIndex === toIndex) continue;
|
|
10830
|
+
const lo = Math.min(fromIndex, toIndex);
|
|
10831
|
+
const hi = Math.max(fromIndex, toIndex);
|
|
10832
|
+
const labelWidth = computeLabelBoxW(edge.label, edge.sub, textMetrics);
|
|
10833
|
+
for (let pair = lo; pair < hi; pair++) {
|
|
10834
|
+
requiredSurfaceGaps[pair] = Math.max(requiredSurfaceGaps[pair], labelWidth);
|
|
10835
|
+
}
|
|
10836
|
+
}
|
|
10837
|
+
const shiftedXById2 = /* @__PURE__ */ new Map([[sortedStages[0].id, sortedStages[0].x]]);
|
|
10838
|
+
for (let index = 1; index < sortedStages.length; index++) {
|
|
10839
|
+
const previous = sortedStages[index - 1];
|
|
10840
|
+
const lane = sortedStages[index];
|
|
10841
|
+
const previousX = shiftedXById2.get(previous.id);
|
|
10842
|
+
const authoredGap = Math.max(0, lane.x - (previous.x + previous.width));
|
|
10843
|
+
const laneGap = Math.max(authoredGap, requiredSurfaceGaps[index - 1] - STAGE_COLUMN_GAP);
|
|
10844
|
+
shiftedXById2.set(lane.id, previousX + previous.width + laneGap);
|
|
10845
|
+
}
|
|
10846
|
+
return lanes.map((lane) => ({ ...lane, x: shiftedXById2.get(lane.id) ?? lane.x }));
|
|
10847
|
+
}
|
|
10634
10848
|
const nodeById = new Map(nodes.map((n) => [n.id, n]));
|
|
10635
10849
|
const sortedByX = [...layoutedLanes].sort((a, b) => a.x - b.x);
|
|
10636
10850
|
const laneIndexById = new Map(sortedByX.map((lane, i) => [lane.id, i]));
|
|
@@ -10702,7 +10916,7 @@ function recomputeContainedLanes(lanes, nodes) {
|
|
|
10702
10916
|
lifelineBottom = Math.max(lifelineBottom, bottom);
|
|
10703
10917
|
}
|
|
10704
10918
|
}
|
|
10705
|
-
|
|
10919
|
+
const contained = lanes.map((lane) => {
|
|
10706
10920
|
if (lane.lifeline) {
|
|
10707
10921
|
return {
|
|
10708
10922
|
...lane,
|
|
@@ -10720,6 +10934,7 @@ function recomputeContainedLanes(lanes, nodes) {
|
|
|
10720
10934
|
height: bottom - top + CONTAIN_PAD * 2 + LANE_LABEL_H
|
|
10721
10935
|
};
|
|
10722
10936
|
});
|
|
10937
|
+
return equalizeStageColumns(contained, nodes);
|
|
10723
10938
|
}
|
|
10724
10939
|
|
|
10725
10940
|
// src/layout/head-label.ts
|
|
@@ -10869,11 +11084,15 @@ function requiredStackGapForEdgeLabels(diag, allStacks) {
|
|
|
10869
11084
|
}
|
|
10870
11085
|
function layoutNodes(diag, lanes, textMetrics) {
|
|
10871
11086
|
const laneMap = new Map(lanes.map((l) => [l.id, l]));
|
|
11087
|
+
const metroDecisionIds = new Set(
|
|
11088
|
+
diag.edges.filter((edge) => edge.routing === "metro").flatMap((edge) => [edge.from, edge.to]).filter((id) => diag.nodes.some((node) => node.id === id && node.kind === "decision"))
|
|
11089
|
+
);
|
|
11090
|
+
const nodeSize = (node) => metroDecisionIds.has(node.id) ? { w: METRO_DECISION_WIDTH, h: METRO_DECISION_HEIGHT } : NODE_SIZE[node.kind];
|
|
10872
11091
|
const allStacks = Array.from(new Set(diag.nodes.map((n) => n.stack))).sort((a, b) => a - b);
|
|
10873
11092
|
const rowH = /* @__PURE__ */ new Map();
|
|
10874
11093
|
for (const stack of allStacks) {
|
|
10875
11094
|
const nodesAtStack = diag.nodes.filter((n) => n.stack === stack);
|
|
10876
|
-
const h = Math.max(...nodesAtStack.map((n) => \u7BB1\u306E\u9AD8\u30552(n,
|
|
11095
|
+
const h = Math.max(...nodesAtStack.map((n) => \u7BB1\u306E\u9AD8\u30552(n, nodeSize(n).h)));
|
|
10877
11096
|
rowH.set(stack, h);
|
|
10878
11097
|
}
|
|
10879
11098
|
const rowCy = /* @__PURE__ */ new Map();
|
|
@@ -10909,7 +11128,7 @@ function layoutNodes(diag, lanes, textMetrics) {
|
|
|
10909
11128
|
if (!lane) {
|
|
10910
11129
|
throw new Error(`cdl layout: node "${n.id}" \u306E lane "${n.lane}" \u304C\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u306A\u3044`);
|
|
10911
11130
|
}
|
|
10912
|
-
const size =
|
|
11131
|
+
const size = nodeSize(n);
|
|
10913
11132
|
if (n.posX !== void 0 && n.posY !== void 0) {
|
|
10914
11133
|
const w2 = n.posW ?? n.w ?? autoRowsWidth(n, size.w, textMetrics);
|
|
10915
11134
|
const h2 = n.posH ?? n.h ?? rowH.get(n.stack) ?? size.h;
|
|
@@ -11032,6 +11251,9 @@ function dropUnsafeLaneDx(dxByLane, nodes) {
|
|
|
11032
11251
|
function applyRowLevelNodeShifts(nodes, lanes, nodeShifts) {
|
|
11033
11252
|
const dyByStack = aggregateRowDy(nodes, nodeShifts);
|
|
11034
11253
|
const dxByLane = dropUnsafeLaneDx(aggregateLaneDx(nodes, nodeShifts), nodes);
|
|
11254
|
+
for (const lane of lanes) {
|
|
11255
|
+
if (lane.stage !== void 0) dxByLane.delete(lane.id);
|
|
11256
|
+
}
|
|
11035
11257
|
let moved = false;
|
|
11036
11258
|
const outNodes = nodes.map((n) => {
|
|
11037
11259
|
const dx = dxByLane.get(n.lane) ?? 0;
|
|
@@ -11151,7 +11373,15 @@ function layout(diag) {
|
|
|
11151
11373
|
);
|
|
11152
11374
|
}
|
|
11153
11375
|
}
|
|
11154
|
-
const
|
|
11376
|
+
const contentViewBox = computeViewBox(
|
|
11377
|
+
containedLanesFinal,
|
|
11378
|
+
nodesFinal,
|
|
11379
|
+
edges,
|
|
11380
|
+
bboxes,
|
|
11381
|
+
diag.viewport
|
|
11382
|
+
);
|
|
11383
|
+
const legendLayout = diag.legend?.length ? layoutLegend(diag.legend, contentViewBox, textMetrics, nodesFinal) : void 0;
|
|
11384
|
+
const viewBox = legendLayout?.viewBox ?? contentViewBox;
|
|
11155
11385
|
return {
|
|
11156
11386
|
id: diag.id,
|
|
11157
11387
|
topic: diag.topic,
|
|
@@ -11178,6 +11408,7 @@ function layout(diag) {
|
|
|
11178
11408
|
...textMetrics === "monospace" ? { textMetrics: "monospace" } : {},
|
|
11179
11409
|
// 種類も配色と同じく空の目印を出さない。 遮断をここに揃えると手書きの図にも効く
|
|
11180
11410
|
...diag.type ? { type: diag.type } : {},
|
|
11411
|
+
...legendLayout ? { legend: legendLayout.legend } : {},
|
|
11181
11412
|
bboxes,
|
|
11182
11413
|
collisions,
|
|
11183
11414
|
nearCollisions,
|
|
@@ -11366,6 +11597,11 @@ function validate(diag) {
|
|
|
11366
11597
|
\u2192 \u4FEE\u6B63\u4F8B: .lane("${n.lane}", { x: 0, width: 400 }) \u3092 node \u5BA3\u8A00\u524D\u306B\u8FFD\u52A0`
|
|
11367
11598
|
);
|
|
11368
11599
|
}
|
|
11600
|
+
if (n.leaderTo !== void 0 && !nodeIds.has(n.leaderTo)) {
|
|
11601
|
+
errors.push(
|
|
11602
|
+
`[cdl] unknown-ref: node "${n.id}" \u306E leaderTo "${n.leaderTo}" \u304C node \u306B\u5B58\u5728\u3057\u307E\u305B\u3093${suggest(n.leaderTo, nodeIds, "node")}`
|
|
11603
|
+
);
|
|
11604
|
+
}
|
|
11369
11605
|
}
|
|
11370
11606
|
for (const e of diag.edges) {
|
|
11371
11607
|
if (!nodeIds.has(e.from)) {
|
|
@@ -11984,6 +12220,10 @@ function uniformLifelineEndY(lanes, nodes, starts = lifelineStartYs(nodes)) {
|
|
|
11984
12220
|
|
|
11985
12221
|
// src/render/edge-head.ts
|
|
11986
12222
|
var EDGE_HEAD_MUTED_MARKER_ID = "cdl-arrow-muted";
|
|
12223
|
+
var METRO_RETURN_ARROW_D = "M 21 0 L 4 9.5 L 4 -9.5 Z";
|
|
12224
|
+
function metroReturnArrowMarkerId(tone) {
|
|
12225
|
+
return `cdl-metro-return-arrow-${tone}`;
|
|
12226
|
+
}
|
|
11987
12227
|
var EDGE_HEAD_SHAPE = {
|
|
11988
12228
|
// 何も描かない端。 marker 自体を出さないので `d` は読まれない
|
|
11989
12229
|
none: { d: "", w: 10, h: 10, refX: 0, filled: false },
|
|
@@ -12038,6 +12278,7 @@ function \u7B49\u5E45\u306E\u5B57(text, fontSize) {
|
|
|
12038
12278
|
});
|
|
12039
12279
|
return out;
|
|
12040
12280
|
}
|
|
12281
|
+
var METRO_PENDING_ATTRIBUTE = "data-cdl-pending";
|
|
12041
12282
|
function defaultEdgeWidth(active) {
|
|
12042
12283
|
return active ? 2.5 : 1.25;
|
|
12043
12284
|
}
|
|
@@ -12056,12 +12297,14 @@ function CdlEdgeView({
|
|
|
12056
12297
|
drawing,
|
|
12057
12298
|
progress,
|
|
12058
12299
|
stateValues,
|
|
12059
|
-
flowing = false
|
|
12300
|
+
flowing = false,
|
|
12301
|
+
pending = false
|
|
12060
12302
|
}) {
|
|
12061
12303
|
const color = edgeColor(edge);
|
|
12062
|
-
const marker = edgeHeadMarkerName(edge.tone, edge.head, !active, edge.headFill);
|
|
12063
|
-
const tailMarker = edge.tailHead === void 0 ? void 0 : edgeHeadMarkerName(edge.tone, edge.tailHead, !active, edge.tailHeadFill);
|
|
12064
12304
|
const style = edge.style ?? "solid";
|
|
12305
|
+
const isMetroReturn = edge.metroReturn === true;
|
|
12306
|
+
const marker = isMetroReturn ? metroReturnArrowMarkerId(edge.tone) : edgeHeadMarkerName(edge.tone, edge.head, !active, edge.headFill);
|
|
12307
|
+
const tailMarker = edge.tailHead === void 0 ? void 0 : edgeHeadMarkerName(edge.tone, edge.tailHead, !active, edge.tailHeadFill);
|
|
12065
12308
|
const isDotted = style === "dotted-flow";
|
|
12066
12309
|
const isPassThrough = isDotted && Boolean(edge.dThrough);
|
|
12067
12310
|
const lineDotsD = isDotted ? shrinkPathEnd(edge.d, 12) : edge.d;
|
|
@@ -12071,6 +12314,7 @@ function CdlEdgeView({
|
|
|
12071
12314
|
return /* @__PURE__ */ jsxs(
|
|
12072
12315
|
"g",
|
|
12073
12316
|
{
|
|
12317
|
+
...pending ? { [METRO_PENDING_ATTRIBUTE]: "true" } : {},
|
|
12074
12318
|
"data-cdl-edge": edge.id,
|
|
12075
12319
|
"data-cdl-routing": edge.routing === "metro" ? "metro" : void 0,
|
|
12076
12320
|
"data-cdl-from": edge.from,
|
|
@@ -12096,11 +12340,12 @@ function CdlEdgeView({
|
|
|
12096
12340
|
fill: "none",
|
|
12097
12341
|
stroke: color,
|
|
12098
12342
|
strokeOpacity: active ? 0.95 : 0.9,
|
|
12099
|
-
strokeWidth: active ? 5 : 4,
|
|
12343
|
+
strokeWidth: edge.routing === "metro" ? METRO_LINE_WIDTH : active ? 5 : 4,
|
|
12100
12344
|
strokeDasharray: "0 18",
|
|
12101
12345
|
strokeLinecap: "round",
|
|
12102
12346
|
style: {
|
|
12103
|
-
transition: "stroke 280ms ease, stroke-opacity 280ms ease, stroke-width 280ms ease"
|
|
12347
|
+
transition: "stroke 280ms ease, stroke-opacity 280ms ease, stroke-width 280ms ease",
|
|
12348
|
+
strokeWidth: edge.routing === "metro" ? METRO_LINE_WIDTH_CSS : void 0
|
|
12104
12349
|
}
|
|
12105
12350
|
}
|
|
12106
12351
|
),
|
|
@@ -12155,7 +12400,9 @@ function SolidEdgePath({
|
|
|
12155
12400
|
const boundWidth = edge.widthBind && stateValues ? resolveNumericAttr(edge.widthBind, stateValues, defaultWidth) : defaultWidth;
|
|
12156
12401
|
const boundStroke = edge.strokeBind && stateValues ? interpolate(edge.strokeBind, stateValues) : color;
|
|
12157
12402
|
const boundDashOffset = edge.dashOffsetBind && stateValues ? resolveNumericAttr(edge.dashOffsetBind, stateValues, 0) : void 0;
|
|
12158
|
-
const
|
|
12403
|
+
const strokeWidth = edge.routing === "metro" && edge.widthBind === void 0 ? edge.metroReturn ? 6 : METRO_LINE_WIDTH : boundWidth;
|
|
12404
|
+
const strokeWidthCss = edge.routing === "metro" && !edge.metroReturn ? edge.widthBind === void 0 ? METRO_LINE_WIDTH_CSS : `var(--cdl-metro-line-width, ${strokeWidth}px)` : void 0;
|
|
12405
|
+
const dashArray = dashed ? edge.metroReturn ? "0 9.6" : "10 8" : active ? boundDashOffset !== void 0 ? "8 6" : void 0 : "4 5";
|
|
12159
12406
|
return /* @__PURE__ */ jsx(
|
|
12160
12407
|
"path",
|
|
12161
12408
|
{
|
|
@@ -12164,14 +12411,15 @@ function SolidEdgePath({
|
|
|
12164
12411
|
fill: "none",
|
|
12165
12412
|
stroke: boundStroke,
|
|
12166
12413
|
strokeOpacity: active ? 0.95 : 0.9,
|
|
12167
|
-
strokeWidth
|
|
12414
|
+
strokeWidth,
|
|
12168
12415
|
strokeDasharray: dashArray,
|
|
12169
12416
|
strokeDashoffset: boundDashOffset,
|
|
12170
12417
|
strokeLinecap: "round",
|
|
12171
12418
|
markerEnd: marker === void 0 ? void 0 : `url(#${marker})`,
|
|
12172
12419
|
markerStart: tailMarker === void 0 ? void 0 : `url(#${tailMarker})`,
|
|
12173
12420
|
style: {
|
|
12174
|
-
transition: "stroke 280ms ease, stroke-opacity 280ms ease, stroke-width 280ms ease"
|
|
12421
|
+
transition: "stroke 280ms ease, stroke-opacity 280ms ease, stroke-width 280ms ease",
|
|
12422
|
+
strokeWidth: strokeWidthCss
|
|
12175
12423
|
}
|
|
12176
12424
|
}
|
|
12177
12425
|
);
|
|
@@ -12468,7 +12716,11 @@ function \u5272\u308B\u5019\u88DC(text) {
|
|
|
12468
12716
|
function \u5165\u3063\u3066\u3044\u308B([\u5DE6, \u53F3]) {
|
|
12469
12717
|
return \u5DE6 !== "" && \u53F3 !== "";
|
|
12470
12718
|
}
|
|
12471
|
-
function CardNode({
|
|
12719
|
+
function CardNode({
|
|
12720
|
+
node,
|
|
12721
|
+
active,
|
|
12722
|
+
compactTitleInset
|
|
12723
|
+
}) {
|
|
12472
12724
|
const accent = nodeAccent(node, "var(--cdl-tone-accent, #2d6a8f)");
|
|
12473
12725
|
const x = node.cx - node.w / 2;
|
|
12474
12726
|
const y = node.cy - node.h / 2;
|
|
@@ -12486,12 +12738,12 @@ function CardNode({ node, active }) {
|
|
|
12486
12738
|
});
|
|
12487
12739
|
const \u305A\u3089\u3057 = \u7E70\u308A\u4E0A\u3052 - \u4F59\u308A;
|
|
12488
12740
|
const titleY = compact ? \u5C0F\u578B\u306B\u547C\u3073\u540D ? node.h / 2 - 2 : node.h / 2 + 8 : 86 - \u305A\u3089\u3057;
|
|
12489
|
-
const titleX = compact ? node.w / 2 : 26;
|
|
12490
|
-
const paddingX = compact ?
|
|
12741
|
+
const titleX = compact ? compactTitleInset ?? node.w / 2 : 26;
|
|
12742
|
+
const paddingX = compact ? (compactTitleInset ?? 8) * 2 : 52;
|
|
12491
12743
|
const availableW = node.w - paddingX;
|
|
12492
12744
|
const initialTitleSize = compact ? 20 : 24;
|
|
12493
12745
|
const titleSize = fitTextSize(node.title, availableW, initialTitleSize, 11);
|
|
12494
|
-
const textAnchor = compact ? "middle" : "start";
|
|
12746
|
+
const textAnchor = compact && compactTitleInset === void 0 ? "middle" : "start";
|
|
12495
12747
|
const subtitleY = 124 - \u305A\u3089\u3057;
|
|
12496
12748
|
const \u6700\u5927\u306E\u884C\u9001\u308A = SUBTITLE_SIZE * \u884C\u9001\u308A\u306E\u500D\u7387;
|
|
12497
12749
|
const \u4E8C\u884C\u304C\u5165\u308B = !compact && subtitleY - \u6700\u5927\u306E\u884C\u9001\u308A / 2 - SUBTITLE_SIZE * ASCENT > titleY + titleSize * DESCENT && subtitleY + \u6700\u5927\u306E\u884C\u9001\u308A / 2 + SUBTITLE_SIZE * DESCENT <= node.h - 4;
|
|
@@ -13251,7 +13503,9 @@ function GenericNode({
|
|
|
13251
13503
|
value,
|
|
13252
13504
|
stateValues,
|
|
13253
13505
|
\u5024\u306E\u540D\u524D,
|
|
13254
|
-
textMetrics = "proportional"
|
|
13506
|
+
textMetrics = "proportional",
|
|
13507
|
+
showKindIcon = true,
|
|
13508
|
+
metroDecision = false
|
|
13255
13509
|
}) {
|
|
13256
13510
|
const base = STYLES[node.kind] ?? FALLBACK;
|
|
13257
13511
|
const toned = toneColor3(node.tone);
|
|
@@ -13282,14 +13536,14 @@ function GenericNode({
|
|
|
13282
13536
|
if (shape === "diamond") {
|
|
13283
13537
|
const cx = w / 2;
|
|
13284
13538
|
const cy = h / 2;
|
|
13285
|
-
const pad = 8;
|
|
13539
|
+
const pad = metroDecision ? 0 : 8;
|
|
13286
13540
|
return /* @__PURE__ */ jsx(
|
|
13287
13541
|
"path",
|
|
13288
13542
|
{
|
|
13289
13543
|
d: `M ${cx} ${pad} L ${w - pad} ${cy} L ${cx} ${h - pad} L ${pad} ${cy} Z`,
|
|
13290
13544
|
fill: "var(--cdl-node-fill, #ffffff)",
|
|
13291
13545
|
stroke: active ? style.accent : "var(--cdl-divider, #d4d4d8)",
|
|
13292
|
-
strokeWidth: active ? 3 : 1.25
|
|
13546
|
+
strokeWidth: metroDecision ? 1.5 : active ? 3 : 1.25
|
|
13293
13547
|
}
|
|
13294
13548
|
);
|
|
13295
13549
|
}
|
|
@@ -13353,11 +13607,11 @@ function GenericNode({
|
|
|
13353
13607
|
const \u305A\u3089\u3057 = \u7E70\u308A\u4E0A\u3052 - \u4F59\u308A;
|
|
13354
13608
|
const \u7D75\u306E\u82AF = centered && STYLES[node.kind]?.shape === "cloud" ? h * CLOUD_ART_CENTER_RISE : 0;
|
|
13355
13609
|
const eyebrowY = centered ? h / 2 - 26 - \u7D75\u306E\u82AF : 32 + cylinderShift + \u4F59\u308A;
|
|
13356
|
-
const titleY = genericTitleBaselineY(node.kind, h, hasRows) - \u305A\u3089\u3057 - \u7D75\u306E\u82AF;
|
|
13610
|
+
const titleY = metroDecision ? h / 2 + 9 : genericTitleBaselineY(node.kind, h, hasRows) - \u305A\u3089\u3057 - \u7D75\u306E\u82AF;
|
|
13357
13611
|
const subtitleY = centered ? h / 2 + 28 - \u7D75\u306E\u82AF : 96 + cylinderShift - \u305A\u3089\u3057;
|
|
13358
13612
|
const iconX = centered ? w / 2 + 40 : w - 48;
|
|
13359
13613
|
const iconY = centered ? h / 2 - 44 - \u7D75\u306E\u82AF : 18 + cylinderShift;
|
|
13360
|
-
const dominantBaseline = centered ? "middle" : void 0;
|
|
13614
|
+
const dominantBaseline = centered && !metroDecision ? "middle" : void 0;
|
|
13361
13615
|
return /* @__PURE__ */ jsxs(
|
|
13362
13616
|
"g",
|
|
13363
13617
|
{
|
|
@@ -13366,12 +13620,12 @@ function GenericNode({
|
|
|
13366
13620
|
"data-cdl-look": style.look,
|
|
13367
13621
|
children: [
|
|
13368
13622
|
shapeEl,
|
|
13369
|
-
/* @__PURE__ */ jsxs("g", { transform: `translate(${iconX} ${iconY}) scale(1)`, "data-cdl-role": "node-kind-icon", children: [
|
|
13623
|
+
showKindIcon && /* @__PURE__ */ jsxs("g", { transform: `translate(${iconX} ${iconY}) scale(1)`, "data-cdl-role": "node-kind-icon", children: [
|
|
13370
13624
|
/* @__PURE__ */ jsx("rect", { width: 24, height: 24, fill: "transparent" }),
|
|
13371
13625
|
/* @__PURE__ */ jsx("path", { d: style.icon, fill: style.eyebrowColor, opacity: 0.7, transform: "scale(1)" })
|
|
13372
13626
|
] }),
|
|
13373
13627
|
node.eyebrow && /* @__PURE__ */ jsx("text", { x: textX, y: eyebrowY, fontSize: 17, fontWeight: 700, letterSpacing: 1.5, fill: paint.onSolid ? "var(--cdl-node-fill, #ffffff)" : style.eyebrowColor, textAnchor, dominantBaseline, children: node.eyebrow }),
|
|
13374
|
-
/* @__PURE__ */ jsx("text", { "data-cdl-role": "node-label", x: textX, y: titleY, fontSize: 20, fontWeight: 700, fill: paint.onSolid ? "var(--cdl-node-fill, #ffffff)" : "var(--cdl-text, #1a1f2a)", textAnchor, dominantBaseline, style: node.kind === "function" || node.kind === "api" ? { fontFamily: "'JetBrains Mono', monospace" } : void 0, children: node.kind === "function" || node.kind === "api" ? \u7B49\u5E45\u306E\u5B57(node.title, 20) : node.title }),
|
|
13628
|
+
/* @__PURE__ */ jsx("text", { "data-cdl-role": "node-label", x: textX, y: titleY, fontSize: metroDecision ? 26 : 20, fontWeight: 700, fill: paint.onSolid ? "var(--cdl-node-fill, #ffffff)" : "var(--cdl-text, #1a1f2a)", textAnchor, dominantBaseline, style: node.kind === "function" || node.kind === "api" ? { fontFamily: "'JetBrains Mono', monospace" } : void 0, children: node.kind === "function" || node.kind === "api" ? \u7B49\u5E45\u306E\u5B57(node.title, 20) : node.title }),
|
|
13375
13629
|
node.subtitle && /* @__PURE__ */ jsx("text", { x: textX, y: subtitleY, fontSize: 17, fill: paint.onSolid ? "var(--cdl-node-fill, #ffffff)" : "var(--cdl-text-dim, #5a6270)", textAnchor, dominantBaseline, style: { fontFamily: "'JetBrains Mono', monospace" }, children: \u7B49\u5E45\u306E\u5B57(node.subtitle, 17) }),
|
|
13376
13630
|
resolvedValue && /* @__PURE__ */ jsx(
|
|
13377
13631
|
"text",
|
|
@@ -13420,50 +13674,176 @@ function GenericNode({
|
|
|
13420
13674
|
var MARK_INNER_RATIO = 0.56;
|
|
13421
13675
|
var RING_WIDTH_ACTIVE = 6;
|
|
13422
13676
|
var RING_WIDTH_IDLE = 4;
|
|
13677
|
+
var METRO_START_RADIUS = 17;
|
|
13678
|
+
var METRO_END_RADIUS = 19;
|
|
13679
|
+
var METRO_END_RING_WIDTH = 3.5;
|
|
13680
|
+
var METRO_END_INNER_RADIUS = 10;
|
|
13423
13681
|
var MARK_DEFAULT = "var(--cdl-tone-accent, #2d6a8f)";
|
|
13424
13682
|
function markRadius(node) {
|
|
13425
13683
|
return Math.min(node.w, node.h) / 2;
|
|
13426
13684
|
}
|
|
13427
|
-
function MarkStartNode({
|
|
13685
|
+
function MarkStartNode({
|
|
13686
|
+
node,
|
|
13687
|
+
metro = false
|
|
13688
|
+
}) {
|
|
13428
13689
|
const \u8272 = nodeAccent(node, MARK_DEFAULT);
|
|
13429
|
-
return /* @__PURE__ */ jsx(
|
|
13430
|
-
"
|
|
13690
|
+
return /* @__PURE__ */ jsx(
|
|
13691
|
+
"g",
|
|
13431
13692
|
{
|
|
13432
|
-
"data-cdl-role": "
|
|
13433
|
-
|
|
13434
|
-
|
|
13435
|
-
|
|
13436
|
-
|
|
13437
|
-
|
|
13693
|
+
"data-cdl-role": metro ? "mark-start" : void 0,
|
|
13694
|
+
transform: `translate(${node.cx - node.w / 2} ${node.cy - node.h / 2})`,
|
|
13695
|
+
children: /* @__PURE__ */ jsx(
|
|
13696
|
+
"circle",
|
|
13697
|
+
{
|
|
13698
|
+
"data-cdl-role": "node-body",
|
|
13699
|
+
"data-cdl-mark": "start",
|
|
13700
|
+
cx: node.w / 2,
|
|
13701
|
+
cy: node.h / 2,
|
|
13702
|
+
r: metro ? METRO_START_RADIUS : markRadius(node),
|
|
13703
|
+
fill: \u8272
|
|
13704
|
+
}
|
|
13705
|
+
)
|
|
13438
13706
|
}
|
|
13439
|
-
)
|
|
13707
|
+
);
|
|
13440
13708
|
}
|
|
13441
|
-
function MarkEndNode({
|
|
13709
|
+
function MarkEndNode({
|
|
13710
|
+
node,
|
|
13711
|
+
active,
|
|
13712
|
+
metro = false
|
|
13713
|
+
}) {
|
|
13442
13714
|
const \u8272 = nodeAccent(node, MARK_DEFAULT);
|
|
13443
|
-
const r = markRadius(node);
|
|
13444
|
-
const \u8F2A\u306E\u592A\u3055 = active ? RING_WIDTH_ACTIVE : RING_WIDTH_IDLE;
|
|
13445
|
-
return /* @__PURE__ */ jsxs(
|
|
13715
|
+
const r = metro ? METRO_END_RADIUS : markRadius(node);
|
|
13716
|
+
const \u8F2A\u306E\u592A\u3055 = metro ? METRO_END_RING_WIDTH : active ? RING_WIDTH_ACTIVE : RING_WIDTH_IDLE;
|
|
13717
|
+
return /* @__PURE__ */ jsxs(
|
|
13718
|
+
"g",
|
|
13719
|
+
{
|
|
13720
|
+
"data-cdl-role": metro ? "mark-end" : void 0,
|
|
13721
|
+
transform: `translate(${node.cx - node.w / 2} ${node.cy - node.h / 2})`,
|
|
13722
|
+
children: [
|
|
13723
|
+
/* @__PURE__ */ jsx(
|
|
13724
|
+
"circle",
|
|
13725
|
+
{
|
|
13726
|
+
"data-cdl-role": "node-body",
|
|
13727
|
+
"data-cdl-mark": "end",
|
|
13728
|
+
cx: node.w / 2,
|
|
13729
|
+
cy: node.h / 2,
|
|
13730
|
+
r: metro ? r : Math.max(0, r - \u8F2A\u306E\u592A\u3055 / 2),
|
|
13731
|
+
fill: "var(--cdl-node-fill, #ffffff)",
|
|
13732
|
+
stroke: \u8272,
|
|
13733
|
+
strokeWidth: \u8F2A\u306E\u592A\u3055
|
|
13734
|
+
}
|
|
13735
|
+
),
|
|
13736
|
+
/* @__PURE__ */ jsx(
|
|
13737
|
+
"circle",
|
|
13738
|
+
{
|
|
13739
|
+
"data-cdl-role": "node-inner",
|
|
13740
|
+
cx: node.w / 2,
|
|
13741
|
+
cy: node.h / 2,
|
|
13742
|
+
r: metro ? METRO_END_INNER_RADIUS : Math.max(0, r * MARK_INNER_RATIO),
|
|
13743
|
+
fill: \u8272
|
|
13744
|
+
}
|
|
13745
|
+
)
|
|
13746
|
+
]
|
|
13747
|
+
}
|
|
13748
|
+
);
|
|
13749
|
+
}
|
|
13750
|
+
var METRO_STATION_RADIUS = 16;
|
|
13751
|
+
var METRO_STATION_STROKE_WIDTH = 6;
|
|
13752
|
+
var METRO_STATION_RADIUS_CSS = `var(--cdl-metro-station-radius, ${METRO_STATION_RADIUS}px)`;
|
|
13753
|
+
var METRO_STATION_STROKE_WIDTH_CSS = `var(--cdl-metro-station-stroke-width, ${METRO_STATION_STROKE_WIDTH}px)`;
|
|
13754
|
+
var STATION_DEFAULT = "var(--cdl-tone-accent, #2d6a8f)";
|
|
13755
|
+
var STATION_NAME_FONT_SIZE = 25;
|
|
13756
|
+
var STATION_NAME_GAP = 18;
|
|
13757
|
+
var STATION_NAME_RIGHT_GAP = 32;
|
|
13758
|
+
var STATION_NAME_RIGHT_BASELINE = 9;
|
|
13759
|
+
var STATION_SUBTITLE_FONT_SIZE = 18;
|
|
13760
|
+
var STATION_SUBTITLE_GAP = 22;
|
|
13761
|
+
function StationNode({
|
|
13762
|
+
node,
|
|
13763
|
+
nameRight = false
|
|
13764
|
+
}) {
|
|
13765
|
+
const name = node.title.trim();
|
|
13766
|
+
const subtitle = node.subtitle?.trim() ?? "";
|
|
13767
|
+
return /* @__PURE__ */ jsxs("g", { children: [
|
|
13446
13768
|
/* @__PURE__ */ jsx(
|
|
13447
13769
|
"circle",
|
|
13448
13770
|
{
|
|
13449
13771
|
"data-cdl-role": "node-body",
|
|
13450
|
-
"data-cdl-mark": "
|
|
13451
|
-
cx: node.
|
|
13452
|
-
cy: node.
|
|
13453
|
-
r:
|
|
13772
|
+
"data-cdl-mark": "station",
|
|
13773
|
+
cx: node.cx,
|
|
13774
|
+
cy: node.cy,
|
|
13775
|
+
r: METRO_STATION_RADIUS,
|
|
13454
13776
|
fill: "var(--cdl-node-fill, #ffffff)",
|
|
13455
|
-
stroke:
|
|
13456
|
-
strokeWidth:
|
|
13777
|
+
stroke: nodeAccent(node, STATION_DEFAULT),
|
|
13778
|
+
strokeWidth: METRO_STATION_STROKE_WIDTH,
|
|
13779
|
+
style: { r: METRO_STATION_RADIUS_CSS, strokeWidth: METRO_STATION_STROKE_WIDTH_CSS }
|
|
13780
|
+
}
|
|
13781
|
+
),
|
|
13782
|
+
name !== "" && /* @__PURE__ */ jsx(
|
|
13783
|
+
"text",
|
|
13784
|
+
{
|
|
13785
|
+
"data-cdl-role": "shape-name",
|
|
13786
|
+
x: nameRight ? node.cx + STATION_NAME_RIGHT_GAP : node.cx,
|
|
13787
|
+
y: nameRight ? node.cy + STATION_NAME_RIGHT_BASELINE : node.cy - METRO_STATION_RADIUS - STATION_NAME_GAP,
|
|
13788
|
+
textAnchor: nameRight ? "start" : "middle",
|
|
13789
|
+
fontSize: STATION_NAME_FONT_SIZE,
|
|
13790
|
+
fontWeight: 700,
|
|
13791
|
+
fill: "var(--cdl-text, #23201b)",
|
|
13792
|
+
stroke: "var(--cdl-node-fill, #ffffff)",
|
|
13793
|
+
strokeWidth: 8,
|
|
13794
|
+
strokeLinejoin: "round",
|
|
13795
|
+
paintOrder: "stroke",
|
|
13796
|
+
children: name
|
|
13457
13797
|
}
|
|
13458
13798
|
),
|
|
13799
|
+
subtitle !== "" && /* @__PURE__ */ jsx(
|
|
13800
|
+
"text",
|
|
13801
|
+
{
|
|
13802
|
+
"data-cdl-role": "shape-value",
|
|
13803
|
+
x: node.cx,
|
|
13804
|
+
y: node.cy + METRO_STATION_RADIUS + STATION_SUBTITLE_GAP,
|
|
13805
|
+
textAnchor: "middle",
|
|
13806
|
+
fontSize: STATION_SUBTITLE_FONT_SIZE,
|
|
13807
|
+
fill: "var(--cdl-text-dim, #5a6270)",
|
|
13808
|
+
children: subtitle
|
|
13809
|
+
}
|
|
13810
|
+
)
|
|
13811
|
+
] });
|
|
13812
|
+
}
|
|
13813
|
+
function TimelineNumberNode({ node }) {
|
|
13814
|
+
const radius = Math.max(0, Math.min(node.w, node.h) / 2 - TIMELINE_NUMBER_STROKE / 2);
|
|
13815
|
+
const fontSize = fitTextSize(
|
|
13816
|
+
node.title,
|
|
13817
|
+
titleUsableWidth(node.kind, node.w, node.h),
|
|
13818
|
+
18,
|
|
13819
|
+
MIN_TEXT_SIZE
|
|
13820
|
+
);
|
|
13821
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13459
13822
|
/* @__PURE__ */ jsx(
|
|
13460
13823
|
"circle",
|
|
13461
13824
|
{
|
|
13462
|
-
"data-cdl-role": "node-
|
|
13463
|
-
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
|
|
13825
|
+
"data-cdl-role": "node-body",
|
|
13826
|
+
"data-cdl-mark": "timeline-number",
|
|
13827
|
+
cx: node.cx,
|
|
13828
|
+
cy: node.cy,
|
|
13829
|
+
r: radius,
|
|
13830
|
+
fill: "var(--cdl-node-fill, #ffffff)",
|
|
13831
|
+
stroke: nodeAccent(node, STATION_DEFAULT),
|
|
13832
|
+
strokeWidth: TIMELINE_NUMBER_STROKE
|
|
13833
|
+
}
|
|
13834
|
+
),
|
|
13835
|
+
/* @__PURE__ */ jsx(
|
|
13836
|
+
"text",
|
|
13837
|
+
{
|
|
13838
|
+
"data-cdl-role": "node-label",
|
|
13839
|
+
x: node.cx,
|
|
13840
|
+
y: node.cy,
|
|
13841
|
+
textAnchor: "middle",
|
|
13842
|
+
dominantBaseline: "central",
|
|
13843
|
+
fontSize,
|
|
13844
|
+
fontWeight: 700,
|
|
13845
|
+
fill: "var(--cdl-text, #1a1f2a)",
|
|
13846
|
+
children: node.title
|
|
13467
13847
|
}
|
|
13468
13848
|
)
|
|
13469
13849
|
] });
|
|
@@ -13795,27 +14175,6 @@ function interpolateColor(template, stateValues, fallback) {
|
|
|
13795
14175
|
if (!template) return fallback;
|
|
13796
14176
|
return interpolate(template, stateValues);
|
|
13797
14177
|
}
|
|
13798
|
-
var STATION_STROKE_ACTIVE = 4;
|
|
13799
|
-
var STATION_STROKE_IDLE = 3;
|
|
13800
|
-
var STATION_DEFAULT = "var(--cdl-tone-accent, #2d6a8f)";
|
|
13801
|
-
function StationNode({ node, active }) {
|
|
13802
|
-
const strokeWidth = active ? STATION_STROKE_ACTIVE : STATION_STROKE_IDLE;
|
|
13803
|
-
const radius = Math.max(0, Math.min(node.w, node.h) / 2 - strokeWidth / 2);
|
|
13804
|
-
const \u5F62 = /* @__PURE__ */ jsx(
|
|
13805
|
-
"circle",
|
|
13806
|
-
{
|
|
13807
|
-
"data-cdl-role": "node-body",
|
|
13808
|
-
"data-cdl-mark": "station",
|
|
13809
|
-
cx: node.cx,
|
|
13810
|
-
cy: node.cy,
|
|
13811
|
-
r: radius,
|
|
13812
|
-
fill: "var(--cdl-node-fill, #ffffff)",
|
|
13813
|
-
stroke: nodeAccent(node, STATION_DEFAULT),
|
|
13814
|
-
strokeWidth
|
|
13815
|
-
}
|
|
13816
|
-
);
|
|
13817
|
-
return renderShapeWithOutsideLabels(\u5F62, node, "middle");
|
|
13818
|
-
}
|
|
13819
14178
|
|
|
13820
14179
|
// src/kinds/label-stack.ts
|
|
13821
14180
|
function \u540D\u672D\u306E\u6BB5\u3092\u307B\u3069\u304F(\u771F\u306Ey, \u9593\u9694, \u4E0A\u9650, \u4E0B\u9650) {
|
|
@@ -20977,10 +21336,14 @@ function CdlNodeView({
|
|
|
20977
21336
|
stateValues,
|
|
20978
21337
|
currentPhaseId,
|
|
20979
21338
|
chartLineScale,
|
|
21339
|
+
compactTitleInset,
|
|
20980
21340
|
\u95A2\u4FC2\u306E\u53D7\u3051\u53E3,
|
|
20981
21341
|
lang,
|
|
20982
21342
|
textMetrics,
|
|
20983
|
-
\u5024\u306E\u540D\u524D
|
|
21343
|
+
\u5024\u306E\u540D\u524D,
|
|
21344
|
+
metroDiagram = false,
|
|
21345
|
+
metroDecision = false,
|
|
21346
|
+
stationNameRight = false
|
|
20984
21347
|
}) {
|
|
20985
21348
|
const value = node.value ? interpolate(node.value, stateValues, \u5024\u306E\u540D\u524D) : void 0;
|
|
20986
21349
|
const rows = (node.rows ?? []).map((r) => interpolate(r, stateValues, \u5024\u306E\u540D\u524D));
|
|
@@ -21021,7 +21384,7 @@ function CdlNodeView({
|
|
|
21021
21384
|
case "event":
|
|
21022
21385
|
return /* @__PURE__ */ jsx(EventNode, { node: resolvedNode, active, progress });
|
|
21023
21386
|
case "card":
|
|
21024
|
-
return /* @__PURE__ */ jsx(CardNode, { node: resolvedNode, active });
|
|
21387
|
+
return /* @__PURE__ */ jsx(CardNode, { node: resolvedNode, active, compactTitleInset });
|
|
21025
21388
|
// 時系列のやり取り (#578)。 1 つの箱が図を丸ごと描く = 縦が時間で、参加者は箱を持たない
|
|
21026
21389
|
case "sequence-board":
|
|
21027
21390
|
return /* @__PURE__ */ jsx(
|
|
@@ -21308,11 +21671,13 @@ function CdlNodeView({
|
|
|
21308
21671
|
case "shape-customer-service":
|
|
21309
21672
|
return /* @__PURE__ */ jsx(ShapeCustomerServiceNode, { node: resolvedNode, active });
|
|
21310
21673
|
case "mark-start":
|
|
21311
|
-
return /* @__PURE__ */ jsx(MarkStartNode, { node: resolvedNode, active });
|
|
21674
|
+
return /* @__PURE__ */ jsx(MarkStartNode, { node: resolvedNode, active, metro: metroDiagram });
|
|
21312
21675
|
case "mark-end":
|
|
21313
|
-
return /* @__PURE__ */ jsx(MarkEndNode, { node: resolvedNode, active });
|
|
21676
|
+
return /* @__PURE__ */ jsx(MarkEndNode, { node: resolvedNode, active, metro: metroDiagram });
|
|
21314
21677
|
case "station":
|
|
21315
|
-
return /* @__PURE__ */ jsx(StationNode, { node: resolvedNode, active });
|
|
21678
|
+
return /* @__PURE__ */ jsx(StationNode, { node: resolvedNode, active, nameRight: stationNameRight });
|
|
21679
|
+
case "timeline-number":
|
|
21680
|
+
return /* @__PURE__ */ jsx(TimelineNumberNode, { node: resolvedNode });
|
|
21316
21681
|
default:
|
|
21317
21682
|
return /* @__PURE__ */ jsx(
|
|
21318
21683
|
GenericNode,
|
|
@@ -21322,7 +21687,9 @@ function CdlNodeView({
|
|
|
21322
21687
|
value: node.value,
|
|
21323
21688
|
stateValues,
|
|
21324
21689
|
\u5024\u306E\u540D\u524D,
|
|
21325
|
-
textMetrics
|
|
21690
|
+
textMetrics,
|
|
21691
|
+
showKindIcon: !(metroDiagram && node.kind === "decision"),
|
|
21692
|
+
metroDecision
|
|
21326
21693
|
}
|
|
21327
21694
|
);
|
|
21328
21695
|
}
|
|
@@ -21436,6 +21803,112 @@ function \u7BB1\u306E\u4E0A\u306E\u8A9E(node, textMetrics = "proportional") {
|
|
|
21436
21803
|
)
|
|
21437
21804
|
] });
|
|
21438
21805
|
}
|
|
21806
|
+
var ink = "var(--cdl-text-accent, #143a52)";
|
|
21807
|
+
var paper = "var(--cdl-stage-bg, #f8fafc)";
|
|
21808
|
+
var LEGEND_MARK_RENDERERS = {
|
|
21809
|
+
diamond: () => /* @__PURE__ */ jsx("path", { d: "M 23 -26 L 46 -8 L 23 10 L 0 -8 Z", fill: "none", stroke: ink, strokeWidth: 2 }),
|
|
21810
|
+
"filled-circle": () => /* @__PURE__ */ jsx("circle", { cx: 23, cy: -8, r: 11, fill: ink }),
|
|
21811
|
+
"double-circle": () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
21812
|
+
/* @__PURE__ */ jsx("circle", { cx: 23, cy: -8, r: 12, fill: "none", stroke: ink, strokeWidth: 2.5 }),
|
|
21813
|
+
/* @__PURE__ */ jsx("circle", { cx: 23, cy: -8, r: 6, fill: ink })
|
|
21814
|
+
] }),
|
|
21815
|
+
"dotted-line": () => /* @__PURE__ */ jsx(
|
|
21816
|
+
"path",
|
|
21817
|
+
{
|
|
21818
|
+
d: `M 0 -8 H ${LEGEND_MARK_REFERENCE_WIDTH}`,
|
|
21819
|
+
fill: "none",
|
|
21820
|
+
stroke: ink,
|
|
21821
|
+
strokeWidth: 6,
|
|
21822
|
+
strokeLinecap: "round",
|
|
21823
|
+
strokeDasharray: "0 9.6"
|
|
21824
|
+
}
|
|
21825
|
+
),
|
|
21826
|
+
"solid-line": () => /* @__PURE__ */ jsx(
|
|
21827
|
+
"path",
|
|
21828
|
+
{
|
|
21829
|
+
d: `M 0 -8 H ${LEGEND_MARK_REFERENCE_WIDTH}`,
|
|
21830
|
+
fill: "none",
|
|
21831
|
+
stroke: ink,
|
|
21832
|
+
strokeWidth: 4,
|
|
21833
|
+
strokeLinecap: "round"
|
|
21834
|
+
}
|
|
21835
|
+
),
|
|
21836
|
+
"curved-line": () => /* @__PURE__ */ jsx(
|
|
21837
|
+
"path",
|
|
21838
|
+
{
|
|
21839
|
+
d: `M 0 6 C 12 -22, 34 -22, ${LEGEND_MARK_REFERENCE_WIDTH} 6`,
|
|
21840
|
+
fill: "none",
|
|
21841
|
+
stroke: ink,
|
|
21842
|
+
strokeWidth: 4,
|
|
21843
|
+
strokeLinecap: "round"
|
|
21844
|
+
}
|
|
21845
|
+
),
|
|
21846
|
+
"rounded-label": () => /* @__PURE__ */ jsx(
|
|
21847
|
+
"rect",
|
|
21848
|
+
{
|
|
21849
|
+
x: 0,
|
|
21850
|
+
y: -23,
|
|
21851
|
+
width: LEGEND_MARK_REFERENCE_WIDTH,
|
|
21852
|
+
height: 30,
|
|
21853
|
+
rx: 9,
|
|
21854
|
+
fill: paper,
|
|
21855
|
+
stroke: ink,
|
|
21856
|
+
strokeWidth: 2
|
|
21857
|
+
}
|
|
21858
|
+
),
|
|
21859
|
+
"numbered-circle": () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
21860
|
+
/* @__PURE__ */ jsx("circle", { cx: 23, cy: -8, r: 13, fill: paper, stroke: ink, strokeWidth: 2.5 }),
|
|
21861
|
+
/* @__PURE__ */ jsx("text", { x: 23, y: -2, textAnchor: "middle", fontSize: 17, fontWeight: 700, fill: ink, children: "1" })
|
|
21862
|
+
] }),
|
|
21863
|
+
station: () => /* @__PURE__ */ jsx("circle", { cx: 23, cy: -8, r: 11, fill: paper, stroke: ink, strokeWidth: 4 }),
|
|
21864
|
+
arrow: () => /* @__PURE__ */ jsx(
|
|
21865
|
+
"path",
|
|
21866
|
+
{
|
|
21867
|
+
d: `M 0 -8 H 42 M 32 -18 L ${LEGEND_MARK_REFERENCE_WIDTH} -8 L 32 2`,
|
|
21868
|
+
fill: "none",
|
|
21869
|
+
stroke: ink,
|
|
21870
|
+
strokeWidth: 3,
|
|
21871
|
+
strokeLinecap: "round",
|
|
21872
|
+
strokeLinejoin: "round"
|
|
21873
|
+
}
|
|
21874
|
+
)
|
|
21875
|
+
};
|
|
21876
|
+
function CdlLegend({ items }) {
|
|
21877
|
+
return /* @__PURE__ */ jsx("g", { "data-cdl-role": "legend", children: items.map((item, index) => {
|
|
21878
|
+
const Mark = LEGEND_MARK_RENDERERS[item.mark];
|
|
21879
|
+
return /* @__PURE__ */ jsxs(
|
|
21880
|
+
"g",
|
|
21881
|
+
{
|
|
21882
|
+
"data-cdl-role": "legend-item",
|
|
21883
|
+
"data-cdl-y": item.y,
|
|
21884
|
+
transform: `translate(${item.x} ${item.y})`,
|
|
21885
|
+
children: [
|
|
21886
|
+
/* @__PURE__ */ jsx(
|
|
21887
|
+
"g",
|
|
21888
|
+
{
|
|
21889
|
+
"data-cdl-role": "legend-mark",
|
|
21890
|
+
"data-cdl-legend-mark": item.mark,
|
|
21891
|
+
transform: `scale(${LEGEND_MARK_SCALE})`,
|
|
21892
|
+
children: /* @__PURE__ */ jsx(Mark, {})
|
|
21893
|
+
}
|
|
21894
|
+
),
|
|
21895
|
+
/* @__PURE__ */ jsx(
|
|
21896
|
+
"text",
|
|
21897
|
+
{
|
|
21898
|
+
"data-cdl-role": "legend-text",
|
|
21899
|
+
x: LEGEND_MARK_WIDTH + LEGEND_MARK_TEXT_GAP,
|
|
21900
|
+
y: 0,
|
|
21901
|
+
fontSize: LEGEND_FONT_SIZE,
|
|
21902
|
+
fill: "var(--cdl-text-mute, #4d7187)",
|
|
21903
|
+
children: item.text
|
|
21904
|
+
}
|
|
21905
|
+
)
|
|
21906
|
+
]
|
|
21907
|
+
},
|
|
21908
|
+
`${item.mark}-${index}`
|
|
21909
|
+
);
|
|
21910
|
+
}) });
|
|
21911
|
+
}
|
|
21439
21912
|
|
|
21440
21913
|
// src/render/relation-focus.ts
|
|
21441
21914
|
function relatedFocusSet(edges, nodeId) {
|
|
@@ -21448,10 +21921,17 @@ function relatedFocusSet(edges, nodeId) {
|
|
|
21448
21921
|
}
|
|
21449
21922
|
return \u96C6\u5408;
|
|
21450
21923
|
}
|
|
21924
|
+
var METRO_LANE_BADGE_WIDTH = 200;
|
|
21925
|
+
var METRO_LANE_BADGE_HEIGHT = 88;
|
|
21926
|
+
var METRO_LANE_BADGE_INSET = 24;
|
|
21927
|
+
var METRO_LANE_GUIDE_GAP = 24;
|
|
21451
21928
|
function \u63CF\u304F\u3082\u306E\u304C\u3042\u308B(laid) {
|
|
21929
|
+
if (laid.legend && laid.legend.length > 0) return true;
|
|
21452
21930
|
if (laid.edges.length > 0) return true;
|
|
21453
21931
|
if (laid.nodes.some((n) => isRenderedNode(n))) return true;
|
|
21454
|
-
return laid.lanes.some(
|
|
21932
|
+
return laid.lanes.some(
|
|
21933
|
+
(l) => l.contain === true || l.lifeline === true || Boolean(l.label) || l.stage !== void 0 || l.metro !== void 0
|
|
21934
|
+
);
|
|
21455
21935
|
}
|
|
21456
21936
|
function CdlStage({
|
|
21457
21937
|
laid,
|
|
@@ -21492,6 +21972,7 @@ function CdlStage({
|
|
|
21492
21972
|
[\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B, \u7126\u70B9, laid.edges]
|
|
21493
21973
|
);
|
|
21494
21974
|
const activeSet = \u7126\u70B9\u306E\u96C6\u5408 ?? new Set(currentPhase?.activate ?? []);
|
|
21975
|
+
const \u8DEF\u7DDA\u56F3 = laid.edges.some((edge) => edge.routing === "metro") && laid.nodes.some((node) => node.kind === "station");
|
|
21495
21976
|
const \u7BB1\u306E\u53D7\u3051\u53E3 = \u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B ? { \u89E6\u308C\u305F, \u96E2\u308C\u305F, \u62BC\u3057\u305F, \u7126\u70B9: \u7126\u70B9?.id ?? null } : void 0;
|
|
21496
21977
|
const \u77E2\u5370\u306E\u51FA\u756A = useMemo(() => {
|
|
21497
21978
|
const \u521D\u51FA = /* @__PURE__ */ new Map();
|
|
@@ -21520,9 +22001,15 @@ function CdlStage({
|
|
|
21520
22001
|
const first = \u521D\u51FA.get(edgeId);
|
|
21521
22002
|
if (first === void 0) return false;
|
|
21522
22003
|
return \u4ECA === first;
|
|
22004
|
+
},
|
|
22005
|
+
/** 初出の段より前にある区間だけを、通過前として選べるようにする。 */
|
|
22006
|
+
\u307E\u3060\u304B: (edgeId) => {
|
|
22007
|
+
const first = \u521D\u51FA.get(edgeId);
|
|
22008
|
+
return first !== void 0 && \u4ECA >= 0 && \u4ECA < first;
|
|
21523
22009
|
}
|
|
21524
22010
|
};
|
|
21525
22011
|
}, [laid.phases, currentPhase, laid.edgeReveal]);
|
|
22012
|
+
const \u7DDA\u3092\u63CF\u304F = (edge) => edge.routing === "metro" || \u77E2\u5370\u306E\u51FA\u756A.\u51FA\u308B\u304B(edge.id);
|
|
21526
22013
|
const drawSet = new Set(currentPhase?.draw ?? []);
|
|
21527
22014
|
const chartLineScales = useMemo(() => {
|
|
21528
22015
|
const nodes = laid.nodes.filter((node) => node.kind === "chart-line");
|
|
@@ -21610,7 +22097,53 @@ function CdlStage({
|
|
|
21610
22097
|
)
|
|
21611
22098
|
);
|
|
21612
22099
|
}, [laid]);
|
|
22100
|
+
const metroReturnArrowMarkers = useMemo(() => {
|
|
22101
|
+
const tones = new Set(
|
|
22102
|
+
laid.edges.filter((edge) => edge.metroReturn === true).map((edge) => edge.tone)
|
|
22103
|
+
);
|
|
22104
|
+
return [...tones].map((tone) => /* @__PURE__ */ jsx(
|
|
22105
|
+
"marker",
|
|
22106
|
+
{
|
|
22107
|
+
id: metroReturnArrowMarkerId(tone),
|
|
22108
|
+
viewBox: "0 -9.5 21 19",
|
|
22109
|
+
refX: "0",
|
|
22110
|
+
refY: "0",
|
|
22111
|
+
markerWidth: "21",
|
|
22112
|
+
markerHeight: "19",
|
|
22113
|
+
markerUnits: "userSpaceOnUse",
|
|
22114
|
+
orient: "auto",
|
|
22115
|
+
children: /* @__PURE__ */ jsx(
|
|
22116
|
+
"path",
|
|
22117
|
+
{
|
|
22118
|
+
"data-cdl-role": "edge-arrowhead",
|
|
22119
|
+
"data-cdl-mark": "metro-return-arrow",
|
|
22120
|
+
d: METRO_RETURN_ARROW_D,
|
|
22121
|
+
fill: TONE[tone]
|
|
22122
|
+
}
|
|
22123
|
+
)
|
|
22124
|
+
},
|
|
22125
|
+
tone
|
|
22126
|
+
));
|
|
22127
|
+
}, [laid.edges]);
|
|
21613
22128
|
const diagramScale = laid.diagramScale ?? 1;
|
|
22129
|
+
const stageLaneIds = new Set(
|
|
22130
|
+
laid.lanes.filter((lane) => lane.stage !== void 0).map((lane) => lane.id)
|
|
22131
|
+
);
|
|
22132
|
+
const stageNoteNodes = laid.nodes.filter(
|
|
22133
|
+
(node) => node.kind === "card" && (stageLaneIds.has(node.lane) || node.leaderTo !== void 0) && isRenderedNode(node) && Boolean(node.subtitle)
|
|
22134
|
+
);
|
|
22135
|
+
const stageNoteNodeIds = new Set(stageNoteNodes.map((node) => node.id));
|
|
22136
|
+
const nodesById = new Map(laid.nodes.map((node) => [node.id, node]));
|
|
22137
|
+
const metroDecisionIds = /* @__PURE__ */ new Set();
|
|
22138
|
+
const stationNamesRight = /* @__PURE__ */ new Set();
|
|
22139
|
+
for (const edge of laid.edges) {
|
|
22140
|
+
if (edge.routing !== "metro") continue;
|
|
22141
|
+
if (nodesById.get(edge.from)?.kind === "decision") metroDecisionIds.add(edge.from);
|
|
22142
|
+
if (nodesById.get(edge.to)?.kind === "decision") metroDecisionIds.add(edge.to);
|
|
22143
|
+
if (edge.toSide === "top" && nodesById.get(edge.to)?.kind === "station") {
|
|
22144
|
+
stationNamesRight.add(edge.to);
|
|
22145
|
+
}
|
|
22146
|
+
}
|
|
21614
22147
|
if (!\u63CF\u304F\u3082\u306E\u304C\u3042\u308B(laid)) return null;
|
|
21615
22148
|
return /* @__PURE__ */ jsxs("div", { className: compact ? "px-3 py-3" : "px-6 py-6", style: compact ? void 0 : { minHeight: 460 }, children: [
|
|
21616
22149
|
/* @__PURE__ */ jsxs(
|
|
@@ -21630,6 +22163,7 @@ function CdlStage({
|
|
|
21630
22163
|
children: [
|
|
21631
22164
|
/* @__PURE__ */ jsxs("defs", { children: [
|
|
21632
22165
|
edgeHeadMarkers,
|
|
22166
|
+
metroReturnArrowMarkers,
|
|
21633
22167
|
/* @__PURE__ */ jsx(
|
|
21634
22168
|
"marker",
|
|
21635
22169
|
{
|
|
@@ -21666,7 +22200,61 @@ function CdlStage({
|
|
|
21666
22200
|
pointerEvents: "none"
|
|
21667
22201
|
}
|
|
21668
22202
|
),
|
|
21669
|
-
lane.
|
|
22203
|
+
lane.stage && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
22204
|
+
/* @__PURE__ */ jsx(
|
|
22205
|
+
"rect",
|
|
22206
|
+
{
|
|
22207
|
+
"data-cdl-role": "stage-column",
|
|
22208
|
+
x: lane.x + STAGE_COLUMN_GAP / 2,
|
|
22209
|
+
y: lane.y,
|
|
22210
|
+
width: lane.width - STAGE_COLUMN_GAP,
|
|
22211
|
+
height: lane.height,
|
|
22212
|
+
rx: 16,
|
|
22213
|
+
fill: "var(--cdl-stage-bg, #fafafa)",
|
|
22214
|
+
fillOpacity: 0.5,
|
|
22215
|
+
stroke: "var(--cdl-text-mute, #8a8678)",
|
|
22216
|
+
strokeWidth: 1.5
|
|
22217
|
+
}
|
|
22218
|
+
),
|
|
22219
|
+
/* @__PURE__ */ jsx(
|
|
22220
|
+
"text",
|
|
22221
|
+
{
|
|
22222
|
+
"data-cdl-role": "stage-number",
|
|
22223
|
+
x: lane.x + STAGE_COLUMN_GAP / 2 + 20,
|
|
22224
|
+
y: lane.y + 24,
|
|
22225
|
+
fontSize: 14,
|
|
22226
|
+
fontWeight: 500,
|
|
22227
|
+
letterSpacing: 1.5,
|
|
22228
|
+
fill: "var(--cdl-text-mute, #8a8678)",
|
|
22229
|
+
children: `\u6BB5\u968E ${lane.stage.number}`
|
|
22230
|
+
}
|
|
22231
|
+
),
|
|
22232
|
+
/* @__PURE__ */ jsx(
|
|
22233
|
+
"text",
|
|
22234
|
+
{
|
|
22235
|
+
"data-cdl-role": "stage-name",
|
|
22236
|
+
x: lane.x + STAGE_COLUMN_GAP / 2 + 20,
|
|
22237
|
+
y: lane.y + 55,
|
|
22238
|
+
fontSize: 22,
|
|
22239
|
+
fontWeight: 700,
|
|
22240
|
+
fill: "var(--cdl-text, #1a1f2a)",
|
|
22241
|
+
children: lane.stage.name
|
|
22242
|
+
}
|
|
22243
|
+
),
|
|
22244
|
+
/* @__PURE__ */ jsx(
|
|
22245
|
+
"line",
|
|
22246
|
+
{
|
|
22247
|
+
"data-cdl-role": "stage-divider",
|
|
22248
|
+
x1: lane.x + STAGE_COLUMN_GAP / 2,
|
|
22249
|
+
y1: lane.y + 72,
|
|
22250
|
+
x2: lane.x + lane.width - STAGE_COLUMN_GAP / 2,
|
|
22251
|
+
y2: lane.y + 72,
|
|
22252
|
+
stroke: "var(--cdl-divider, #d4d4d8)",
|
|
22253
|
+
strokeWidth: 1.5
|
|
22254
|
+
}
|
|
22255
|
+
)
|
|
22256
|
+
] }),
|
|
22257
|
+
lane.contain && lane.stage === void 0 && /* @__PURE__ */ jsx(
|
|
21670
22258
|
"rect",
|
|
21671
22259
|
{
|
|
21672
22260
|
"data-cdl-role": "lane-container",
|
|
@@ -21702,7 +22290,85 @@ function CdlStage({
|
|
|
21702
22290
|
}
|
|
21703
22291
|
);
|
|
21704
22292
|
})(),
|
|
21705
|
-
lane.
|
|
22293
|
+
lane.timelineAxis && (() => {
|
|
22294
|
+
const ys = laid.nodes.filter((node) => node.lane === lane.id && isRenderedNode(node)).map((node) => node.cy);
|
|
22295
|
+
if (ys.length < 2) return null;
|
|
22296
|
+
const y1 = Math.min(...ys);
|
|
22297
|
+
const y2 = Math.max(...ys);
|
|
22298
|
+
if (y2 <= y1) return null;
|
|
22299
|
+
return /* @__PURE__ */ jsx(
|
|
22300
|
+
"line",
|
|
22301
|
+
{
|
|
22302
|
+
"data-cdl-role": "timeline-axis",
|
|
22303
|
+
x1: lane.x + lane.width / 2,
|
|
22304
|
+
y1,
|
|
22305
|
+
x2: lane.x + lane.width / 2,
|
|
22306
|
+
y2,
|
|
22307
|
+
stroke: "var(--cdl-tone-accent, #2d6a8f)",
|
|
22308
|
+
strokeWidth: TIMELINE_NUMBER_STROKE
|
|
22309
|
+
}
|
|
22310
|
+
);
|
|
22311
|
+
})(),
|
|
22312
|
+
lane.metro !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
22313
|
+
/* @__PURE__ */ jsx(
|
|
22314
|
+
"line",
|
|
22315
|
+
{
|
|
22316
|
+
"data-cdl-role": "metro-lane-guide",
|
|
22317
|
+
x1: lane.x + METRO_LANE_BADGE_INSET + METRO_LANE_BADGE_WIDTH + METRO_LANE_GUIDE_GAP,
|
|
22318
|
+
y1: lane.y + lane.height / 2,
|
|
22319
|
+
x2: lane.x + lane.width - METRO_LANE_BADGE_INSET,
|
|
22320
|
+
y2: lane.y + lane.height / 2,
|
|
22321
|
+
stroke: "var(--cdl-line-mute, #a89d8f)",
|
|
22322
|
+
strokeWidth: 2,
|
|
22323
|
+
strokeDasharray: "22 7 5 7",
|
|
22324
|
+
opacity: 0.45
|
|
22325
|
+
}
|
|
22326
|
+
),
|
|
22327
|
+
/* @__PURE__ */ jsxs(
|
|
22328
|
+
"g",
|
|
22329
|
+
{
|
|
22330
|
+
"data-cdl-role": "metro-lane-badge",
|
|
22331
|
+
transform: `translate(${lane.x + METRO_LANE_BADGE_INSET} ${lane.y + lane.height / 2 - METRO_LANE_BADGE_HEIGHT / 2})`,
|
|
22332
|
+
children: [
|
|
22333
|
+
/* @__PURE__ */ jsx(
|
|
22334
|
+
"rect",
|
|
22335
|
+
{
|
|
22336
|
+
width: METRO_LANE_BADGE_WIDTH,
|
|
22337
|
+
height: METRO_LANE_BADGE_HEIGHT,
|
|
22338
|
+
rx: 12,
|
|
22339
|
+
fill: "var(--cdl-node-fill, #ffffff)",
|
|
22340
|
+
stroke: "var(--cdl-tone-accent, #2d6a8f)",
|
|
22341
|
+
strokeWidth: 1.25
|
|
22342
|
+
}
|
|
22343
|
+
),
|
|
22344
|
+
/* @__PURE__ */ jsx(
|
|
22345
|
+
"text",
|
|
22346
|
+
{
|
|
22347
|
+
x: METRO_LANE_BADGE_WIDTH / 2,
|
|
22348
|
+
y: lane.metro.subtitle ? 37 : 53,
|
|
22349
|
+
fontSize: 26,
|
|
22350
|
+
fontWeight: 700,
|
|
22351
|
+
fill: "var(--cdl-text, #1a1f2a)",
|
|
22352
|
+
textAnchor: "middle",
|
|
22353
|
+
children: lane.label
|
|
22354
|
+
}
|
|
22355
|
+
),
|
|
22356
|
+
lane.metro.subtitle && /* @__PURE__ */ jsx(
|
|
22357
|
+
"text",
|
|
22358
|
+
{
|
|
22359
|
+
x: METRO_LANE_BADGE_WIDTH / 2,
|
|
22360
|
+
y: 67,
|
|
22361
|
+
fontSize: 18,
|
|
22362
|
+
fill: "var(--cdl-text-dim, #5a6270)",
|
|
22363
|
+
textAnchor: "middle",
|
|
22364
|
+
children: lane.metro.subtitle
|
|
22365
|
+
}
|
|
22366
|
+
)
|
|
22367
|
+
]
|
|
22368
|
+
}
|
|
22369
|
+
)
|
|
22370
|
+
] }),
|
|
22371
|
+
lane.label && lane.metro === void 0 && /* @__PURE__ */ jsx(
|
|
21706
22372
|
"text",
|
|
21707
22373
|
{
|
|
21708
22374
|
"data-cdl-role": "lane-label",
|
|
@@ -21719,7 +22385,34 @@ function CdlStage({
|
|
|
21719
22385
|
},
|
|
21720
22386
|
lane.id
|
|
21721
22387
|
)),
|
|
21722
|
-
laid.
|
|
22388
|
+
laid.nodes.map((node) => {
|
|
22389
|
+
if (node.leaderTo === void 0) return null;
|
|
22390
|
+
const target = nodesById.get(node.leaderTo);
|
|
22391
|
+
if (target === void 0) return null;
|
|
22392
|
+
if (!isRenderedNode(node) || !isRenderedNode(target)) return null;
|
|
22393
|
+
const targetIsRight = target.cx >= node.cx;
|
|
22394
|
+
const x1 = node.cx + (targetIsRight ? node.w / 2 : -node.w / 2);
|
|
22395
|
+
const x2 = target.cx + (targetIsRight ? -target.w / 2 : target.w / 2);
|
|
22396
|
+
if (targetIsRight ? x2 <= x1 : x1 <= x2) return null;
|
|
22397
|
+
return /* @__PURE__ */ jsx(
|
|
22398
|
+
"line",
|
|
22399
|
+
{
|
|
22400
|
+
"data-cdl-role": "timeline-leader",
|
|
22401
|
+
"data-cdl-leader-from": node.id,
|
|
22402
|
+
"data-cdl-leader-to": node.leaderTo,
|
|
22403
|
+
x1,
|
|
22404
|
+
y1: node.cy,
|
|
22405
|
+
x2,
|
|
22406
|
+
y2: target.cy,
|
|
22407
|
+
stroke: "var(--cdl-line-mute, #a89d8f)",
|
|
22408
|
+
strokeWidth: 1.5,
|
|
22409
|
+
strokeDasharray: "2 4",
|
|
22410
|
+
strokeLinecap: "round"
|
|
22411
|
+
},
|
|
22412
|
+
`timeline-leader-${node.id}`
|
|
22413
|
+
);
|
|
22414
|
+
}),
|
|
22415
|
+
laid.edges.filter(\u7DDA\u3092\u63CF\u304F).map((edge) => /* @__PURE__ */ jsx(
|
|
21723
22416
|
CdlEdgeView,
|
|
21724
22417
|
{
|
|
21725
22418
|
edge,
|
|
@@ -21727,16 +22420,19 @@ function CdlStage({
|
|
|
21727
22420
|
flowing: \u7126\u70B9\u306E\u96C6\u5408?.has(edge.id) === true && !\u52D5\u304D\u3092\u63A7\u3048\u308B,
|
|
21728
22421
|
drawing: \u77E2\u5370\u306E\u51FA\u756A.\u4F38\u3070\u3059\u304B(edge.id),
|
|
21729
22422
|
progress: \u77E2\u5370\u306E\u51FA\u756A.\u4F38\u3070\u3059\u304B(edge.id) ? \u63CF\u304F\u9032\u307F : progress,
|
|
21730
|
-
stateValues
|
|
22423
|
+
stateValues,
|
|
22424
|
+
pending: edge.routing === "metro" && \u77E2\u5370\u306E\u51FA\u756A.\u307E\u3060\u304B(edge.id)
|
|
21731
22425
|
},
|
|
21732
22426
|
edge.id
|
|
21733
22427
|
)),
|
|
21734
22428
|
laid.nodes.map((node) => {
|
|
21735
22429
|
const \u63CF\u304F = drawSet.has(node.id);
|
|
22430
|
+
const \u6BB5\u968E\u306E\u88DC\u8DB3 = stageNoteNodeIds.has(node.id);
|
|
21736
22431
|
const view = /* @__PURE__ */ jsx(
|
|
21737
22432
|
CdlNodeView,
|
|
21738
22433
|
{
|
|
21739
|
-
node,
|
|
22434
|
+
node: \u6BB5\u968E\u306E\u88DC\u8DB3 ? { ...node, subtitle: void 0 } : node,
|
|
22435
|
+
compactTitleInset: \u6BB5\u968E\u306E\u88DC\u8DB3 ? STAGE_CARD_TEXT_INSET : void 0,
|
|
21740
22436
|
active: activeSet.has(node.id),
|
|
21741
22437
|
lang: laid.lang,
|
|
21742
22438
|
textMetrics: laid.textMetrics,
|
|
@@ -21746,13 +22442,32 @@ function CdlStage({
|
|
|
21746
22442
|
stateValues,
|
|
21747
22443
|
\u5024\u306E\u540D\u524D,
|
|
21748
22444
|
currentPhaseId: currentPhase?.id,
|
|
21749
|
-
chartLineScale: chartLineScales.get(node.id)
|
|
22445
|
+
chartLineScale: chartLineScales.get(node.id),
|
|
22446
|
+
metroDiagram: \u8DEF\u7DDA\u56F3,
|
|
22447
|
+
metroDecision: metroDecisionIds.has(node.id),
|
|
22448
|
+
stationNameRight: stationNamesRight.has(node.id)
|
|
21750
22449
|
}
|
|
21751
22450
|
);
|
|
21752
22451
|
return /* @__PURE__ */ jsx("g", { children: view }, node.id);
|
|
21753
22452
|
}),
|
|
21754
|
-
|
|
21755
|
-
|
|
22453
|
+
stageNoteNodes.map((node) => /* @__PURE__ */ jsx(
|
|
22454
|
+
"text",
|
|
22455
|
+
{
|
|
22456
|
+
"data-cdl-role": "stage-note",
|
|
22457
|
+
"data-cdl-stage-node": node.id,
|
|
22458
|
+
x: node.cx + node.w / 2 - STAGE_CARD_TEXT_INSET,
|
|
22459
|
+
y: node.cy + 1,
|
|
22460
|
+
fontSize: 14,
|
|
22461
|
+
fontWeight: 500,
|
|
22462
|
+
textAnchor: "end",
|
|
22463
|
+
dominantBaseline: "middle",
|
|
22464
|
+
fill: "var(--cdl-text-mute, #8a8678)",
|
|
22465
|
+
children: interpolate(node.subtitle, stateValues, \u5024\u306E\u540D\u524D)
|
|
22466
|
+
},
|
|
22467
|
+
`stage-note-${node.id}`
|
|
22468
|
+
)),
|
|
22469
|
+
laid.edges.filter((edge) => Boolean(edge.dThrough) && \u7DDA\u3092\u63CF\u304F(edge)).map((edge) => /* @__PURE__ */ jsx(CdlEdgeGlowView, { edge, active: activeSet.has(edge.id) }, `glow-${edge.id}`)),
|
|
22470
|
+
laid.edges.filter(\u7DDA\u3092\u63CF\u304F).map((edge) => /* @__PURE__ */ jsx(
|
|
21756
22471
|
CdlEdgeLabelView,
|
|
21757
22472
|
{
|
|
21758
22473
|
edge,
|
|
@@ -21761,7 +22476,7 @@ function CdlStage({
|
|
|
21761
22476
|
},
|
|
21762
22477
|
`label-${edge.id}`
|
|
21763
22478
|
)),
|
|
21764
|
-
laid.edges.filter((edge) => (edge.headLabel || edge.tailLabel) && \
|
|
22479
|
+
laid.edges.filter((edge) => (edge.headLabel || edge.tailLabel) && \u7DDA\u3092\u63CF\u304F(edge)).flatMap(
|
|
21765
22480
|
(edge) => ["head", "tail"].map((\u7AEF) => /* @__PURE__ */ jsx(
|
|
21766
22481
|
CdlEdgeEndLabelView,
|
|
21767
22482
|
{
|
|
@@ -21773,6 +22488,7 @@ function CdlStage({
|
|
|
21773
22488
|
`${\u7AEF}-label-${edge.id}`
|
|
21774
22489
|
))
|
|
21775
22490
|
),
|
|
22491
|
+
laid.legend && /* @__PURE__ */ jsx(CdlLegend, { items: laid.legend }),
|
|
21776
22492
|
debug && /* @__PURE__ */ jsxs("g", { pointerEvents: "none", children: [
|
|
21777
22493
|
laid.bboxes.map((bbox, idx) => {
|
|
21778
22494
|
const color = bbox.kind === "node" ? "#3b82f6" : bbox.kind === "lane-label" ? "#a855f7" : bbox.kind === "edge-label" ? "#10b981" : "#f59e0b";
|