@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.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
3317
|
}
|
|
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
|
-
}
|
|
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);
|
|
@@ -9107,6 +9224,57 @@ function bowSharedStraightPaths(edges, nodes, skipIds, textMetrics = "proportion
|
|
|
9107
9224
|
function nodeRect(n) {
|
|
9108
9225
|
return { x: n.cx - n.w / 2, y: n.cy - n.h / 2, w: n.w, h: n.h };
|
|
9109
9226
|
}
|
|
9227
|
+
function countPathObstacleCrossings(d, obstacles) {
|
|
9228
|
+
const segments = flattenPathSegments(extractPathSegments(d));
|
|
9229
|
+
return obstacles.filter((obstacle) => segmentsCrossRect(segments, nodeRect(obstacle))).length;
|
|
9230
|
+
}
|
|
9231
|
+
function makeBackDetourCandidate(A, B, from, to, obstacles, detourY, side, columnXOverride) {
|
|
9232
|
+
const lowIsA = A.y >= B.y;
|
|
9233
|
+
const low = lowIsA ? A : B;
|
|
9234
|
+
const lowBendY = low.y - VERTICAL_DETOUR_EXIT;
|
|
9235
|
+
const bandTop = Math.min(detourY, lowBendY);
|
|
9236
|
+
const bandBottom = Math.max(detourY, lowBendY);
|
|
9237
|
+
const bandObstacles = obstacles.map(nodeRect).filter((rect) => rect.y + rect.h >= bandTop && rect.y <= bandBottom);
|
|
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
|
+
}
|
|
9247
|
+
}
|
|
9248
|
+
const bendAY = lowIsA ? lowBendY : detourY;
|
|
9249
|
+
const bendBY = lowIsA ? detourY : lowBendY;
|
|
9250
|
+
const vertices = [
|
|
9251
|
+
A,
|
|
9252
|
+
{ x: A.x, y: bendAY },
|
|
9253
|
+
{ x: columnX, y: bendAY },
|
|
9254
|
+
{ x: columnX, y: bendBY },
|
|
9255
|
+
{ x: B.x, y: bendBY },
|
|
9256
|
+
B
|
|
9257
|
+
];
|
|
9258
|
+
const d = verticesToPath(vertices);
|
|
9259
|
+
const high = lowIsA ? B : A;
|
|
9260
|
+
return {
|
|
9261
|
+
d,
|
|
9262
|
+
labelX: (high.x + columnX) / 2,
|
|
9263
|
+
crossings: countPathObstacleCrossings(d, obstacles),
|
|
9264
|
+
length: vertices.slice(1).reduce((sum, vertex, index) => {
|
|
9265
|
+
const previous = vertices[index];
|
|
9266
|
+
return sum + Math.hypot(vertex.x - previous.x, vertex.y - previous.y);
|
|
9267
|
+
}, 0)
|
|
9268
|
+
};
|
|
9269
|
+
}
|
|
9270
|
+
function chooseBackDetourCandidate(A, B, from, to, obstacles, detourY) {
|
|
9271
|
+
const left = makeBackDetourCandidate(A, B, from, to, obstacles, detourY, "left");
|
|
9272
|
+
const right = makeBackDetourCandidate(A, B, from, to, obstacles, detourY, "right");
|
|
9273
|
+
if (left.crossings !== right.crossings) return left.crossings < right.crossings ? left : right;
|
|
9274
|
+
if (Math.abs(left.length - right.length) >= 0.5) return left.length < right.length ? left : right;
|
|
9275
|
+
const preferred = Math.abs(A.x - B.x) < 0.5 ? "right" : A.x < B.x ? "left" : "right";
|
|
9276
|
+
return preferred === "left" ? left : right;
|
|
9277
|
+
}
|
|
9110
9278
|
function rectGap(a, b) {
|
|
9111
9279
|
const dx = Math.max(0, a.x - (b.x + b.w), b.x - (a.x + a.w));
|
|
9112
9280
|
const dy = Math.max(0, a.y - (b.y + b.h), b.y - (a.y + a.h));
|
|
@@ -9184,7 +9352,7 @@ function sidePoint(n, side) {
|
|
|
9184
9352
|
return { x: n.cx + n.w / 2, y: n.cy };
|
|
9185
9353
|
}
|
|
9186
9354
|
}
|
|
9187
|
-
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") {
|
|
9188
9356
|
const labelBoxW = edge ? computeLabelBoxW(edge.label, edge.sub, textMetrics) : 0;
|
|
9189
9357
|
const labelHalfW = labelBoxW / 2;
|
|
9190
9358
|
const labelInit = labelInitClearance(edge);
|
|
@@ -9554,23 +9722,52 @@ function routePath(from, to, fromSide, toSide, obstacles = [], detourSide, _from
|
|
|
9554
9722
|
};
|
|
9555
9723
|
}
|
|
9556
9724
|
if (topTopPair) {
|
|
9557
|
-
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
|
+
);
|
|
9558
9736
|
const corner = 14;
|
|
9559
|
-
const xDir =
|
|
9560
|
-
|
|
9561
|
-
d: `M ${
|
|
9562
|
-
L ${
|
|
9563
|
-
Q ${
|
|
9564
|
-
L ${
|
|
9565
|
-
Q ${
|
|
9566
|
-
L ${
|
|
9567
|
-
labelX: (
|
|
9737
|
+
const xDir = backB.x > backA.x ? 1 : -1;
|
|
9738
|
+
const existing = {
|
|
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,
|
|
9568
9746
|
// CAR-468 SSOT ... 旧 detourY - 30 magic number を LABEL_INIT_CLEARANCE (26、 CAR-570 で 34 → 26 縮小) に置換。
|
|
9569
9747
|
// CAR-518 SSOT ... dotted-flow は 62 world (marker glow radius 分拡張) を labelInit で参照。
|
|
9570
9748
|
// top-top detour の水平 segment 上方 labelInit world = spec 準拠距離。
|
|
9571
9749
|
labelY: detourY - labelInit,
|
|
9572
9750
|
labelAnchor: "middle"
|
|
9573
9751
|
};
|
|
9752
|
+
const existingCrossings = countPathObstacleCrossings(existing.d, obstacles);
|
|
9753
|
+
if (existingCrossings === 0) return existing;
|
|
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);
|
|
9764
|
+
if (candidate.crossings >= existingCrossings) return existing;
|
|
9765
|
+
return {
|
|
9766
|
+
d: candidate.d,
|
|
9767
|
+
labelX: candidate.labelX,
|
|
9768
|
+
labelY: detourY - labelInit,
|
|
9769
|
+
labelAnchor: "middle"
|
|
9770
|
+
};
|
|
9574
9771
|
}
|
|
9575
9772
|
const midX = fromSide === "left" || fromSide === "right" ? B.x : A.x;
|
|
9576
9773
|
const midY = fromSide === "top" || fromSide === "bottom" ? B.y : A.y;
|
|
@@ -10497,12 +10694,56 @@ function \u76F4\u524D\u306E\u6298\u308C\u3054\u3068\u305A\u3089\u3059(segs, \u6A
|
|
|
10497
10694
|
return parts.join(" ");
|
|
10498
10695
|
}
|
|
10499
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
|
+
|
|
10500
10730
|
// src/layout/lanes.ts
|
|
10501
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
|
+
}
|
|
10502
10743
|
function layoutLanes(diag) {
|
|
10503
10744
|
const laneGap = diag.viewport?.laneGap ?? diag.viewport?.gap ?? DEFAULT_LANE_GAP;
|
|
10504
10745
|
let cursorX = 0;
|
|
10505
|
-
|
|
10746
|
+
const lanes = diag.lanes.map((lane, index) => {
|
|
10506
10747
|
if (lane.posX !== void 0 && lane.posY !== void 0) {
|
|
10507
10748
|
return {
|
|
10508
10749
|
...lane,
|
|
@@ -10513,7 +10754,9 @@ function layoutLanes(diag) {
|
|
|
10513
10754
|
};
|
|
10514
10755
|
}
|
|
10515
10756
|
const resolvedX = lane.x ?? cursorX;
|
|
10516
|
-
|
|
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;
|
|
10517
10760
|
return {
|
|
10518
10761
|
...lane,
|
|
10519
10762
|
x: resolvedX,
|
|
@@ -10521,6 +10764,7 @@ function layoutLanes(diag) {
|
|
|
10521
10764
|
height: LANE_LABEL_H
|
|
10522
10765
|
};
|
|
10523
10766
|
});
|
|
10767
|
+
return equalizeStageColumns(lanes);
|
|
10524
10768
|
}
|
|
10525
10769
|
function expandLanesForNodes(lanes, nodes) {
|
|
10526
10770
|
const targetNodeGap = targetNodeNodeClearance();
|
|
@@ -10549,7 +10793,8 @@ function expandLanesForNodes(lanes, nodes) {
|
|
|
10549
10793
|
if (lane.posX !== void 0 && lane.posY !== void 0) continue;
|
|
10550
10794
|
const inside = nodes.filter((n) => n.lane === lane.id);
|
|
10551
10795
|
const maxNodeW = inside.length > 0 ? Math.max(...inside.map((n) => n.w)) : 0;
|
|
10552
|
-
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);
|
|
10553
10798
|
widthOf.set(lane.id, newWidth);
|
|
10554
10799
|
deltaOf.set(lane.id, newWidth - lane.width);
|
|
10555
10800
|
}
|
|
@@ -10574,6 +10819,34 @@ function expandLaneGapsForEdgeLabels(lanes, nodes, edges, textMetrics = "proport
|
|
|
10574
10819
|
if (lanes.length < 2) return lanes;
|
|
10575
10820
|
const layoutedLanes = lanes.filter((l) => !(l.posX !== void 0 && l.posY !== void 0));
|
|
10576
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
|
+
}
|
|
10577
10850
|
const nodeById = new Map(nodes.map((n) => [n.id, n]));
|
|
10578
10851
|
const sortedByX = [...layoutedLanes].sort((a, b) => a.x - b.x);
|
|
10579
10852
|
const laneIndexById = new Map(sortedByX.map((lane, i) => [lane.id, i]));
|
|
@@ -10645,7 +10918,7 @@ function recomputeContainedLanes(lanes, nodes) {
|
|
|
10645
10918
|
lifelineBottom = Math.max(lifelineBottom, bottom);
|
|
10646
10919
|
}
|
|
10647
10920
|
}
|
|
10648
|
-
|
|
10921
|
+
const contained = lanes.map((lane) => {
|
|
10649
10922
|
if (lane.lifeline) {
|
|
10650
10923
|
return {
|
|
10651
10924
|
...lane,
|
|
@@ -10663,6 +10936,7 @@ function recomputeContainedLanes(lanes, nodes) {
|
|
|
10663
10936
|
height: bottom - top + CONTAIN_PAD * 2 + LANE_LABEL_H
|
|
10664
10937
|
};
|
|
10665
10938
|
});
|
|
10939
|
+
return equalizeStageColumns(contained, nodes);
|
|
10666
10940
|
}
|
|
10667
10941
|
|
|
10668
10942
|
// src/layout/head-label.ts
|
|
@@ -10812,11 +11086,15 @@ function requiredStackGapForEdgeLabels(diag, allStacks) {
|
|
|
10812
11086
|
}
|
|
10813
11087
|
function layoutNodes(diag, lanes, textMetrics) {
|
|
10814
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];
|
|
10815
11093
|
const allStacks = Array.from(new Set(diag.nodes.map((n) => n.stack))).sort((a, b) => a - b);
|
|
10816
11094
|
const rowH = /* @__PURE__ */ new Map();
|
|
10817
11095
|
for (const stack of allStacks) {
|
|
10818
11096
|
const nodesAtStack = diag.nodes.filter((n) => n.stack === stack);
|
|
10819
|
-
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)));
|
|
10820
11098
|
rowH.set(stack, h);
|
|
10821
11099
|
}
|
|
10822
11100
|
const rowCy = /* @__PURE__ */ new Map();
|
|
@@ -10852,7 +11130,7 @@ function layoutNodes(diag, lanes, textMetrics) {
|
|
|
10852
11130
|
if (!lane) {
|
|
10853
11131
|
throw new Error(`cdl layout: node "${n.id}" \u306E lane "${n.lane}" \u304C\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u306A\u3044`);
|
|
10854
11132
|
}
|
|
10855
|
-
const size =
|
|
11133
|
+
const size = nodeSize(n);
|
|
10856
11134
|
if (n.posX !== void 0 && n.posY !== void 0) {
|
|
10857
11135
|
const w2 = n.posW ?? n.w ?? autoRowsWidth(n, size.w, textMetrics);
|
|
10858
11136
|
const h2 = n.posH ?? n.h ?? rowH.get(n.stack) ?? size.h;
|
|
@@ -10975,6 +11253,9 @@ function dropUnsafeLaneDx(dxByLane, nodes) {
|
|
|
10975
11253
|
function applyRowLevelNodeShifts(nodes, lanes, nodeShifts) {
|
|
10976
11254
|
const dyByStack = aggregateRowDy(nodes, nodeShifts);
|
|
10977
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
|
+
}
|
|
10978
11259
|
let moved = false;
|
|
10979
11260
|
const outNodes = nodes.map((n) => {
|
|
10980
11261
|
const dx = dxByLane.get(n.lane) ?? 0;
|
|
@@ -11094,7 +11375,15 @@ function layout(diag) {
|
|
|
11094
11375
|
);
|
|
11095
11376
|
}
|
|
11096
11377
|
}
|
|
11097
|
-
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;
|
|
11098
11387
|
return {
|
|
11099
11388
|
id: diag.id,
|
|
11100
11389
|
topic: diag.topic,
|
|
@@ -11121,6 +11410,7 @@ function layout(diag) {
|
|
|
11121
11410
|
...textMetrics === "monospace" ? { textMetrics: "monospace" } : {},
|
|
11122
11411
|
// 種類も配色と同じく空の目印を出さない。 遮断をここに揃えると手書きの図にも効く
|
|
11123
11412
|
...diag.type ? { type: diag.type } : {},
|
|
11413
|
+
...legendLayout ? { legend: legendLayout.legend } : {},
|
|
11124
11414
|
bboxes,
|
|
11125
11415
|
collisions,
|
|
11126
11416
|
nearCollisions,
|
|
@@ -11309,6 +11599,11 @@ function validate(diag) {
|
|
|
11309
11599
|
\u2192 \u4FEE\u6B63\u4F8B: .lane("${n.lane}", { x: 0, width: 400 }) \u3092 node \u5BA3\u8A00\u524D\u306B\u8FFD\u52A0`
|
|
11310
11600
|
);
|
|
11311
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
|
+
}
|
|
11312
11607
|
}
|
|
11313
11608
|
for (const e of diag.edges) {
|
|
11314
11609
|
if (!nodeIds.has(e.from)) {
|
|
@@ -11927,6 +12222,10 @@ function uniformLifelineEndY(lanes, nodes, starts = lifelineStartYs(nodes)) {
|
|
|
11927
12222
|
|
|
11928
12223
|
// src/render/edge-head.ts
|
|
11929
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
|
+
}
|
|
11930
12229
|
var EDGE_HEAD_SHAPE = {
|
|
11931
12230
|
// 何も描かない端。 marker 自体を出さないので `d` は読まれない
|
|
11932
12231
|
none: { d: "", w: 10, h: 10, refX: 0, filled: false },
|
|
@@ -11981,6 +12280,7 @@ function \u7B49\u5E45\u306E\u5B57(text, fontSize) {
|
|
|
11981
12280
|
});
|
|
11982
12281
|
return out;
|
|
11983
12282
|
}
|
|
12283
|
+
var METRO_PENDING_ATTRIBUTE = "data-cdl-pending";
|
|
11984
12284
|
function defaultEdgeWidth(active) {
|
|
11985
12285
|
return active ? 2.5 : 1.25;
|
|
11986
12286
|
}
|
|
@@ -11999,12 +12299,14 @@ function CdlEdgeView({
|
|
|
11999
12299
|
drawing,
|
|
12000
12300
|
progress,
|
|
12001
12301
|
stateValues,
|
|
12002
|
-
flowing = false
|
|
12302
|
+
flowing = false,
|
|
12303
|
+
pending = false
|
|
12003
12304
|
}) {
|
|
12004
12305
|
const color = edgeColor(edge);
|
|
12005
|
-
const marker = edgeHeadMarkerName(edge.tone, edge.head, !active, edge.headFill);
|
|
12006
|
-
const tailMarker = edge.tailHead === void 0 ? void 0 : edgeHeadMarkerName(edge.tone, edge.tailHead, !active, edge.tailHeadFill);
|
|
12007
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);
|
|
12008
12310
|
const isDotted = style === "dotted-flow";
|
|
12009
12311
|
const isPassThrough = isDotted && Boolean(edge.dThrough);
|
|
12010
12312
|
const lineDotsD = isDotted ? shrinkPathEnd(edge.d, 12) : edge.d;
|
|
@@ -12014,6 +12316,7 @@ function CdlEdgeView({
|
|
|
12014
12316
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12015
12317
|
"g",
|
|
12016
12318
|
{
|
|
12319
|
+
...pending ? { [METRO_PENDING_ATTRIBUTE]: "true" } : {},
|
|
12017
12320
|
"data-cdl-edge": edge.id,
|
|
12018
12321
|
"data-cdl-routing": edge.routing === "metro" ? "metro" : void 0,
|
|
12019
12322
|
"data-cdl-from": edge.from,
|
|
@@ -12039,11 +12342,12 @@ function CdlEdgeView({
|
|
|
12039
12342
|
fill: "none",
|
|
12040
12343
|
stroke: color,
|
|
12041
12344
|
strokeOpacity: active ? 0.95 : 0.9,
|
|
12042
|
-
strokeWidth: active ? 5 : 4,
|
|
12345
|
+
strokeWidth: edge.routing === "metro" ? METRO_LINE_WIDTH : active ? 5 : 4,
|
|
12043
12346
|
strokeDasharray: "0 18",
|
|
12044
12347
|
strokeLinecap: "round",
|
|
12045
12348
|
style: {
|
|
12046
|
-
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
|
|
12047
12351
|
}
|
|
12048
12352
|
}
|
|
12049
12353
|
),
|
|
@@ -12098,7 +12402,9 @@ function SolidEdgePath({
|
|
|
12098
12402
|
const boundWidth = edge.widthBind && stateValues ? resolveNumericAttr(edge.widthBind, stateValues, defaultWidth) : defaultWidth;
|
|
12099
12403
|
const boundStroke = edge.strokeBind && stateValues ? interpolate(edge.strokeBind, stateValues) : color;
|
|
12100
12404
|
const boundDashOffset = edge.dashOffsetBind && stateValues ? resolveNumericAttr(edge.dashOffsetBind, stateValues, 0) : void 0;
|
|
12101
|
-
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";
|
|
12102
12408
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12103
12409
|
"path",
|
|
12104
12410
|
{
|
|
@@ -12107,14 +12413,15 @@ function SolidEdgePath({
|
|
|
12107
12413
|
fill: "none",
|
|
12108
12414
|
stroke: boundStroke,
|
|
12109
12415
|
strokeOpacity: active ? 0.95 : 0.9,
|
|
12110
|
-
strokeWidth
|
|
12416
|
+
strokeWidth,
|
|
12111
12417
|
strokeDasharray: dashArray,
|
|
12112
12418
|
strokeDashoffset: boundDashOffset,
|
|
12113
12419
|
strokeLinecap: "round",
|
|
12114
12420
|
markerEnd: marker === void 0 ? void 0 : `url(#${marker})`,
|
|
12115
12421
|
markerStart: tailMarker === void 0 ? void 0 : `url(#${tailMarker})`,
|
|
12116
12422
|
style: {
|
|
12117
|
-
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
|
|
12118
12425
|
}
|
|
12119
12426
|
}
|
|
12120
12427
|
);
|
|
@@ -12411,7 +12718,11 @@ function \u5272\u308B\u5019\u88DC(text) {
|
|
|
12411
12718
|
function \u5165\u3063\u3066\u3044\u308B([\u5DE6, \u53F3]) {
|
|
12412
12719
|
return \u5DE6 !== "" && \u53F3 !== "";
|
|
12413
12720
|
}
|
|
12414
|
-
function CardNode({
|
|
12721
|
+
function CardNode({
|
|
12722
|
+
node,
|
|
12723
|
+
active,
|
|
12724
|
+
compactTitleInset
|
|
12725
|
+
}) {
|
|
12415
12726
|
const accent = nodeAccent(node, "var(--cdl-tone-accent, #2d6a8f)");
|
|
12416
12727
|
const x = node.cx - node.w / 2;
|
|
12417
12728
|
const y = node.cy - node.h / 2;
|
|
@@ -12429,12 +12740,12 @@ function CardNode({ node, active }) {
|
|
|
12429
12740
|
});
|
|
12430
12741
|
const \u305A\u3089\u3057 = \u7E70\u308A\u4E0A\u3052 - \u4F59\u308A;
|
|
12431
12742
|
const titleY = compact ? \u5C0F\u578B\u306B\u547C\u3073\u540D ? node.h / 2 - 2 : node.h / 2 + 8 : 86 - \u305A\u3089\u3057;
|
|
12432
|
-
const titleX = compact ? node.w / 2 : 26;
|
|
12433
|
-
const paddingX = compact ?
|
|
12743
|
+
const titleX = compact ? compactTitleInset ?? node.w / 2 : 26;
|
|
12744
|
+
const paddingX = compact ? (compactTitleInset ?? 8) * 2 : 52;
|
|
12434
12745
|
const availableW = node.w - paddingX;
|
|
12435
12746
|
const initialTitleSize = compact ? 20 : 24;
|
|
12436
12747
|
const titleSize = fitTextSize(node.title, availableW, initialTitleSize, 11);
|
|
12437
|
-
const textAnchor = compact ? "middle" : "start";
|
|
12748
|
+
const textAnchor = compact && compactTitleInset === void 0 ? "middle" : "start";
|
|
12438
12749
|
const subtitleY = 124 - \u305A\u3089\u3057;
|
|
12439
12750
|
const \u6700\u5927\u306E\u884C\u9001\u308A = SUBTITLE_SIZE * \u884C\u9001\u308A\u306E\u500D\u7387;
|
|
12440
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;
|
|
@@ -13194,7 +13505,9 @@ function GenericNode({
|
|
|
13194
13505
|
value,
|
|
13195
13506
|
stateValues,
|
|
13196
13507
|
\u5024\u306E\u540D\u524D,
|
|
13197
|
-
textMetrics = "proportional"
|
|
13508
|
+
textMetrics = "proportional",
|
|
13509
|
+
showKindIcon = true,
|
|
13510
|
+
metroDecision = false
|
|
13198
13511
|
}) {
|
|
13199
13512
|
const base = STYLES[node.kind] ?? FALLBACK;
|
|
13200
13513
|
const toned = toneColor3(node.tone);
|
|
@@ -13225,14 +13538,14 @@ function GenericNode({
|
|
|
13225
13538
|
if (shape === "diamond") {
|
|
13226
13539
|
const cx = w / 2;
|
|
13227
13540
|
const cy = h / 2;
|
|
13228
|
-
const pad = 8;
|
|
13541
|
+
const pad = metroDecision ? 0 : 8;
|
|
13229
13542
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13230
13543
|
"path",
|
|
13231
13544
|
{
|
|
13232
13545
|
d: `M ${cx} ${pad} L ${w - pad} ${cy} L ${cx} ${h - pad} L ${pad} ${cy} Z`,
|
|
13233
13546
|
fill: "var(--cdl-node-fill, #ffffff)",
|
|
13234
13547
|
stroke: active ? style.accent : "var(--cdl-divider, #d4d4d8)",
|
|
13235
|
-
strokeWidth: active ? 3 : 1.25
|
|
13548
|
+
strokeWidth: metroDecision ? 1.5 : active ? 3 : 1.25
|
|
13236
13549
|
}
|
|
13237
13550
|
);
|
|
13238
13551
|
}
|
|
@@ -13296,11 +13609,11 @@ function GenericNode({
|
|
|
13296
13609
|
const \u305A\u3089\u3057 = \u7E70\u308A\u4E0A\u3052 - \u4F59\u308A;
|
|
13297
13610
|
const \u7D75\u306E\u82AF = centered && STYLES[node.kind]?.shape === "cloud" ? h * CLOUD_ART_CENTER_RISE : 0;
|
|
13298
13611
|
const eyebrowY = centered ? h / 2 - 26 - \u7D75\u306E\u82AF : 32 + cylinderShift + \u4F59\u308A;
|
|
13299
|
-
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;
|
|
13300
13613
|
const subtitleY = centered ? h / 2 + 28 - \u7D75\u306E\u82AF : 96 + cylinderShift - \u305A\u3089\u3057;
|
|
13301
13614
|
const iconX = centered ? w / 2 + 40 : w - 48;
|
|
13302
13615
|
const iconY = centered ? h / 2 - 44 - \u7D75\u306E\u82AF : 18 + cylinderShift;
|
|
13303
|
-
const dominantBaseline = centered ? "middle" : void 0;
|
|
13616
|
+
const dominantBaseline = centered && !metroDecision ? "middle" : void 0;
|
|
13304
13617
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
13305
13618
|
"g",
|
|
13306
13619
|
{
|
|
@@ -13309,12 +13622,12 @@ function GenericNode({
|
|
|
13309
13622
|
"data-cdl-look": style.look,
|
|
13310
13623
|
children: [
|
|
13311
13624
|
shapeEl,
|
|
13312
|
-
/* @__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: [
|
|
13313
13626
|
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: 24, height: 24, fill: "transparent" }),
|
|
13314
13627
|
/* @__PURE__ */ jsxRuntime.jsx("path", { d: style.icon, fill: style.eyebrowColor, opacity: 0.7, transform: "scale(1)" })
|
|
13315
13628
|
] }),
|
|
13316
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 }),
|
|
13317
|
-
/* @__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 }),
|
|
13318
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) }),
|
|
13319
13632
|
resolvedValue && /* @__PURE__ */ jsxRuntime.jsx(
|
|
13320
13633
|
"text",
|
|
@@ -13363,50 +13676,176 @@ function GenericNode({
|
|
|
13363
13676
|
var MARK_INNER_RATIO = 0.56;
|
|
13364
13677
|
var RING_WIDTH_ACTIVE = 6;
|
|
13365
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;
|
|
13366
13683
|
var MARK_DEFAULT = "var(--cdl-tone-accent, #2d6a8f)";
|
|
13367
13684
|
function markRadius(node) {
|
|
13368
13685
|
return Math.min(node.w, node.h) / 2;
|
|
13369
13686
|
}
|
|
13370
|
-
function MarkStartNode({
|
|
13687
|
+
function MarkStartNode({
|
|
13688
|
+
node,
|
|
13689
|
+
metro = false
|
|
13690
|
+
}) {
|
|
13371
13691
|
const \u8272 = nodeAccent(node, MARK_DEFAULT);
|
|
13372
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13373
|
-
"
|
|
13692
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13693
|
+
"g",
|
|
13374
13694
|
{
|
|
13375
|
-
"data-cdl-role": "
|
|
13376
|
-
|
|
13377
|
-
|
|
13378
|
-
|
|
13379
|
-
|
|
13380
|
-
|
|
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
|
+
)
|
|
13381
13708
|
}
|
|
13382
|
-
)
|
|
13709
|
+
);
|
|
13383
13710
|
}
|
|
13384
|
-
function MarkEndNode({
|
|
13711
|
+
function MarkEndNode({
|
|
13712
|
+
node,
|
|
13713
|
+
active,
|
|
13714
|
+
metro = false
|
|
13715
|
+
}) {
|
|
13385
13716
|
const \u8272 = nodeAccent(node, MARK_DEFAULT);
|
|
13386
|
-
const r = markRadius(node);
|
|
13387
|
-
const \u8F2A\u306E\u592A\u3055 = active ? RING_WIDTH_ACTIVE : RING_WIDTH_IDLE;
|
|
13388
|
-
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: [
|
|
13389
13770
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13390
13771
|
"circle",
|
|
13391
13772
|
{
|
|
13392
13773
|
"data-cdl-role": "node-body",
|
|
13393
|
-
"data-cdl-mark": "
|
|
13394
|
-
cx: node.
|
|
13395
|
-
cy: node.
|
|
13396
|
-
r:
|
|
13774
|
+
"data-cdl-mark": "station",
|
|
13775
|
+
cx: node.cx,
|
|
13776
|
+
cy: node.cy,
|
|
13777
|
+
r: METRO_STATION_RADIUS,
|
|
13397
13778
|
fill: "var(--cdl-node-fill, #ffffff)",
|
|
13398
|
-
stroke:
|
|
13399
|
-
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 }
|
|
13400
13782
|
}
|
|
13401
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
|
|
13799
|
+
}
|
|
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: [
|
|
13402
13824
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13403
13825
|
"circle",
|
|
13404
13826
|
{
|
|
13405
|
-
"data-cdl-role": "node-
|
|
13406
|
-
|
|
13407
|
-
|
|
13408
|
-
|
|
13409
|
-
|
|
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
|
|
13410
13849
|
}
|
|
13411
13850
|
)
|
|
13412
13851
|
] });
|
|
@@ -13738,27 +14177,6 @@ function interpolateColor(template, stateValues, fallback) {
|
|
|
13738
14177
|
if (!template) return fallback;
|
|
13739
14178
|
return interpolate(template, stateValues);
|
|
13740
14179
|
}
|
|
13741
|
-
var STATION_STROKE_ACTIVE = 4;
|
|
13742
|
-
var STATION_STROKE_IDLE = 3;
|
|
13743
|
-
var STATION_DEFAULT = "var(--cdl-tone-accent, #2d6a8f)";
|
|
13744
|
-
function StationNode({ node, active }) {
|
|
13745
|
-
const strokeWidth = active ? STATION_STROKE_ACTIVE : STATION_STROKE_IDLE;
|
|
13746
|
-
const radius = Math.max(0, Math.min(node.w, node.h) / 2 - strokeWidth / 2);
|
|
13747
|
-
const \u5F62 = /* @__PURE__ */ jsxRuntime.jsx(
|
|
13748
|
-
"circle",
|
|
13749
|
-
{
|
|
13750
|
-
"data-cdl-role": "node-body",
|
|
13751
|
-
"data-cdl-mark": "station",
|
|
13752
|
-
cx: node.cx,
|
|
13753
|
-
cy: node.cy,
|
|
13754
|
-
r: radius,
|
|
13755
|
-
fill: "var(--cdl-node-fill, #ffffff)",
|
|
13756
|
-
stroke: nodeAccent(node, STATION_DEFAULT),
|
|
13757
|
-
strokeWidth
|
|
13758
|
-
}
|
|
13759
|
-
);
|
|
13760
|
-
return renderShapeWithOutsideLabels(\u5F62, node, "middle");
|
|
13761
|
-
}
|
|
13762
14180
|
|
|
13763
14181
|
// src/kinds/label-stack.ts
|
|
13764
14182
|
function \u540D\u672D\u306E\u6BB5\u3092\u307B\u3069\u304F(\u771F\u306Ey, \u9593\u9694, \u4E0A\u9650, \u4E0B\u9650) {
|
|
@@ -20920,10 +21338,14 @@ function CdlNodeView({
|
|
|
20920
21338
|
stateValues,
|
|
20921
21339
|
currentPhaseId,
|
|
20922
21340
|
chartLineScale,
|
|
21341
|
+
compactTitleInset,
|
|
20923
21342
|
\u95A2\u4FC2\u306E\u53D7\u3051\u53E3,
|
|
20924
21343
|
lang,
|
|
20925
21344
|
textMetrics,
|
|
20926
|
-
\u5024\u306E\u540D\u524D
|
|
21345
|
+
\u5024\u306E\u540D\u524D,
|
|
21346
|
+
metroDiagram = false,
|
|
21347
|
+
metroDecision = false,
|
|
21348
|
+
stationNameRight = false
|
|
20927
21349
|
}) {
|
|
20928
21350
|
const value = node.value ? interpolate(node.value, stateValues, \u5024\u306E\u540D\u524D) : void 0;
|
|
20929
21351
|
const rows = (node.rows ?? []).map((r) => interpolate(r, stateValues, \u5024\u306E\u540D\u524D));
|
|
@@ -20964,7 +21386,7 @@ function CdlNodeView({
|
|
|
20964
21386
|
case "event":
|
|
20965
21387
|
return /* @__PURE__ */ jsxRuntime.jsx(EventNode, { node: resolvedNode, active, progress });
|
|
20966
21388
|
case "card":
|
|
20967
|
-
return /* @__PURE__ */ jsxRuntime.jsx(CardNode, { node: resolvedNode, active });
|
|
21389
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CardNode, { node: resolvedNode, active, compactTitleInset });
|
|
20968
21390
|
// 時系列のやり取り (#578)。 1 つの箱が図を丸ごと描く = 縦が時間で、参加者は箱を持たない
|
|
20969
21391
|
case "sequence-board":
|
|
20970
21392
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -21251,11 +21673,13 @@ function CdlNodeView({
|
|
|
21251
21673
|
case "shape-customer-service":
|
|
21252
21674
|
return /* @__PURE__ */ jsxRuntime.jsx(ShapeCustomerServiceNode, { node: resolvedNode, active });
|
|
21253
21675
|
case "mark-start":
|
|
21254
|
-
return /* @__PURE__ */ jsxRuntime.jsx(MarkStartNode, { node: resolvedNode, active });
|
|
21676
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MarkStartNode, { node: resolvedNode, active, metro: metroDiagram });
|
|
21255
21677
|
case "mark-end":
|
|
21256
|
-
return /* @__PURE__ */ jsxRuntime.jsx(MarkEndNode, { node: resolvedNode, active });
|
|
21678
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MarkEndNode, { node: resolvedNode, active, metro: metroDiagram });
|
|
21257
21679
|
case "station":
|
|
21258
|
-
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 });
|
|
21259
21683
|
default:
|
|
21260
21684
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
21261
21685
|
GenericNode,
|
|
@@ -21265,7 +21689,9 @@ function CdlNodeView({
|
|
|
21265
21689
|
value: node.value,
|
|
21266
21690
|
stateValues,
|
|
21267
21691
|
\u5024\u306E\u540D\u524D,
|
|
21268
|
-
textMetrics
|
|
21692
|
+
textMetrics,
|
|
21693
|
+
showKindIcon: !(metroDiagram && node.kind === "decision"),
|
|
21694
|
+
metroDecision
|
|
21269
21695
|
}
|
|
21270
21696
|
);
|
|
21271
21697
|
}
|
|
@@ -21379,6 +21805,112 @@ function \u7BB1\u306E\u4E0A\u306E\u8A9E(node, textMetrics = "proportional") {
|
|
|
21379
21805
|
)
|
|
21380
21806
|
] });
|
|
21381
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
|
+
}
|
|
21382
21914
|
|
|
21383
21915
|
// src/render/relation-focus.ts
|
|
21384
21916
|
function relatedFocusSet(edges, nodeId) {
|
|
@@ -21391,10 +21923,17 @@ function relatedFocusSet(edges, nodeId) {
|
|
|
21391
21923
|
}
|
|
21392
21924
|
return \u96C6\u5408;
|
|
21393
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;
|
|
21394
21930
|
function \u63CF\u304F\u3082\u306E\u304C\u3042\u308B(laid) {
|
|
21931
|
+
if (laid.legend && laid.legend.length > 0) return true;
|
|
21395
21932
|
if (laid.edges.length > 0) return true;
|
|
21396
21933
|
if (laid.nodes.some((n) => isRenderedNode(n))) return true;
|
|
21397
|
-
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
|
+
);
|
|
21398
21937
|
}
|
|
21399
21938
|
function CdlStage({
|
|
21400
21939
|
laid,
|
|
@@ -21435,6 +21974,7 @@ function CdlStage({
|
|
|
21435
21974
|
[\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B, \u7126\u70B9, laid.edges]
|
|
21436
21975
|
);
|
|
21437
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");
|
|
21438
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;
|
|
21439
21979
|
const \u77E2\u5370\u306E\u51FA\u756A = react.useMemo(() => {
|
|
21440
21980
|
const \u521D\u51FA = /* @__PURE__ */ new Map();
|
|
@@ -21463,9 +22003,15 @@ function CdlStage({
|
|
|
21463
22003
|
const first = \u521D\u51FA.get(edgeId);
|
|
21464
22004
|
if (first === void 0) return false;
|
|
21465
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;
|
|
21466
22011
|
}
|
|
21467
22012
|
};
|
|
21468
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);
|
|
21469
22015
|
const drawSet = new Set(currentPhase?.draw ?? []);
|
|
21470
22016
|
const chartLineScales = react.useMemo(() => {
|
|
21471
22017
|
const nodes = laid.nodes.filter((node) => node.kind === "chart-line");
|
|
@@ -21553,7 +22099,53 @@ function CdlStage({
|
|
|
21553
22099
|
)
|
|
21554
22100
|
);
|
|
21555
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]);
|
|
21556
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
|
+
}
|
|
21557
22149
|
if (!\u63CF\u304F\u3082\u306E\u304C\u3042\u308B(laid)) return null;
|
|
21558
22150
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: compact ? "px-3 py-3" : "px-6 py-6", style: compact ? void 0 : { minHeight: 460 }, children: [
|
|
21559
22151
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -21573,6 +22165,7 @@ function CdlStage({
|
|
|
21573
22165
|
children: [
|
|
21574
22166
|
/* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
|
|
21575
22167
|
edgeHeadMarkers,
|
|
22168
|
+
metroReturnArrowMarkers,
|
|
21576
22169
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
21577
22170
|
"marker",
|
|
21578
22171
|
{
|
|
@@ -21609,7 +22202,61 @@ function CdlStage({
|
|
|
21609
22202
|
pointerEvents: "none"
|
|
21610
22203
|
}
|
|
21611
22204
|
),
|
|
21612
|
-
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(
|
|
21613
22260
|
"rect",
|
|
21614
22261
|
{
|
|
21615
22262
|
"data-cdl-role": "lane-container",
|
|
@@ -21645,7 +22292,85 @@ function CdlStage({
|
|
|
21645
22292
|
}
|
|
21646
22293
|
);
|
|
21647
22294
|
})(),
|
|
21648
|
-
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(
|
|
21649
22374
|
"text",
|
|
21650
22375
|
{
|
|
21651
22376
|
"data-cdl-role": "lane-label",
|
|
@@ -21662,7 +22387,34 @@ function CdlStage({
|
|
|
21662
22387
|
},
|
|
21663
22388
|
lane.id
|
|
21664
22389
|
)),
|
|
21665
|
-
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(
|
|
21666
22418
|
CdlEdgeView,
|
|
21667
22419
|
{
|
|
21668
22420
|
edge,
|
|
@@ -21670,16 +22422,19 @@ function CdlStage({
|
|
|
21670
22422
|
flowing: \u7126\u70B9\u306E\u96C6\u5408?.has(edge.id) === true && !\u52D5\u304D\u3092\u63A7\u3048\u308B,
|
|
21671
22423
|
drawing: \u77E2\u5370\u306E\u51FA\u756A.\u4F38\u3070\u3059\u304B(edge.id),
|
|
21672
22424
|
progress: \u77E2\u5370\u306E\u51FA\u756A.\u4F38\u3070\u3059\u304B(edge.id) ? \u63CF\u304F\u9032\u307F : progress,
|
|
21673
|
-
stateValues
|
|
22425
|
+
stateValues,
|
|
22426
|
+
pending: edge.routing === "metro" && \u77E2\u5370\u306E\u51FA\u756A.\u307E\u3060\u304B(edge.id)
|
|
21674
22427
|
},
|
|
21675
22428
|
edge.id
|
|
21676
22429
|
)),
|
|
21677
22430
|
laid.nodes.map((node) => {
|
|
21678
22431
|
const \u63CF\u304F = drawSet.has(node.id);
|
|
22432
|
+
const \u6BB5\u968E\u306E\u88DC\u8DB3 = stageNoteNodeIds.has(node.id);
|
|
21679
22433
|
const view = /* @__PURE__ */ jsxRuntime.jsx(
|
|
21680
22434
|
CdlNodeView,
|
|
21681
22435
|
{
|
|
21682
|
-
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,
|
|
21683
22438
|
active: activeSet.has(node.id),
|
|
21684
22439
|
lang: laid.lang,
|
|
21685
22440
|
textMetrics: laid.textMetrics,
|
|
@@ -21689,13 +22444,32 @@ function CdlStage({
|
|
|
21689
22444
|
stateValues,
|
|
21690
22445
|
\u5024\u306E\u540D\u524D,
|
|
21691
22446
|
currentPhaseId: currentPhase?.id,
|
|
21692
|
-
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)
|
|
21693
22451
|
}
|
|
21694
22452
|
);
|
|
21695
22453
|
return /* @__PURE__ */ jsxRuntime.jsx("g", { children: view }, node.id);
|
|
21696
22454
|
}),
|
|
21697
|
-
|
|
21698
|
-
|
|
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(
|
|
21699
22473
|
CdlEdgeLabelView,
|
|
21700
22474
|
{
|
|
21701
22475
|
edge,
|
|
@@ -21704,7 +22478,7 @@ function CdlStage({
|
|
|
21704
22478
|
},
|
|
21705
22479
|
`label-${edge.id}`
|
|
21706
22480
|
)),
|
|
21707
|
-
laid.edges.filter((edge) => (edge.headLabel || edge.tailLabel) && \
|
|
22481
|
+
laid.edges.filter((edge) => (edge.headLabel || edge.tailLabel) && \u7DDA\u3092\u63CF\u304F(edge)).flatMap(
|
|
21708
22482
|
(edge) => ["head", "tail"].map((\u7AEF) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
21709
22483
|
CdlEdgeEndLabelView,
|
|
21710
22484
|
{
|
|
@@ -21716,6 +22490,7 @@ function CdlStage({
|
|
|
21716
22490
|
`${\u7AEF}-label-${edge.id}`
|
|
21717
22491
|
))
|
|
21718
22492
|
),
|
|
22493
|
+
laid.legend && /* @__PURE__ */ jsxRuntime.jsx(CdlLegend, { items: laid.legend }),
|
|
21719
22494
|
debug && /* @__PURE__ */ jsxRuntime.jsxs("g", { pointerEvents: "none", children: [
|
|
21720
22495
|
laid.bboxes.map((bbox, idx) => {
|
|
21721
22496
|
const color = bbox.kind === "node" ? "#3b82f6" : bbox.kind === "lane-label" ? "#a855f7" : bbox.kind === "edge-label" ? "#10b981" : "#f59e0b";
|