@cardenelabs/cdl 0.123.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 +55 -1
- package/README.md +14 -1
- package/dist/index.cjs +924 -134
- 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 +924 -135
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +909 -134
- 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 +909 -134
- package/dist/react.js.map +1 -1
- package/dist/{render-CVczwfRb.d.cts → render-7yEHIUK1.d.cts} +60 -5
- package/dist/{render-CVczwfRb.d.ts → render-7yEHIUK1.d.ts} +60 -5
- 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 +169 -17
- 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 +109 -7
- 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
3315
|
}
|
|
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
|
-
}
|
|
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);
|
|
@@ -9105,6 +9222,57 @@ function bowSharedStraightPaths(edges, nodes, skipIds, textMetrics = "proportion
|
|
|
9105
9222
|
function nodeRect(n) {
|
|
9106
9223
|
return { x: n.cx - n.w / 2, y: n.cy - n.h / 2, w: n.w, h: n.h };
|
|
9107
9224
|
}
|
|
9225
|
+
function countPathObstacleCrossings(d, obstacles) {
|
|
9226
|
+
const segments = flattenPathSegments(extractPathSegments(d));
|
|
9227
|
+
return obstacles.filter((obstacle) => segmentsCrossRect(segments, nodeRect(obstacle))).length;
|
|
9228
|
+
}
|
|
9229
|
+
function makeBackDetourCandidate(A, B, from, to, obstacles, detourY, side, columnXOverride) {
|
|
9230
|
+
const lowIsA = A.y >= B.y;
|
|
9231
|
+
const low = lowIsA ? A : B;
|
|
9232
|
+
const lowBendY = low.y - VERTICAL_DETOUR_EXIT;
|
|
9233
|
+
const bandTop = Math.min(detourY, lowBendY);
|
|
9234
|
+
const bandBottom = Math.max(detourY, lowBendY);
|
|
9235
|
+
const bandObstacles = obstacles.map(nodeRect).filter((rect) => rect.y + rect.h >= bandTop && rect.y <= bandBottom);
|
|
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
|
+
}
|
|
9245
|
+
}
|
|
9246
|
+
const bendAY = lowIsA ? lowBendY : detourY;
|
|
9247
|
+
const bendBY = lowIsA ? detourY : lowBendY;
|
|
9248
|
+
const vertices = [
|
|
9249
|
+
A,
|
|
9250
|
+
{ x: A.x, y: bendAY },
|
|
9251
|
+
{ x: columnX, y: bendAY },
|
|
9252
|
+
{ x: columnX, y: bendBY },
|
|
9253
|
+
{ x: B.x, y: bendBY },
|
|
9254
|
+
B
|
|
9255
|
+
];
|
|
9256
|
+
const d = verticesToPath(vertices);
|
|
9257
|
+
const high = lowIsA ? B : A;
|
|
9258
|
+
return {
|
|
9259
|
+
d,
|
|
9260
|
+
labelX: (high.x + columnX) / 2,
|
|
9261
|
+
crossings: countPathObstacleCrossings(d, obstacles),
|
|
9262
|
+
length: vertices.slice(1).reduce((sum, vertex, index) => {
|
|
9263
|
+
const previous = vertices[index];
|
|
9264
|
+
return sum + Math.hypot(vertex.x - previous.x, vertex.y - previous.y);
|
|
9265
|
+
}, 0)
|
|
9266
|
+
};
|
|
9267
|
+
}
|
|
9268
|
+
function chooseBackDetourCandidate(A, B, from, to, obstacles, detourY) {
|
|
9269
|
+
const left = makeBackDetourCandidate(A, B, from, to, obstacles, detourY, "left");
|
|
9270
|
+
const right = makeBackDetourCandidate(A, B, from, to, obstacles, detourY, "right");
|
|
9271
|
+
if (left.crossings !== right.crossings) return left.crossings < right.crossings ? left : right;
|
|
9272
|
+
if (Math.abs(left.length - right.length) >= 0.5) return left.length < right.length ? left : right;
|
|
9273
|
+
const preferred = Math.abs(A.x - B.x) < 0.5 ? "right" : A.x < B.x ? "left" : "right";
|
|
9274
|
+
return preferred === "left" ? left : right;
|
|
9275
|
+
}
|
|
9108
9276
|
function rectGap(a, b) {
|
|
9109
9277
|
const dx = Math.max(0, a.x - (b.x + b.w), b.x - (a.x + a.w));
|
|
9110
9278
|
const dy = Math.max(0, a.y - (b.y + b.h), b.y - (a.y + a.h));
|
|
@@ -9182,7 +9350,7 @@ function sidePoint(n, side) {
|
|
|
9182
9350
|
return { x: n.cx + n.w / 2, y: n.cy };
|
|
9183
9351
|
}
|
|
9184
9352
|
}
|
|
9185
|
-
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") {
|
|
9186
9354
|
const labelBoxW = edge ? computeLabelBoxW(edge.label, edge.sub, textMetrics) : 0;
|
|
9187
9355
|
const labelHalfW = labelBoxW / 2;
|
|
9188
9356
|
const labelInit = labelInitClearance(edge);
|
|
@@ -9552,23 +9720,52 @@ function routePath(from, to, fromSide, toSide, obstacles = [], detourSide, _from
|
|
|
9552
9720
|
};
|
|
9553
9721
|
}
|
|
9554
9722
|
if (topTopPair) {
|
|
9555
|
-
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
|
+
);
|
|
9556
9734
|
const corner = 14;
|
|
9557
|
-
const xDir =
|
|
9558
|
-
|
|
9559
|
-
d: `M ${
|
|
9560
|
-
L ${
|
|
9561
|
-
Q ${
|
|
9562
|
-
L ${
|
|
9563
|
-
Q ${
|
|
9564
|
-
L ${
|
|
9565
|
-
labelX: (
|
|
9735
|
+
const xDir = backB.x > backA.x ? 1 : -1;
|
|
9736
|
+
const existing = {
|
|
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,
|
|
9566
9744
|
// CAR-468 SSOT ... 旧 detourY - 30 magic number を LABEL_INIT_CLEARANCE (26、 CAR-570 で 34 → 26 縮小) に置換。
|
|
9567
9745
|
// CAR-518 SSOT ... dotted-flow は 62 world (marker glow radius 分拡張) を labelInit で参照。
|
|
9568
9746
|
// top-top detour の水平 segment 上方 labelInit world = spec 準拠距離。
|
|
9569
9747
|
labelY: detourY - labelInit,
|
|
9570
9748
|
labelAnchor: "middle"
|
|
9571
9749
|
};
|
|
9750
|
+
const existingCrossings = countPathObstacleCrossings(existing.d, obstacles);
|
|
9751
|
+
if (existingCrossings === 0) return existing;
|
|
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);
|
|
9762
|
+
if (candidate.crossings >= existingCrossings) return existing;
|
|
9763
|
+
return {
|
|
9764
|
+
d: candidate.d,
|
|
9765
|
+
labelX: candidate.labelX,
|
|
9766
|
+
labelY: detourY - labelInit,
|
|
9767
|
+
labelAnchor: "middle"
|
|
9768
|
+
};
|
|
9572
9769
|
}
|
|
9573
9770
|
const midX = fromSide === "left" || fromSide === "right" ? B.x : A.x;
|
|
9574
9771
|
const midY = fromSide === "top" || fromSide === "bottom" ? B.y : A.y;
|
|
@@ -10495,12 +10692,56 @@ function \u76F4\u524D\u306E\u6298\u308C\u3054\u3068\u305A\u3089\u3059(segs, \u6A
|
|
|
10495
10692
|
return parts.join(" ");
|
|
10496
10693
|
}
|
|
10497
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
|
+
|
|
10498
10728
|
// src/layout/lanes.ts
|
|
10499
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
|
+
}
|
|
10500
10741
|
function layoutLanes(diag) {
|
|
10501
10742
|
const laneGap = diag.viewport?.laneGap ?? diag.viewport?.gap ?? DEFAULT_LANE_GAP;
|
|
10502
10743
|
let cursorX = 0;
|
|
10503
|
-
|
|
10744
|
+
const lanes = diag.lanes.map((lane, index) => {
|
|
10504
10745
|
if (lane.posX !== void 0 && lane.posY !== void 0) {
|
|
10505
10746
|
return {
|
|
10506
10747
|
...lane,
|
|
@@ -10511,7 +10752,9 @@ function layoutLanes(diag) {
|
|
|
10511
10752
|
};
|
|
10512
10753
|
}
|
|
10513
10754
|
const resolvedX = lane.x ?? cursorX;
|
|
10514
|
-
|
|
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;
|
|
10515
10758
|
return {
|
|
10516
10759
|
...lane,
|
|
10517
10760
|
x: resolvedX,
|
|
@@ -10519,6 +10762,7 @@ function layoutLanes(diag) {
|
|
|
10519
10762
|
height: LANE_LABEL_H
|
|
10520
10763
|
};
|
|
10521
10764
|
});
|
|
10765
|
+
return equalizeStageColumns(lanes);
|
|
10522
10766
|
}
|
|
10523
10767
|
function expandLanesForNodes(lanes, nodes) {
|
|
10524
10768
|
const targetNodeGap = targetNodeNodeClearance();
|
|
@@ -10547,7 +10791,8 @@ function expandLanesForNodes(lanes, nodes) {
|
|
|
10547
10791
|
if (lane.posX !== void 0 && lane.posY !== void 0) continue;
|
|
10548
10792
|
const inside = nodes.filter((n) => n.lane === lane.id);
|
|
10549
10793
|
const maxNodeW = inside.length > 0 ? Math.max(...inside.map((n) => n.w)) : 0;
|
|
10550
|
-
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);
|
|
10551
10796
|
widthOf.set(lane.id, newWidth);
|
|
10552
10797
|
deltaOf.set(lane.id, newWidth - lane.width);
|
|
10553
10798
|
}
|
|
@@ -10572,6 +10817,34 @@ function expandLaneGapsForEdgeLabels(lanes, nodes, edges, textMetrics = "proport
|
|
|
10572
10817
|
if (lanes.length < 2) return lanes;
|
|
10573
10818
|
const layoutedLanes = lanes.filter((l) => !(l.posX !== void 0 && l.posY !== void 0));
|
|
10574
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
|
+
}
|
|
10575
10848
|
const nodeById = new Map(nodes.map((n) => [n.id, n]));
|
|
10576
10849
|
const sortedByX = [...layoutedLanes].sort((a, b) => a.x - b.x);
|
|
10577
10850
|
const laneIndexById = new Map(sortedByX.map((lane, i) => [lane.id, i]));
|
|
@@ -10643,7 +10916,7 @@ function recomputeContainedLanes(lanes, nodes) {
|
|
|
10643
10916
|
lifelineBottom = Math.max(lifelineBottom, bottom);
|
|
10644
10917
|
}
|
|
10645
10918
|
}
|
|
10646
|
-
|
|
10919
|
+
const contained = lanes.map((lane) => {
|
|
10647
10920
|
if (lane.lifeline) {
|
|
10648
10921
|
return {
|
|
10649
10922
|
...lane,
|
|
@@ -10661,6 +10934,7 @@ function recomputeContainedLanes(lanes, nodes) {
|
|
|
10661
10934
|
height: bottom - top + CONTAIN_PAD * 2 + LANE_LABEL_H
|
|
10662
10935
|
};
|
|
10663
10936
|
});
|
|
10937
|
+
return equalizeStageColumns(contained, nodes);
|
|
10664
10938
|
}
|
|
10665
10939
|
|
|
10666
10940
|
// src/layout/head-label.ts
|
|
@@ -10810,11 +11084,15 @@ function requiredStackGapForEdgeLabels(diag, allStacks) {
|
|
|
10810
11084
|
}
|
|
10811
11085
|
function layoutNodes(diag, lanes, textMetrics) {
|
|
10812
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];
|
|
10813
11091
|
const allStacks = Array.from(new Set(diag.nodes.map((n) => n.stack))).sort((a, b) => a - b);
|
|
10814
11092
|
const rowH = /* @__PURE__ */ new Map();
|
|
10815
11093
|
for (const stack of allStacks) {
|
|
10816
11094
|
const nodesAtStack = diag.nodes.filter((n) => n.stack === stack);
|
|
10817
|
-
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)));
|
|
10818
11096
|
rowH.set(stack, h);
|
|
10819
11097
|
}
|
|
10820
11098
|
const rowCy = /* @__PURE__ */ new Map();
|
|
@@ -10850,7 +11128,7 @@ function layoutNodes(diag, lanes, textMetrics) {
|
|
|
10850
11128
|
if (!lane) {
|
|
10851
11129
|
throw new Error(`cdl layout: node "${n.id}" \u306E lane "${n.lane}" \u304C\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u306A\u3044`);
|
|
10852
11130
|
}
|
|
10853
|
-
const size =
|
|
11131
|
+
const size = nodeSize(n);
|
|
10854
11132
|
if (n.posX !== void 0 && n.posY !== void 0) {
|
|
10855
11133
|
const w2 = n.posW ?? n.w ?? autoRowsWidth(n, size.w, textMetrics);
|
|
10856
11134
|
const h2 = n.posH ?? n.h ?? rowH.get(n.stack) ?? size.h;
|
|
@@ -10973,6 +11251,9 @@ function dropUnsafeLaneDx(dxByLane, nodes) {
|
|
|
10973
11251
|
function applyRowLevelNodeShifts(nodes, lanes, nodeShifts) {
|
|
10974
11252
|
const dyByStack = aggregateRowDy(nodes, nodeShifts);
|
|
10975
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
|
+
}
|
|
10976
11257
|
let moved = false;
|
|
10977
11258
|
const outNodes = nodes.map((n) => {
|
|
10978
11259
|
const dx = dxByLane.get(n.lane) ?? 0;
|
|
@@ -11092,7 +11373,15 @@ function layout(diag) {
|
|
|
11092
11373
|
);
|
|
11093
11374
|
}
|
|
11094
11375
|
}
|
|
11095
|
-
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;
|
|
11096
11385
|
return {
|
|
11097
11386
|
id: diag.id,
|
|
11098
11387
|
topic: diag.topic,
|
|
@@ -11119,6 +11408,7 @@ function layout(diag) {
|
|
|
11119
11408
|
...textMetrics === "monospace" ? { textMetrics: "monospace" } : {},
|
|
11120
11409
|
// 種類も配色と同じく空の目印を出さない。 遮断をここに揃えると手書きの図にも効く
|
|
11121
11410
|
...diag.type ? { type: diag.type } : {},
|
|
11411
|
+
...legendLayout ? { legend: legendLayout.legend } : {},
|
|
11122
11412
|
bboxes,
|
|
11123
11413
|
collisions,
|
|
11124
11414
|
nearCollisions,
|
|
@@ -11307,6 +11597,11 @@ function validate(diag) {
|
|
|
11307
11597
|
\u2192 \u4FEE\u6B63\u4F8B: .lane("${n.lane}", { x: 0, width: 400 }) \u3092 node \u5BA3\u8A00\u524D\u306B\u8FFD\u52A0`
|
|
11308
11598
|
);
|
|
11309
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
|
+
}
|
|
11310
11605
|
}
|
|
11311
11606
|
for (const e of diag.edges) {
|
|
11312
11607
|
if (!nodeIds.has(e.from)) {
|
|
@@ -11925,6 +12220,10 @@ function uniformLifelineEndY(lanes, nodes, starts = lifelineStartYs(nodes)) {
|
|
|
11925
12220
|
|
|
11926
12221
|
// src/render/edge-head.ts
|
|
11927
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
|
+
}
|
|
11928
12227
|
var EDGE_HEAD_SHAPE = {
|
|
11929
12228
|
// 何も描かない端。 marker 自体を出さないので `d` は読まれない
|
|
11930
12229
|
none: { d: "", w: 10, h: 10, refX: 0, filled: false },
|
|
@@ -11979,6 +12278,7 @@ function \u7B49\u5E45\u306E\u5B57(text, fontSize) {
|
|
|
11979
12278
|
});
|
|
11980
12279
|
return out;
|
|
11981
12280
|
}
|
|
12281
|
+
var METRO_PENDING_ATTRIBUTE = "data-cdl-pending";
|
|
11982
12282
|
function defaultEdgeWidth(active) {
|
|
11983
12283
|
return active ? 2.5 : 1.25;
|
|
11984
12284
|
}
|
|
@@ -11997,12 +12297,14 @@ function CdlEdgeView({
|
|
|
11997
12297
|
drawing,
|
|
11998
12298
|
progress,
|
|
11999
12299
|
stateValues,
|
|
12000
|
-
flowing = false
|
|
12300
|
+
flowing = false,
|
|
12301
|
+
pending = false
|
|
12001
12302
|
}) {
|
|
12002
12303
|
const color = edgeColor(edge);
|
|
12003
|
-
const marker = edgeHeadMarkerName(edge.tone, edge.head, !active, edge.headFill);
|
|
12004
|
-
const tailMarker = edge.tailHead === void 0 ? void 0 : edgeHeadMarkerName(edge.tone, edge.tailHead, !active, edge.tailHeadFill);
|
|
12005
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);
|
|
12006
12308
|
const isDotted = style === "dotted-flow";
|
|
12007
12309
|
const isPassThrough = isDotted && Boolean(edge.dThrough);
|
|
12008
12310
|
const lineDotsD = isDotted ? shrinkPathEnd(edge.d, 12) : edge.d;
|
|
@@ -12012,6 +12314,7 @@ function CdlEdgeView({
|
|
|
12012
12314
|
return /* @__PURE__ */ jsxs(
|
|
12013
12315
|
"g",
|
|
12014
12316
|
{
|
|
12317
|
+
...pending ? { [METRO_PENDING_ATTRIBUTE]: "true" } : {},
|
|
12015
12318
|
"data-cdl-edge": edge.id,
|
|
12016
12319
|
"data-cdl-routing": edge.routing === "metro" ? "metro" : void 0,
|
|
12017
12320
|
"data-cdl-from": edge.from,
|
|
@@ -12037,11 +12340,12 @@ function CdlEdgeView({
|
|
|
12037
12340
|
fill: "none",
|
|
12038
12341
|
stroke: color,
|
|
12039
12342
|
strokeOpacity: active ? 0.95 : 0.9,
|
|
12040
|
-
strokeWidth: active ? 5 : 4,
|
|
12343
|
+
strokeWidth: edge.routing === "metro" ? METRO_LINE_WIDTH : active ? 5 : 4,
|
|
12041
12344
|
strokeDasharray: "0 18",
|
|
12042
12345
|
strokeLinecap: "round",
|
|
12043
12346
|
style: {
|
|
12044
|
-
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
|
|
12045
12349
|
}
|
|
12046
12350
|
}
|
|
12047
12351
|
),
|
|
@@ -12096,7 +12400,9 @@ function SolidEdgePath({
|
|
|
12096
12400
|
const boundWidth = edge.widthBind && stateValues ? resolveNumericAttr(edge.widthBind, stateValues, defaultWidth) : defaultWidth;
|
|
12097
12401
|
const boundStroke = edge.strokeBind && stateValues ? interpolate(edge.strokeBind, stateValues) : color;
|
|
12098
12402
|
const boundDashOffset = edge.dashOffsetBind && stateValues ? resolveNumericAttr(edge.dashOffsetBind, stateValues, 0) : void 0;
|
|
12099
|
-
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";
|
|
12100
12406
|
return /* @__PURE__ */ jsx(
|
|
12101
12407
|
"path",
|
|
12102
12408
|
{
|
|
@@ -12105,14 +12411,15 @@ function SolidEdgePath({
|
|
|
12105
12411
|
fill: "none",
|
|
12106
12412
|
stroke: boundStroke,
|
|
12107
12413
|
strokeOpacity: active ? 0.95 : 0.9,
|
|
12108
|
-
strokeWidth
|
|
12414
|
+
strokeWidth,
|
|
12109
12415
|
strokeDasharray: dashArray,
|
|
12110
12416
|
strokeDashoffset: boundDashOffset,
|
|
12111
12417
|
strokeLinecap: "round",
|
|
12112
12418
|
markerEnd: marker === void 0 ? void 0 : `url(#${marker})`,
|
|
12113
12419
|
markerStart: tailMarker === void 0 ? void 0 : `url(#${tailMarker})`,
|
|
12114
12420
|
style: {
|
|
12115
|
-
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
|
|
12116
12423
|
}
|
|
12117
12424
|
}
|
|
12118
12425
|
);
|
|
@@ -12409,7 +12716,11 @@ function \u5272\u308B\u5019\u88DC(text) {
|
|
|
12409
12716
|
function \u5165\u3063\u3066\u3044\u308B([\u5DE6, \u53F3]) {
|
|
12410
12717
|
return \u5DE6 !== "" && \u53F3 !== "";
|
|
12411
12718
|
}
|
|
12412
|
-
function CardNode({
|
|
12719
|
+
function CardNode({
|
|
12720
|
+
node,
|
|
12721
|
+
active,
|
|
12722
|
+
compactTitleInset
|
|
12723
|
+
}) {
|
|
12413
12724
|
const accent = nodeAccent(node, "var(--cdl-tone-accent, #2d6a8f)");
|
|
12414
12725
|
const x = node.cx - node.w / 2;
|
|
12415
12726
|
const y = node.cy - node.h / 2;
|
|
@@ -12427,12 +12738,12 @@ function CardNode({ node, active }) {
|
|
|
12427
12738
|
});
|
|
12428
12739
|
const \u305A\u3089\u3057 = \u7E70\u308A\u4E0A\u3052 - \u4F59\u308A;
|
|
12429
12740
|
const titleY = compact ? \u5C0F\u578B\u306B\u547C\u3073\u540D ? node.h / 2 - 2 : node.h / 2 + 8 : 86 - \u305A\u3089\u3057;
|
|
12430
|
-
const titleX = compact ? node.w / 2 : 26;
|
|
12431
|
-
const paddingX = compact ?
|
|
12741
|
+
const titleX = compact ? compactTitleInset ?? node.w / 2 : 26;
|
|
12742
|
+
const paddingX = compact ? (compactTitleInset ?? 8) * 2 : 52;
|
|
12432
12743
|
const availableW = node.w - paddingX;
|
|
12433
12744
|
const initialTitleSize = compact ? 20 : 24;
|
|
12434
12745
|
const titleSize = fitTextSize(node.title, availableW, initialTitleSize, 11);
|
|
12435
|
-
const textAnchor = compact ? "middle" : "start";
|
|
12746
|
+
const textAnchor = compact && compactTitleInset === void 0 ? "middle" : "start";
|
|
12436
12747
|
const subtitleY = 124 - \u305A\u3089\u3057;
|
|
12437
12748
|
const \u6700\u5927\u306E\u884C\u9001\u308A = SUBTITLE_SIZE * \u884C\u9001\u308A\u306E\u500D\u7387;
|
|
12438
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;
|
|
@@ -13192,7 +13503,9 @@ function GenericNode({
|
|
|
13192
13503
|
value,
|
|
13193
13504
|
stateValues,
|
|
13194
13505
|
\u5024\u306E\u540D\u524D,
|
|
13195
|
-
textMetrics = "proportional"
|
|
13506
|
+
textMetrics = "proportional",
|
|
13507
|
+
showKindIcon = true,
|
|
13508
|
+
metroDecision = false
|
|
13196
13509
|
}) {
|
|
13197
13510
|
const base = STYLES[node.kind] ?? FALLBACK;
|
|
13198
13511
|
const toned = toneColor3(node.tone);
|
|
@@ -13223,14 +13536,14 @@ function GenericNode({
|
|
|
13223
13536
|
if (shape === "diamond") {
|
|
13224
13537
|
const cx = w / 2;
|
|
13225
13538
|
const cy = h / 2;
|
|
13226
|
-
const pad = 8;
|
|
13539
|
+
const pad = metroDecision ? 0 : 8;
|
|
13227
13540
|
return /* @__PURE__ */ jsx(
|
|
13228
13541
|
"path",
|
|
13229
13542
|
{
|
|
13230
13543
|
d: `M ${cx} ${pad} L ${w - pad} ${cy} L ${cx} ${h - pad} L ${pad} ${cy} Z`,
|
|
13231
13544
|
fill: "var(--cdl-node-fill, #ffffff)",
|
|
13232
13545
|
stroke: active ? style.accent : "var(--cdl-divider, #d4d4d8)",
|
|
13233
|
-
strokeWidth: active ? 3 : 1.25
|
|
13546
|
+
strokeWidth: metroDecision ? 1.5 : active ? 3 : 1.25
|
|
13234
13547
|
}
|
|
13235
13548
|
);
|
|
13236
13549
|
}
|
|
@@ -13294,11 +13607,11 @@ function GenericNode({
|
|
|
13294
13607
|
const \u305A\u3089\u3057 = \u7E70\u308A\u4E0A\u3052 - \u4F59\u308A;
|
|
13295
13608
|
const \u7D75\u306E\u82AF = centered && STYLES[node.kind]?.shape === "cloud" ? h * CLOUD_ART_CENTER_RISE : 0;
|
|
13296
13609
|
const eyebrowY = centered ? h / 2 - 26 - \u7D75\u306E\u82AF : 32 + cylinderShift + \u4F59\u308A;
|
|
13297
|
-
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;
|
|
13298
13611
|
const subtitleY = centered ? h / 2 + 28 - \u7D75\u306E\u82AF : 96 + cylinderShift - \u305A\u3089\u3057;
|
|
13299
13612
|
const iconX = centered ? w / 2 + 40 : w - 48;
|
|
13300
13613
|
const iconY = centered ? h / 2 - 44 - \u7D75\u306E\u82AF : 18 + cylinderShift;
|
|
13301
|
-
const dominantBaseline = centered ? "middle" : void 0;
|
|
13614
|
+
const dominantBaseline = centered && !metroDecision ? "middle" : void 0;
|
|
13302
13615
|
return /* @__PURE__ */ jsxs(
|
|
13303
13616
|
"g",
|
|
13304
13617
|
{
|
|
@@ -13307,12 +13620,12 @@ function GenericNode({
|
|
|
13307
13620
|
"data-cdl-look": style.look,
|
|
13308
13621
|
children: [
|
|
13309
13622
|
shapeEl,
|
|
13310
|
-
/* @__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: [
|
|
13311
13624
|
/* @__PURE__ */ jsx("rect", { width: 24, height: 24, fill: "transparent" }),
|
|
13312
13625
|
/* @__PURE__ */ jsx("path", { d: style.icon, fill: style.eyebrowColor, opacity: 0.7, transform: "scale(1)" })
|
|
13313
13626
|
] }),
|
|
13314
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 }),
|
|
13315
|
-
/* @__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 }),
|
|
13316
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) }),
|
|
13317
13630
|
resolvedValue && /* @__PURE__ */ jsx(
|
|
13318
13631
|
"text",
|
|
@@ -13361,50 +13674,176 @@ function GenericNode({
|
|
|
13361
13674
|
var MARK_INNER_RATIO = 0.56;
|
|
13362
13675
|
var RING_WIDTH_ACTIVE = 6;
|
|
13363
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;
|
|
13364
13681
|
var MARK_DEFAULT = "var(--cdl-tone-accent, #2d6a8f)";
|
|
13365
13682
|
function markRadius(node) {
|
|
13366
13683
|
return Math.min(node.w, node.h) / 2;
|
|
13367
13684
|
}
|
|
13368
|
-
function MarkStartNode({
|
|
13685
|
+
function MarkStartNode({
|
|
13686
|
+
node,
|
|
13687
|
+
metro = false
|
|
13688
|
+
}) {
|
|
13369
13689
|
const \u8272 = nodeAccent(node, MARK_DEFAULT);
|
|
13370
|
-
return /* @__PURE__ */ jsx(
|
|
13371
|
-
"
|
|
13690
|
+
return /* @__PURE__ */ jsx(
|
|
13691
|
+
"g",
|
|
13372
13692
|
{
|
|
13373
|
-
"data-cdl-role": "
|
|
13374
|
-
|
|
13375
|
-
|
|
13376
|
-
|
|
13377
|
-
|
|
13378
|
-
|
|
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
|
+
)
|
|
13379
13706
|
}
|
|
13380
|
-
)
|
|
13707
|
+
);
|
|
13381
13708
|
}
|
|
13382
|
-
function MarkEndNode({
|
|
13709
|
+
function MarkEndNode({
|
|
13710
|
+
node,
|
|
13711
|
+
active,
|
|
13712
|
+
metro = false
|
|
13713
|
+
}) {
|
|
13383
13714
|
const \u8272 = nodeAccent(node, MARK_DEFAULT);
|
|
13384
|
-
const r = markRadius(node);
|
|
13385
|
-
const \u8F2A\u306E\u592A\u3055 = active ? RING_WIDTH_ACTIVE : RING_WIDTH_IDLE;
|
|
13386
|
-
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: [
|
|
13387
13768
|
/* @__PURE__ */ jsx(
|
|
13388
13769
|
"circle",
|
|
13389
13770
|
{
|
|
13390
13771
|
"data-cdl-role": "node-body",
|
|
13391
|
-
"data-cdl-mark": "
|
|
13392
|
-
cx: node.
|
|
13393
|
-
cy: node.
|
|
13394
|
-
r:
|
|
13772
|
+
"data-cdl-mark": "station",
|
|
13773
|
+
cx: node.cx,
|
|
13774
|
+
cy: node.cy,
|
|
13775
|
+
r: METRO_STATION_RADIUS,
|
|
13395
13776
|
fill: "var(--cdl-node-fill, #ffffff)",
|
|
13396
|
-
stroke:
|
|
13397
|
-
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 }
|
|
13398
13780
|
}
|
|
13399
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
|
|
13797
|
+
}
|
|
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: [
|
|
13400
13822
|
/* @__PURE__ */ jsx(
|
|
13401
13823
|
"circle",
|
|
13402
13824
|
{
|
|
13403
|
-
"data-cdl-role": "node-
|
|
13404
|
-
|
|
13405
|
-
|
|
13406
|
-
|
|
13407
|
-
|
|
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
|
|
13408
13847
|
}
|
|
13409
13848
|
)
|
|
13410
13849
|
] });
|
|
@@ -13736,27 +14175,6 @@ function interpolateColor(template, stateValues, fallback) {
|
|
|
13736
14175
|
if (!template) return fallback;
|
|
13737
14176
|
return interpolate(template, stateValues);
|
|
13738
14177
|
}
|
|
13739
|
-
var STATION_STROKE_ACTIVE = 4;
|
|
13740
|
-
var STATION_STROKE_IDLE = 3;
|
|
13741
|
-
var STATION_DEFAULT = "var(--cdl-tone-accent, #2d6a8f)";
|
|
13742
|
-
function StationNode({ node, active }) {
|
|
13743
|
-
const strokeWidth = active ? STATION_STROKE_ACTIVE : STATION_STROKE_IDLE;
|
|
13744
|
-
const radius = Math.max(0, Math.min(node.w, node.h) / 2 - strokeWidth / 2);
|
|
13745
|
-
const \u5F62 = /* @__PURE__ */ jsx(
|
|
13746
|
-
"circle",
|
|
13747
|
-
{
|
|
13748
|
-
"data-cdl-role": "node-body",
|
|
13749
|
-
"data-cdl-mark": "station",
|
|
13750
|
-
cx: node.cx,
|
|
13751
|
-
cy: node.cy,
|
|
13752
|
-
r: radius,
|
|
13753
|
-
fill: "var(--cdl-node-fill, #ffffff)",
|
|
13754
|
-
stroke: nodeAccent(node, STATION_DEFAULT),
|
|
13755
|
-
strokeWidth
|
|
13756
|
-
}
|
|
13757
|
-
);
|
|
13758
|
-
return renderShapeWithOutsideLabels(\u5F62, node, "middle");
|
|
13759
|
-
}
|
|
13760
14178
|
|
|
13761
14179
|
// src/kinds/label-stack.ts
|
|
13762
14180
|
function \u540D\u672D\u306E\u6BB5\u3092\u307B\u3069\u304F(\u771F\u306Ey, \u9593\u9694, \u4E0A\u9650, \u4E0B\u9650) {
|
|
@@ -20918,10 +21336,14 @@ function CdlNodeView({
|
|
|
20918
21336
|
stateValues,
|
|
20919
21337
|
currentPhaseId,
|
|
20920
21338
|
chartLineScale,
|
|
21339
|
+
compactTitleInset,
|
|
20921
21340
|
\u95A2\u4FC2\u306E\u53D7\u3051\u53E3,
|
|
20922
21341
|
lang,
|
|
20923
21342
|
textMetrics,
|
|
20924
|
-
\u5024\u306E\u540D\u524D
|
|
21343
|
+
\u5024\u306E\u540D\u524D,
|
|
21344
|
+
metroDiagram = false,
|
|
21345
|
+
metroDecision = false,
|
|
21346
|
+
stationNameRight = false
|
|
20925
21347
|
}) {
|
|
20926
21348
|
const value = node.value ? interpolate(node.value, stateValues, \u5024\u306E\u540D\u524D) : void 0;
|
|
20927
21349
|
const rows = (node.rows ?? []).map((r) => interpolate(r, stateValues, \u5024\u306E\u540D\u524D));
|
|
@@ -20962,7 +21384,7 @@ function CdlNodeView({
|
|
|
20962
21384
|
case "event":
|
|
20963
21385
|
return /* @__PURE__ */ jsx(EventNode, { node: resolvedNode, active, progress });
|
|
20964
21386
|
case "card":
|
|
20965
|
-
return /* @__PURE__ */ jsx(CardNode, { node: resolvedNode, active });
|
|
21387
|
+
return /* @__PURE__ */ jsx(CardNode, { node: resolvedNode, active, compactTitleInset });
|
|
20966
21388
|
// 時系列のやり取り (#578)。 1 つの箱が図を丸ごと描く = 縦が時間で、参加者は箱を持たない
|
|
20967
21389
|
case "sequence-board":
|
|
20968
21390
|
return /* @__PURE__ */ jsx(
|
|
@@ -21249,11 +21671,13 @@ function CdlNodeView({
|
|
|
21249
21671
|
case "shape-customer-service":
|
|
21250
21672
|
return /* @__PURE__ */ jsx(ShapeCustomerServiceNode, { node: resolvedNode, active });
|
|
21251
21673
|
case "mark-start":
|
|
21252
|
-
return /* @__PURE__ */ jsx(MarkStartNode, { node: resolvedNode, active });
|
|
21674
|
+
return /* @__PURE__ */ jsx(MarkStartNode, { node: resolvedNode, active, metro: metroDiagram });
|
|
21253
21675
|
case "mark-end":
|
|
21254
|
-
return /* @__PURE__ */ jsx(MarkEndNode, { node: resolvedNode, active });
|
|
21676
|
+
return /* @__PURE__ */ jsx(MarkEndNode, { node: resolvedNode, active, metro: metroDiagram });
|
|
21255
21677
|
case "station":
|
|
21256
|
-
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 });
|
|
21257
21681
|
default:
|
|
21258
21682
|
return /* @__PURE__ */ jsx(
|
|
21259
21683
|
GenericNode,
|
|
@@ -21263,7 +21687,9 @@ function CdlNodeView({
|
|
|
21263
21687
|
value: node.value,
|
|
21264
21688
|
stateValues,
|
|
21265
21689
|
\u5024\u306E\u540D\u524D,
|
|
21266
|
-
textMetrics
|
|
21690
|
+
textMetrics,
|
|
21691
|
+
showKindIcon: !(metroDiagram && node.kind === "decision"),
|
|
21692
|
+
metroDecision
|
|
21267
21693
|
}
|
|
21268
21694
|
);
|
|
21269
21695
|
}
|
|
@@ -21377,6 +21803,112 @@ function \u7BB1\u306E\u4E0A\u306E\u8A9E(node, textMetrics = "proportional") {
|
|
|
21377
21803
|
)
|
|
21378
21804
|
] });
|
|
21379
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
|
+
}
|
|
21380
21912
|
|
|
21381
21913
|
// src/render/relation-focus.ts
|
|
21382
21914
|
function relatedFocusSet(edges, nodeId) {
|
|
@@ -21389,10 +21921,17 @@ function relatedFocusSet(edges, nodeId) {
|
|
|
21389
21921
|
}
|
|
21390
21922
|
return \u96C6\u5408;
|
|
21391
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;
|
|
21392
21928
|
function \u63CF\u304F\u3082\u306E\u304C\u3042\u308B(laid) {
|
|
21929
|
+
if (laid.legend && laid.legend.length > 0) return true;
|
|
21393
21930
|
if (laid.edges.length > 0) return true;
|
|
21394
21931
|
if (laid.nodes.some((n) => isRenderedNode(n))) return true;
|
|
21395
|
-
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
|
+
);
|
|
21396
21935
|
}
|
|
21397
21936
|
function CdlStage({
|
|
21398
21937
|
laid,
|
|
@@ -21433,6 +21972,7 @@ function CdlStage({
|
|
|
21433
21972
|
[\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B, \u7126\u70B9, laid.edges]
|
|
21434
21973
|
);
|
|
21435
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");
|
|
21436
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;
|
|
21437
21977
|
const \u77E2\u5370\u306E\u51FA\u756A = useMemo(() => {
|
|
21438
21978
|
const \u521D\u51FA = /* @__PURE__ */ new Map();
|
|
@@ -21461,9 +22001,15 @@ function CdlStage({
|
|
|
21461
22001
|
const first = \u521D\u51FA.get(edgeId);
|
|
21462
22002
|
if (first === void 0) return false;
|
|
21463
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;
|
|
21464
22009
|
}
|
|
21465
22010
|
};
|
|
21466
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);
|
|
21467
22013
|
const drawSet = new Set(currentPhase?.draw ?? []);
|
|
21468
22014
|
const chartLineScales = useMemo(() => {
|
|
21469
22015
|
const nodes = laid.nodes.filter((node) => node.kind === "chart-line");
|
|
@@ -21551,7 +22097,53 @@ function CdlStage({
|
|
|
21551
22097
|
)
|
|
21552
22098
|
);
|
|
21553
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]);
|
|
21554
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
|
+
}
|
|
21555
22147
|
if (!\u63CF\u304F\u3082\u306E\u304C\u3042\u308B(laid)) return null;
|
|
21556
22148
|
return /* @__PURE__ */ jsxs("div", { className: compact ? "px-3 py-3" : "px-6 py-6", style: compact ? void 0 : { minHeight: 460 }, children: [
|
|
21557
22149
|
/* @__PURE__ */ jsxs(
|
|
@@ -21571,6 +22163,7 @@ function CdlStage({
|
|
|
21571
22163
|
children: [
|
|
21572
22164
|
/* @__PURE__ */ jsxs("defs", { children: [
|
|
21573
22165
|
edgeHeadMarkers,
|
|
22166
|
+
metroReturnArrowMarkers,
|
|
21574
22167
|
/* @__PURE__ */ jsx(
|
|
21575
22168
|
"marker",
|
|
21576
22169
|
{
|
|
@@ -21607,7 +22200,61 @@ function CdlStage({
|
|
|
21607
22200
|
pointerEvents: "none"
|
|
21608
22201
|
}
|
|
21609
22202
|
),
|
|
21610
|
-
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(
|
|
21611
22258
|
"rect",
|
|
21612
22259
|
{
|
|
21613
22260
|
"data-cdl-role": "lane-container",
|
|
@@ -21643,7 +22290,85 @@ function CdlStage({
|
|
|
21643
22290
|
}
|
|
21644
22291
|
);
|
|
21645
22292
|
})(),
|
|
21646
|
-
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(
|
|
21647
22372
|
"text",
|
|
21648
22373
|
{
|
|
21649
22374
|
"data-cdl-role": "lane-label",
|
|
@@ -21660,7 +22385,34 @@ function CdlStage({
|
|
|
21660
22385
|
},
|
|
21661
22386
|
lane.id
|
|
21662
22387
|
)),
|
|
21663
|
-
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(
|
|
21664
22416
|
CdlEdgeView,
|
|
21665
22417
|
{
|
|
21666
22418
|
edge,
|
|
@@ -21668,16 +22420,19 @@ function CdlStage({
|
|
|
21668
22420
|
flowing: \u7126\u70B9\u306E\u96C6\u5408?.has(edge.id) === true && !\u52D5\u304D\u3092\u63A7\u3048\u308B,
|
|
21669
22421
|
drawing: \u77E2\u5370\u306E\u51FA\u756A.\u4F38\u3070\u3059\u304B(edge.id),
|
|
21670
22422
|
progress: \u77E2\u5370\u306E\u51FA\u756A.\u4F38\u3070\u3059\u304B(edge.id) ? \u63CF\u304F\u9032\u307F : progress,
|
|
21671
|
-
stateValues
|
|
22423
|
+
stateValues,
|
|
22424
|
+
pending: edge.routing === "metro" && \u77E2\u5370\u306E\u51FA\u756A.\u307E\u3060\u304B(edge.id)
|
|
21672
22425
|
},
|
|
21673
22426
|
edge.id
|
|
21674
22427
|
)),
|
|
21675
22428
|
laid.nodes.map((node) => {
|
|
21676
22429
|
const \u63CF\u304F = drawSet.has(node.id);
|
|
22430
|
+
const \u6BB5\u968E\u306E\u88DC\u8DB3 = stageNoteNodeIds.has(node.id);
|
|
21677
22431
|
const view = /* @__PURE__ */ jsx(
|
|
21678
22432
|
CdlNodeView,
|
|
21679
22433
|
{
|
|
21680
|
-
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,
|
|
21681
22436
|
active: activeSet.has(node.id),
|
|
21682
22437
|
lang: laid.lang,
|
|
21683
22438
|
textMetrics: laid.textMetrics,
|
|
@@ -21687,13 +22442,32 @@ function CdlStage({
|
|
|
21687
22442
|
stateValues,
|
|
21688
22443
|
\u5024\u306E\u540D\u524D,
|
|
21689
22444
|
currentPhaseId: currentPhase?.id,
|
|
21690
|
-
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)
|
|
21691
22449
|
}
|
|
21692
22450
|
);
|
|
21693
22451
|
return /* @__PURE__ */ jsx("g", { children: view }, node.id);
|
|
21694
22452
|
}),
|
|
21695
|
-
|
|
21696
|
-
|
|
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(
|
|
21697
22471
|
CdlEdgeLabelView,
|
|
21698
22472
|
{
|
|
21699
22473
|
edge,
|
|
@@ -21702,7 +22476,7 @@ function CdlStage({
|
|
|
21702
22476
|
},
|
|
21703
22477
|
`label-${edge.id}`
|
|
21704
22478
|
)),
|
|
21705
|
-
laid.edges.filter((edge) => (edge.headLabel || edge.tailLabel) && \
|
|
22479
|
+
laid.edges.filter((edge) => (edge.headLabel || edge.tailLabel) && \u7DDA\u3092\u63CF\u304F(edge)).flatMap(
|
|
21706
22480
|
(edge) => ["head", "tail"].map((\u7AEF) => /* @__PURE__ */ jsx(
|
|
21707
22481
|
CdlEdgeEndLabelView,
|
|
21708
22482
|
{
|
|
@@ -21714,6 +22488,7 @@ function CdlStage({
|
|
|
21714
22488
|
`${\u7AEF}-label-${edge.id}`
|
|
21715
22489
|
))
|
|
21716
22490
|
),
|
|
22491
|
+
laid.legend && /* @__PURE__ */ jsx(CdlLegend, { items: laid.legend }),
|
|
21717
22492
|
debug && /* @__PURE__ */ jsxs("g", { pointerEvents: "none", children: [
|
|
21718
22493
|
laid.bboxes.map((bbox, idx) => {
|
|
21719
22494
|
const color = bbox.kind === "node" ? "#3b82f6" : bbox.kind === "lane-label" ? "#a855f7" : bbox.kind === "edge-label" ? "#10b981" : "#f59e0b";
|