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