@cardenelabs/cdl 0.120.0 → 0.122.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 +75 -1
- package/README.md +73 -0
- package/SPEC.md +1 -1
- package/dist/index.cjs +470 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -10
- package/dist/index.d.ts +16 -10
- package/dist/index.js +470 -70
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +459 -61
- 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 +459 -61
- package/dist/react.js.map +1 -1
- package/dist/{render-A5AKjNuy.d.cts → render-U_pC-Ksh.d.cts} +21 -6
- package/dist/{render-A5AKjNuy.d.ts → render-U_pC-Ksh.d.ts} +21 -6
- package/package.json +1 -1
- package/src/builder.ts +3 -2
- package/src/index.ts +1 -0
- package/src/kinds/dyn-shape.tsx +22 -9
- package/src/kinds/station.tsx +29 -0
- package/src/layout/collisions.ts +29 -20
- package/src/layout/curve-path.ts +125 -0
- package/src/layout/edges.ts +207 -39
- package/src/layout/head-label.ts +26 -12
- package/src/layout/metro-path.ts +184 -0
- package/src/layout/spec.ts +16 -1
- package/src/layout/tokens.ts +2 -0
- package/src/layout-with-validation.ts +10 -5
- package/src/layout.ts +22 -12
- package/src/render/edges.tsx +19 -3
- package/src/render/nodes.tsx +3 -0
- package/src/types.ts +22 -4
- package/src/visual-validate.ts +24 -4
package/dist/react.js
CHANGED
|
@@ -986,6 +986,7 @@ var KINDS_DRAWING_TITLE_OUTSIDE = /* @__PURE__ */ new Set([
|
|
|
986
986
|
"dyn-arc",
|
|
987
987
|
"dyn-wave",
|
|
988
988
|
"dyn-polygon",
|
|
989
|
+
"station",
|
|
989
990
|
...KINDS_DRAWING_OWN_PAYLOAD
|
|
990
991
|
]);
|
|
991
992
|
function drawsTitleOutsideBox(kind) {
|
|
@@ -993,7 +994,7 @@ function drawsTitleOutsideBox(kind) {
|
|
|
993
994
|
}
|
|
994
995
|
var TITLE_FONT_SIZE_DEFAULT = 18;
|
|
995
996
|
var TITLE_FONT_SIZE = new Map([
|
|
996
|
-
...["dyn-rect", "dyn-circle", "dyn-arc", "dyn-wave", "dyn-polygon"].map(
|
|
997
|
+
...["dyn-rect", "dyn-circle", "dyn-arc", "dyn-wave", "dyn-polygon", "station"].map(
|
|
997
998
|
(k) => [k, 13]
|
|
998
999
|
),
|
|
999
1000
|
...[
|
|
@@ -1044,6 +1045,10 @@ var TITLE_FONT_SIZE = new Map([
|
|
|
1044
1045
|
function titleFontSize(kind) {
|
|
1045
1046
|
return TITLE_FONT_SIZE.get(kind ?? "") ?? TITLE_FONT_SIZE_DEFAULT;
|
|
1046
1047
|
}
|
|
1048
|
+
var KINDS_WITH_TITLE_WIDTH_OUTSIDE_NODE = /* @__PURE__ */ new Set(["station"]);
|
|
1049
|
+
function skipsNodeTitleWidthCheck(kind) {
|
|
1050
|
+
return KINDS_WITH_TITLE_WIDTH_OUTSIDE_NODE.has(kind ?? "");
|
|
1051
|
+
}
|
|
1047
1052
|
var TITLE_BOX_PADDING = 52;
|
|
1048
1053
|
var KINDS_SCALING_TITLE_WHEN_LOW = /* @__PURE__ */ new Set(["actor", "event", "function", "storage"]);
|
|
1049
1054
|
var KINDS_SCALING_TITLE_ALWAYS = /* @__PURE__ */ new Set([
|
|
@@ -1126,7 +1131,8 @@ var KINDS_DRAWING_ONLY_SHAPE = [
|
|
|
1126
1131
|
"dyn-circle",
|
|
1127
1132
|
"dyn-arc",
|
|
1128
1133
|
"dyn-wave",
|
|
1129
|
-
"dyn-polygon"
|
|
1134
|
+
"dyn-polygon",
|
|
1135
|
+
"station"
|
|
1130
1136
|
];
|
|
1131
1137
|
var KINDS_WITHOUT_EYEBROW_TEXT = /* @__PURE__ */ new Set([
|
|
1132
1138
|
...KINDS_DRAWING_ONLY_SHAPE,
|
|
@@ -1829,13 +1835,13 @@ function detectCollisions(bboxes, edges) {
|
|
|
1829
1835
|
}
|
|
1830
1836
|
function extractPathSegments(d) {
|
|
1831
1837
|
const segs = [];
|
|
1832
|
-
const commandRegex = /([
|
|
1838
|
+
const commandRegex = /([MLCQAZmlcqaz])([^MLCQAZmlcqaz]*)/g;
|
|
1833
1839
|
let cur = { x: 0, y: 0 };
|
|
1834
1840
|
let m;
|
|
1835
1841
|
while ((m = commandRegex.exec(d)) !== null) {
|
|
1836
1842
|
const cmd = m[1];
|
|
1837
1843
|
const args = (m[2] ?? "").trim().split(/[\s,]+/).filter(Boolean).map(parseFloat);
|
|
1838
|
-
const need = cmd === "M" || cmd === "L" ? 2 : cmd === "Q" ? 4 : cmd === "C" ? 6 : 0;
|
|
1844
|
+
const need = cmd === "M" || cmd === "L" ? 2 : cmd === "Q" ? 4 : cmd === "C" ? 6 : cmd === "A" ? 7 : 0;
|
|
1839
1845
|
if (need > 0 && (args.length < need || !args.slice(0, need).every(Number.isFinite))) continue;
|
|
1840
1846
|
if (cmd === "M") {
|
|
1841
1847
|
cur = { x: args[0], y: args[1] };
|
|
@@ -1865,6 +1871,10 @@ function extractPathSegments(d) {
|
|
|
1865
1871
|
ctrl: [{ x: args[0], y: args[1] }, { x: args[2], y: args[3] }]
|
|
1866
1872
|
});
|
|
1867
1873
|
cur = next;
|
|
1874
|
+
} else if (cmd === "A") {
|
|
1875
|
+
const next = { x: args[5], y: args[6] };
|
|
1876
|
+
segs.push({ x1: cur.x, y1: cur.y, x2: next.x, y2: next.y, cmd: "A" });
|
|
1877
|
+
cur = next;
|
|
1868
1878
|
}
|
|
1869
1879
|
}
|
|
1870
1880
|
return segs;
|
|
@@ -2971,6 +2981,232 @@ function applyEdgeLabelAndPathShifts(edges, labelShiftMap, edgePathShiftMap) {
|
|
|
2971
2981
|
});
|
|
2972
2982
|
}
|
|
2973
2983
|
|
|
2984
|
+
// src/layout/curve-path.ts
|
|
2985
|
+
var SAME_HEIGHT_THRESHOLD = 1;
|
|
2986
|
+
function curvePath(from, to, edge, labelMarginExtra = 0) {
|
|
2987
|
+
const fromLeft = from.cx - from.w / 2;
|
|
2988
|
+
const fromRight = from.cx + from.w / 2;
|
|
2989
|
+
const toLeft = to.cx - to.w / 2;
|
|
2990
|
+
const toRight = to.cx + to.w / 2;
|
|
2991
|
+
let fromSide;
|
|
2992
|
+
let toSide;
|
|
2993
|
+
let x1;
|
|
2994
|
+
let x2;
|
|
2995
|
+
if (toLeft >= fromRight) {
|
|
2996
|
+
fromSide = "right";
|
|
2997
|
+
toSide = "left";
|
|
2998
|
+
x1 = fromRight;
|
|
2999
|
+
x2 = toLeft;
|
|
3000
|
+
} else if (toRight <= fromLeft) {
|
|
3001
|
+
fromSide = "left";
|
|
3002
|
+
toSide = "right";
|
|
3003
|
+
x1 = fromLeft;
|
|
3004
|
+
x2 = toRight;
|
|
3005
|
+
} else {
|
|
3006
|
+
fromSide = "right";
|
|
3007
|
+
toSide = "right";
|
|
3008
|
+
x1 = fromRight;
|
|
3009
|
+
x2 = toRight;
|
|
3010
|
+
}
|
|
3011
|
+
const y1 = from.cy;
|
|
3012
|
+
const y2 = to.cy;
|
|
3013
|
+
const sameHeight = Math.abs(y2 - y1) < SAME_HEIGHT_THRESHOLD;
|
|
3014
|
+
let d;
|
|
3015
|
+
let midX;
|
|
3016
|
+
let midY;
|
|
3017
|
+
let tangentX;
|
|
3018
|
+
let tangentY;
|
|
3019
|
+
if (sameHeight) {
|
|
3020
|
+
d = `M ${x1} ${y1} L ${x2} ${y2}`;
|
|
3021
|
+
midX = (x1 + x2) / 2;
|
|
3022
|
+
midY = (y1 + y2) / 2;
|
|
3023
|
+
tangentX = x2 - x1;
|
|
3024
|
+
tangentY = y2 - y1;
|
|
3025
|
+
} else {
|
|
3026
|
+
let c1x;
|
|
3027
|
+
let c2x;
|
|
3028
|
+
if (fromSide !== toSide) {
|
|
3029
|
+
const direction = x2 > x1 ? 1 : -1;
|
|
3030
|
+
const bulge = Math.max(Math.abs(x2 - x1) / 2, EDGE_STUB_OUT);
|
|
3031
|
+
c1x = x1 + direction * bulge;
|
|
3032
|
+
c2x = x2 - direction * bulge;
|
|
3033
|
+
} else {
|
|
3034
|
+
const bulgeX = Math.max(x1, x2) + EDGE_STUB_OUT;
|
|
3035
|
+
c1x = bulgeX;
|
|
3036
|
+
c2x = bulgeX;
|
|
3037
|
+
}
|
|
3038
|
+
d = `M ${x1} ${y1} C ${c1x} ${y1}, ${c2x} ${y2}, ${x2} ${y2}`;
|
|
3039
|
+
midX = (x1 + 3 * c1x + 3 * c2x + x2) / 8;
|
|
3040
|
+
midY = (y1 + 3 * y1 + 3 * y2 + y2) / 8;
|
|
3041
|
+
tangentX = x2 + c2x - c1x - x1;
|
|
3042
|
+
tangentY = y2 + y2 - y1 - y1;
|
|
3043
|
+
}
|
|
3044
|
+
if (edge?.overlay) {
|
|
3045
|
+
return { d, fromSide, toSide, labelX: midX, labelY: midY, labelAnchor: "middle" };
|
|
3046
|
+
}
|
|
3047
|
+
const tangentLength = Math.hypot(tangentX, tangentY);
|
|
3048
|
+
let normalX = tangentY / tangentLength;
|
|
3049
|
+
let normalY = -tangentX / tangentLength;
|
|
3050
|
+
if (normalY > Number.EPSILON || Math.abs(normalY) <= Number.EPSILON && normalX < 0) {
|
|
3051
|
+
normalX *= -1;
|
|
3052
|
+
normalY *= -1;
|
|
3053
|
+
}
|
|
3054
|
+
const labelW = computeLabelBoxW(edge?.label, edge?.sub);
|
|
3055
|
+
const labelH = labelPillH(edge?.sub);
|
|
3056
|
+
const distance = labelPathClearanceHorizontal(edge) + (Math.abs(normalX) * labelW + Math.abs(normalY) * labelH) / 2 + labelMarginExtra;
|
|
3057
|
+
return {
|
|
3058
|
+
d,
|
|
3059
|
+
fromSide,
|
|
3060
|
+
toSide,
|
|
3061
|
+
labelX: midX + normalX * distance,
|
|
3062
|
+
labelY: midY + normalY * distance,
|
|
3063
|
+
labelAnchor: "middle"
|
|
3064
|
+
};
|
|
3065
|
+
}
|
|
3066
|
+
|
|
3067
|
+
// src/layout/metro-path.ts
|
|
3068
|
+
var METRO_CORNER_RADIUS = 24;
|
|
3069
|
+
var T = Math.SQRT2 - 1;
|
|
3070
|
+
function round2(v) {
|
|
3071
|
+
return Math.round(v * 100) / 100;
|
|
3072
|
+
}
|
|
3073
|
+
function point(p) {
|
|
3074
|
+
return `${round2(p.x)} ${round2(p.y)}`;
|
|
3075
|
+
}
|
|
3076
|
+
function add(p, v, scale) {
|
|
3077
|
+
return { x: p.x + v.x * scale, y: p.y + v.y * scale };
|
|
3078
|
+
}
|
|
3079
|
+
function polyline(points) {
|
|
3080
|
+
const distinct = points.filter((p, i) => {
|
|
3081
|
+
const previous = points[i - 1];
|
|
3082
|
+
return previous === void 0 || p.x !== previous.x || p.y !== previous.y;
|
|
3083
|
+
});
|
|
3084
|
+
return distinct.map((p, i) => `${i === 0 ? "M" : "L"} ${point(p)}`).join(" ");
|
|
3085
|
+
}
|
|
3086
|
+
function metroPath(from, to, edge, labelMarginExtra = 0) {
|
|
3087
|
+
const fromLeft = from.cx - from.w / 2;
|
|
3088
|
+
const fromRight = from.cx + from.w / 2;
|
|
3089
|
+
const toLeft = to.cx - to.w / 2;
|
|
3090
|
+
const toRight = to.cx + to.w / 2;
|
|
3091
|
+
let fromSide;
|
|
3092
|
+
let toSide;
|
|
3093
|
+
let x1;
|
|
3094
|
+
let x2;
|
|
3095
|
+
let dir;
|
|
3096
|
+
if (toLeft >= fromRight) {
|
|
3097
|
+
fromSide = "right";
|
|
3098
|
+
toSide = "left";
|
|
3099
|
+
x1 = fromRight;
|
|
3100
|
+
x2 = toLeft;
|
|
3101
|
+
dir = 1;
|
|
3102
|
+
} else if (toRight <= fromLeft) {
|
|
3103
|
+
fromSide = "left";
|
|
3104
|
+
toSide = "right";
|
|
3105
|
+
x1 = fromLeft;
|
|
3106
|
+
x2 = toRight;
|
|
3107
|
+
dir = -1;
|
|
3108
|
+
} else {
|
|
3109
|
+
fromSide = "right";
|
|
3110
|
+
toSide = "right";
|
|
3111
|
+
x1 = fromRight;
|
|
3112
|
+
x2 = toRight;
|
|
3113
|
+
dir = 1;
|
|
3114
|
+
}
|
|
3115
|
+
const y1 = from.cy;
|
|
3116
|
+
const y2 = to.cy;
|
|
3117
|
+
const dy = y2 - y1;
|
|
3118
|
+
const sgn = Math.sign(dy);
|
|
3119
|
+
let d;
|
|
3120
|
+
let mid;
|
|
3121
|
+
let tangent;
|
|
3122
|
+
if (Math.abs(dy) < SAME_HEIGHT_THRESHOLD) {
|
|
3123
|
+
d = `M ${point({ x: x1, y: y1 })} L ${point({ x: x2, y: y2 })}`;
|
|
3124
|
+
mid = { x: (x1 + x2) / 2, y: (y1 + y2) / 2 };
|
|
3125
|
+
tangent = { x: x2 - x1, y: y2 - y1 };
|
|
3126
|
+
} else if (fromSide !== toSide && Math.abs(x2 - x1) >= Math.abs(dy)) {
|
|
3127
|
+
const horizontal = Math.abs(x2 - x1);
|
|
3128
|
+
const s = (horizontal - Math.abs(dy)) / 2;
|
|
3129
|
+
const p0 = { x: x1, y: y1 };
|
|
3130
|
+
const p1 = { x: x1 + dir * s, y: y1 };
|
|
3131
|
+
const p2 = { x: x2 - dir * s, y: y2 };
|
|
3132
|
+
const p3 = { x: x2, y: y2 };
|
|
3133
|
+
const u = { x: dir, y: 0 };
|
|
3134
|
+
const w = { x: dir / Math.SQRT2, y: sgn / Math.SQRT2 };
|
|
3135
|
+
const r = Math.min(
|
|
3136
|
+
METRO_CORNER_RADIUS,
|
|
3137
|
+
s / T,
|
|
3138
|
+
Math.SQRT2 * Math.abs(dy) / (2 * T)
|
|
3139
|
+
);
|
|
3140
|
+
const t = r * T;
|
|
3141
|
+
if (r >= 0.5) {
|
|
3142
|
+
const f1 = dir * sgn > 0 ? 1 : 0;
|
|
3143
|
+
d = [
|
|
3144
|
+
`M ${point(p0)}`,
|
|
3145
|
+
`L ${point(add(p1, u, -t))}`,
|
|
3146
|
+
`A ${round2(r)} ${round2(r)} 0 0 ${f1} ${point(add(p1, w, t))}`,
|
|
3147
|
+
`L ${point(add(p2, w, -t))}`,
|
|
3148
|
+
`A ${round2(r)} ${round2(r)} 0 0 ${1 - f1} ${point(add(p2, u, t))}`,
|
|
3149
|
+
`L ${point(p3)}`
|
|
3150
|
+
].join(" ");
|
|
3151
|
+
} else {
|
|
3152
|
+
d = polyline([p0, p1, p2, p3]);
|
|
3153
|
+
}
|
|
3154
|
+
mid = { x: (x1 + x2) / 2, y: (y1 + y2) / 2 };
|
|
3155
|
+
tangent = w;
|
|
3156
|
+
} else {
|
|
3157
|
+
fromSide = "right";
|
|
3158
|
+
toSide = "right";
|
|
3159
|
+
x1 = fromRight;
|
|
3160
|
+
x2 = toRight;
|
|
3161
|
+
const xa = Math.max(x1, x2) + EDGE_STUB_OUT;
|
|
3162
|
+
const h = Math.abs(dy) / 2;
|
|
3163
|
+
const p0 = { x: x1, y: y1 };
|
|
3164
|
+
const p1 = { x: xa, y: y1 };
|
|
3165
|
+
const p2 = { x: xa + h, y: y1 + sgn * h };
|
|
3166
|
+
const p3 = { x: xa, y: y2 };
|
|
3167
|
+
const p4 = { x: x2, y: y2 };
|
|
3168
|
+
const u = { x: 1, y: 0 };
|
|
3169
|
+
const w1 = { x: 1 / Math.SQRT2, y: sgn / Math.SQRT2 };
|
|
3170
|
+
const w2 = { x: -1 / Math.SQRT2, y: sgn / Math.SQRT2 };
|
|
3171
|
+
const r = Math.min(METRO_CORNER_RADIUS, h);
|
|
3172
|
+
const t = r * T;
|
|
3173
|
+
const sweep = sgn > 0 ? 1 : 0;
|
|
3174
|
+
d = [
|
|
3175
|
+
`M ${point(p0)}`,
|
|
3176
|
+
`L ${point(add(p1, u, -t))}`,
|
|
3177
|
+
`A ${round2(r)} ${round2(r)} 0 0 ${sweep} ${point(add(p1, w1, t))}`,
|
|
3178
|
+
`L ${point(add(p2, w1, -r))}`,
|
|
3179
|
+
`A ${round2(r)} ${round2(r)} 0 0 ${sweep} ${point(add(p2, w2, r))}`,
|
|
3180
|
+
`L ${point(add(p3, w2, -t))}`,
|
|
3181
|
+
`A ${round2(r)} ${round2(r)} 0 0 ${sweep} ${point(add(p3, u, -t))}`,
|
|
3182
|
+
`L ${point(p4)}`
|
|
3183
|
+
].join(" ");
|
|
3184
|
+
mid = { x: p2.x - T * r, y: p2.y };
|
|
3185
|
+
tangent = { x: 0, y: sgn };
|
|
3186
|
+
}
|
|
3187
|
+
if (edge?.overlay) {
|
|
3188
|
+
return { d, fromSide, toSide, labelX: mid.x, labelY: mid.y, labelAnchor: "middle" };
|
|
3189
|
+
}
|
|
3190
|
+
const tangentLength = Math.hypot(tangent.x, tangent.y);
|
|
3191
|
+
let normalX = tangent.y / tangentLength;
|
|
3192
|
+
let normalY = -tangent.x / tangentLength;
|
|
3193
|
+
if (normalY > Number.EPSILON || Math.abs(normalY) <= Number.EPSILON && normalX < 0) {
|
|
3194
|
+
normalX *= -1;
|
|
3195
|
+
normalY *= -1;
|
|
3196
|
+
}
|
|
3197
|
+
const labelW = computeLabelBoxW(edge?.label, edge?.sub);
|
|
3198
|
+
const labelH = labelPillH(edge?.sub);
|
|
3199
|
+
const distance = labelPathClearanceHorizontal(edge) + (Math.abs(normalX) * labelW + Math.abs(normalY) * labelH) / 2 + labelMarginExtra;
|
|
3200
|
+
return {
|
|
3201
|
+
d,
|
|
3202
|
+
fromSide,
|
|
3203
|
+
toSide,
|
|
3204
|
+
labelX: mid.x + normalX * distance,
|
|
3205
|
+
labelY: mid.y + normalY * distance,
|
|
3206
|
+
labelAnchor: "middle"
|
|
3207
|
+
};
|
|
3208
|
+
}
|
|
3209
|
+
|
|
2974
3210
|
// src/types.ts
|
|
2975
3211
|
var TONES = ["accent", "teal", "success", "error", "warning", "info"];
|
|
2976
3212
|
var NODE_KINDS = [
|
|
@@ -3098,6 +3334,8 @@ var NODE_KINDS = [
|
|
|
3098
3334
|
// 状態遷移図が使う。 印そのものが意味を持つので文字は描かない
|
|
3099
3335
|
"mark-start",
|
|
3100
3336
|
"mark-end",
|
|
3337
|
+
// 路線図の駅 (#996) ... 線路上の点を小さな丸で示し、名前と説明は丸の外に置く
|
|
3338
|
+
"station",
|
|
3101
3339
|
// 時系列のやり取り (#578) ... 1 つの箱が図を丸ごと描く。 縦が時間で、参加者は箱を持たない
|
|
3102
3340
|
"sequence-board"
|
|
3103
3341
|
];
|
|
@@ -6257,6 +6495,7 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes, \u5
|
|
|
6257
6495
|
const LIFELINE_W_THRESHOLD = 8;
|
|
6258
6496
|
for (const n of laid.nodes) {
|
|
6259
6497
|
if (n.w < LIFELINE_W_THRESHOLD) continue;
|
|
6498
|
+
if (n.kind === "station") continue;
|
|
6260
6499
|
if (n.w < MIN_NODE_W || n.h < MIN_NODE_H) {
|
|
6261
6500
|
push(
|
|
6262
6501
|
"node-visibility",
|
|
@@ -6278,6 +6517,7 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes, \u5
|
|
|
6278
6517
|
if (n.id.endsWith("-spacer")) continue;
|
|
6279
6518
|
if (!rendersTitleText(n.kind)) continue;
|
|
6280
6519
|
if (fitsOwnTitleWidth(n.kind)) continue;
|
|
6520
|
+
if (skipsNodeTitleWidthCheck(n.kind)) continue;
|
|
6281
6521
|
if (!isRenderedNode(n)) continue;
|
|
6282
6522
|
const titleTrimmed = n.title?.trim() ?? "";
|
|
6283
6523
|
if (!titleTrimmed) continue;
|
|
@@ -6882,6 +7122,9 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes, \u5
|
|
|
6882
7122
|
for (let i = 0; i + 1 < sorted.length; i++) {
|
|
6883
7123
|
const upper = sorted[i];
|
|
6884
7124
|
const lower = sorted[i + 1];
|
|
7125
|
+
if (upper.cx + upper.w / 2 <= lower.cx - lower.w / 2 || lower.cx + lower.w / 2 <= upper.cx - upper.w / 2) {
|
|
7126
|
+
continue;
|
|
7127
|
+
}
|
|
6885
7128
|
const upperBottom = upper.cy + upper.h / 2;
|
|
6886
7129
|
const lowerTop = lower.cy - lower.h / 2;
|
|
6887
7130
|
const gap = lowerTop - upperBottom;
|
|
@@ -7513,11 +7756,18 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes, \u5
|
|
|
7513
7756
|
{
|
|
7514
7757
|
const crestSpans = (segs, peakY) => {
|
|
7515
7758
|
const out = [];
|
|
7759
|
+
let \u5186\u5F27\u306E\u59CB\u70B9 = null;
|
|
7516
7760
|
for (const s of segs) {
|
|
7517
|
-
if (
|
|
7518
|
-
|
|
7761
|
+
if (s.cmd === "A") {
|
|
7762
|
+
\u5186\u5F27\u306E\u59CB\u70B9 ??= { x: s.x1, y: s.y1 };
|
|
7763
|
+
continue;
|
|
7764
|
+
}
|
|
7765
|
+
const \u59CB\u70B9 = \u5186\u5F27\u306E\u59CB\u70B9 ?? { x: s.x1, y: s.y1 };
|
|
7766
|
+
\u5186\u5F27\u306E\u59CB\u70B9 = null;
|
|
7767
|
+
if (Math.abs(\u59CB\u70B9.y - s.y2) > 1) continue;
|
|
7768
|
+
if (Math.abs(\u59CB\u70B9.y - peakY) > 1) continue;
|
|
7519
7769
|
if (s.cmd !== "L" && !(s.ctrl ?? []).every((c) => Math.abs(c.y - peakY) <= 1)) continue;
|
|
7520
|
-
out.push({ minX: Math.min(
|
|
7770
|
+
out.push({ minX: Math.min(\u59CB\u70B9.x, s.x2), maxX: Math.max(\u59CB\u70B9.x, s.x2) });
|
|
7521
7771
|
}
|
|
7522
7772
|
return out;
|
|
7523
7773
|
};
|
|
@@ -7954,6 +8204,8 @@ var TOKENS = {
|
|
|
7954
8204
|
// 箱としての最小 (80x40) より大きく、名前を持つ箱 (card 320x150) よりは明らかに小さい
|
|
7955
8205
|
"mark-start": { w: 96, h: 96 },
|
|
7956
8206
|
"mark-end": { w: 96, h: 96 },
|
|
8207
|
+
// 路線図の駅 (#996) ... 正方形にして小さな丸が縦横どちらにも歪まないようにする。
|
|
8208
|
+
station: { w: 24, h: 24 },
|
|
7957
8209
|
// 時系列のやり取り (#578)。 実寸は中身から決まる (`sequenceBoardMetrics`) ので、
|
|
7958
8210
|
// ここは書かなかった時の受け皿
|
|
7959
8211
|
"sequence-board": { w: 960, h: 640 }
|
|
@@ -7978,6 +8230,7 @@ var LANE_PAD_MIN = 25;
|
|
|
7978
8230
|
// src/layout/edges.ts
|
|
7979
8231
|
var VERTICAL_DETOUR_GAP = 50;
|
|
7980
8232
|
var VERTICAL_DETOUR_CORNER = 14;
|
|
8233
|
+
var OVERLAY_LABEL_ON_PATH_TOLERANCE = 1;
|
|
7981
8234
|
function verticalCornerDir(from, to) {
|
|
7982
8235
|
return to < from ? -1 : 1;
|
|
7983
8236
|
}
|
|
@@ -8061,6 +8314,36 @@ function layoutEdges(diag, nodes, lanes = []) {
|
|
|
8061
8314
|
});
|
|
8062
8315
|
} else if (isSelfLoop(e)) {
|
|
8063
8316
|
selfLoopEdges.push(e);
|
|
8317
|
+
} else if (e.routing === "curve") {
|
|
8318
|
+
const from = nmap.get(e.from);
|
|
8319
|
+
const to = nmap.get(e.to);
|
|
8320
|
+
if (!from) throw new Error(`cdl layout: edge "${e.id}" \u306E from "${e.from}" \u304C node \u306B\u7121\u3044`);
|
|
8321
|
+
if (!to) throw new Error(`cdl layout: edge "${e.id}" \u306E to "${e.to}" \u304C node \u306B\u7121\u3044`);
|
|
8322
|
+
const c = curvePath(from, to, e, labelMarginExtra);
|
|
8323
|
+
positionedEdges.push({
|
|
8324
|
+
...e,
|
|
8325
|
+
d: c.d,
|
|
8326
|
+
fromSide: c.fromSide,
|
|
8327
|
+
toSide: c.toSide,
|
|
8328
|
+
labelX: c.labelX + (e.labelOffsetX ?? 0),
|
|
8329
|
+
labelY: c.labelY + (e.labelOffsetY ?? 0),
|
|
8330
|
+
labelAnchor: c.labelAnchor
|
|
8331
|
+
});
|
|
8332
|
+
} else if (e.routing === "metro") {
|
|
8333
|
+
const from = nmap.get(e.from);
|
|
8334
|
+
const to = nmap.get(e.to);
|
|
8335
|
+
if (!from) throw new Error(`cdl layout: edge "${e.id}" \u306E from "${e.from}" \u304C node \u306B\u7121\u3044`);
|
|
8336
|
+
if (!to) throw new Error(`cdl layout: edge "${e.id}" \u306E to "${e.to}" \u304C node \u306B\u7121\u3044`);
|
|
8337
|
+
const m = metroPath(from, to, e, labelMarginExtra);
|
|
8338
|
+
positionedEdges.push({
|
|
8339
|
+
...e,
|
|
8340
|
+
d: m.d,
|
|
8341
|
+
fromSide: m.fromSide,
|
|
8342
|
+
toSide: m.toSide,
|
|
8343
|
+
labelX: m.labelX + (e.labelOffsetX ?? 0),
|
|
8344
|
+
labelY: m.labelY + (e.labelOffsetY ?? 0),
|
|
8345
|
+
labelAnchor: m.labelAnchor
|
|
8346
|
+
});
|
|
8064
8347
|
} else {
|
|
8065
8348
|
autoEdges.push(e);
|
|
8066
8349
|
}
|
|
@@ -9565,9 +9848,11 @@ function hopEdgeCrossings(edges) {
|
|
|
9565
9848
|
ends.set(e.id, pathEnds(segs));
|
|
9566
9849
|
}
|
|
9567
9850
|
for (const e of edges) {
|
|
9851
|
+
if (e.routing === "metro") continue;
|
|
9568
9852
|
if ((e.d.match(/M/g) ?? []).length !== 1) continue;
|
|
9569
9853
|
const own = extractPathSegments(e.d);
|
|
9570
9854
|
if (own.length === 0) continue;
|
|
9855
|
+
if (own.some((s) => s.cmd === "A")) continue;
|
|
9571
9856
|
const myEnds = ends.get(e.id) ?? [];
|
|
9572
9857
|
const hops = /* @__PURE__ */ new Map();
|
|
9573
9858
|
for (let i = 0; i < own.length; i++) {
|
|
@@ -9655,7 +9940,7 @@ function pathVertices(d) {
|
|
|
9655
9940
|
const out = [{ x: first.x1, y: first.y1 }];
|
|
9656
9941
|
for (let i = 0; i < segs.length; i++) {
|
|
9657
9942
|
const s = segs[i];
|
|
9658
|
-
if (s.cmd === "C") return null;
|
|
9943
|
+
if (s.cmd === "C" || s.cmd === "A") return null;
|
|
9659
9944
|
if (s.cmd === "Q") {
|
|
9660
9945
|
const c = s.ctrl?.[0];
|
|
9661
9946
|
if (!c) return null;
|
|
@@ -9718,7 +10003,7 @@ function separateSharedStraightRuns(edges, nodes) {
|
|
|
9718
10003
|
const v = pathVertices(e.d);
|
|
9719
10004
|
if (v && v.length >= 2) verts.set(e.id, v);
|
|
9720
10005
|
}
|
|
9721
|
-
if (verts.size
|
|
10006
|
+
if (verts.size === 0) return;
|
|
9722
10007
|
const moved = /* @__PURE__ */ new Set();
|
|
9723
10008
|
const fits = (e, pts, k, ax, delta) => {
|
|
9724
10009
|
const \u8A66\u3057 = pts.map(
|
|
@@ -9736,33 +10021,40 @@ function separateSharedStraightRuns(edges, nodes) {
|
|
|
9736
10021
|
for (let j = i + 1; j < edges.length; j++) {
|
|
9737
10022
|
const \u524D = edges[i];
|
|
9738
10023
|
const \u5F8C = edges[j];
|
|
9739
|
-
|
|
9740
|
-
const
|
|
9741
|
-
|
|
9742
|
-
|
|
10024
|
+
if (\u524D.routing === "metro" && \u5F8C.routing === "metro") continue;
|
|
10025
|
+
const \u56FA\u5B9A = \u5F8C.routing === "metro" ? \u5F8C : \u524D;
|
|
10026
|
+
const \u52D5\u304B\u3059 = \u5F8C.routing === "metro" ? \u524D : \u5F8C;
|
|
10027
|
+
const B = verts.get(\u52D5\u304B\u3059.id);
|
|
10028
|
+
if (!B) continue;
|
|
10029
|
+
const \u56FA\u5B9A\u306E\u89D2 = verts.get(\u56FA\u5B9A.id);
|
|
10030
|
+
const \u56FA\u5B9A\u306E\u7D4C\u8DEF = \u56FA\u5B9A\u306E\u89D2 ? [\u56FA\u5B9A\u306E\u89D2] : \u56FA\u5B9A.routing === "metro" ? extractPathSegments(\u56FA\u5B9A.d).filter((s) => s.cmd === "L").map((s) => [{ x: s.x1, y: s.y1 }, { x: s.x2, y: s.y2 }]) : [];
|
|
10031
|
+
if (\u56FA\u5B9A\u306E\u7D4C\u8DEF.length === 0) continue;
|
|
10032
|
+
if (\u56FA\u5B9A.from === \u52D5\u304B\u3059.from) continue;
|
|
9743
10033
|
for (const ax of [0, 1]) {
|
|
9744
|
-
for (
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
|
|
9751
|
-
|
|
9752
|
-
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9756
|
-
|
|
9757
|
-
|
|
9758
|
-
|
|
9759
|
-
|
|
9760
|
-
|
|
9761
|
-
|
|
9762
|
-
|
|
10034
|
+
for (const A of \u56FA\u5B9A\u306E\u7D4C\u8DEF) {
|
|
10035
|
+
for (let ka = 0; ka + 1 < A.length; ka++) {
|
|
10036
|
+
if (!runIsAligned(A, ka, ax)) continue;
|
|
10037
|
+
for (let kb = 0; kb + 1 < B.length; kb++) {
|
|
10038
|
+
if (!runIsAligned(B, kb, ax)) continue;
|
|
10039
|
+
if (kb === 0 || kb + 1 === B.length - 1) continue;
|
|
10040
|
+
const \u5EA7\u6A19A = ax === 0 ? A[ka].x : A[ka].y;
|
|
10041
|
+
const \u5EA7\u6A19B = ax === 0 ? B[kb].x : B[kb].y;
|
|
10042
|
+
if (Math.abs(\u5EA7\u6A19A - \u5EA7\u6A19B) > SHARED_RUN_EPS) continue;
|
|
10043
|
+
const sa = runSpan(A, ka, ax);
|
|
10044
|
+
const sb = runSpan(B, kb, ax);
|
|
10045
|
+
if (Math.min(sa.hi, sb.hi) - Math.max(sa.lo, sb.lo) < SHARED_RUN_MIN) continue;
|
|
10046
|
+
for (const delta of [SHARED_RUN_SEPARATION, -SHARED_RUN_SEPARATION]) {
|
|
10047
|
+
if (!fits(\u52D5\u304B\u3059, B, kb, ax, delta)) continue;
|
|
10048
|
+
if (ax === 0) {
|
|
10049
|
+
B[kb].x += delta;
|
|
10050
|
+
B[kb + 1].x += delta;
|
|
10051
|
+
} else {
|
|
10052
|
+
B[kb].y += delta;
|
|
10053
|
+
B[kb + 1].y += delta;
|
|
10054
|
+
}
|
|
10055
|
+
moved.add(\u52D5\u304B\u3059.id);
|
|
10056
|
+
break;
|
|
9763
10057
|
}
|
|
9764
|
-
moved.add(\u5F8C.id);
|
|
9765
|
-
break;
|
|
9766
10058
|
}
|
|
9767
10059
|
}
|
|
9768
10060
|
}
|
|
@@ -9789,12 +10081,19 @@ function pullOutgoingFirstCorner(edges, nodes) {
|
|
|
9789
10081
|
let \u672D\u3092\u65E7\u7D4C\u8DEF\u3078\u8FFD\u5F93\u6E08\u307F = false;
|
|
9790
10082
|
for (const list of \u675F.values()) {
|
|
9791
10083
|
if (list.length < 2) continue;
|
|
9792
|
-
const \u4E26\u3073 = list.
|
|
10084
|
+
const \u4E26\u3073 = list.map((e) => {
|
|
9793
10085
|
const pts = pathVertices(e.d);
|
|
9794
|
-
if (
|
|
9795
|
-
|
|
9796
|
-
|
|
10086
|
+
if (pts && pts.length >= 2) {
|
|
10087
|
+
return { e, pts, \u6700\u521D\u306E\u9577\u3055: Math.hypot(pts[1].x - pts[0].x, pts[1].y - pts[0].y) };
|
|
10088
|
+
}
|
|
10089
|
+
if (e.routing !== "metro") return null;
|
|
10090
|
+
const first = extractPathSegments(e.d)[0];
|
|
10091
|
+
if (!first) return null;
|
|
10092
|
+
return { e, pts: null, \u6700\u521D\u306E\u9577\u3055: Math.hypot(first.x2 - first.x1, first.y2 - first.y1) };
|
|
10093
|
+
}).filter((x) => x !== null).sort((a, b) => b.\u6700\u521D\u306E\u9577\u3055 - a.\u6700\u521D\u306E\u9577\u3055);
|
|
9797
10094
|
for (const { e, pts, \u6700\u521D\u306E\u9577\u3055 } of \u4E26\u3073.slice(1)) {
|
|
10095
|
+
if (e.routing === "metro") continue;
|
|
10096
|
+
if (!pts) continue;
|
|
9798
10097
|
if ((\u540C\u3058\u7D44\u306E\u6570.get(`${e.from}->${e.to}`) ?? 0) > 1) continue;
|
|
9799
10098
|
if (pts.length < 3 || \u6700\u521D\u306E\u9577\u3055 <= EDGE_STUB_OUT + VERTICAL_DETOUR_CORNER) continue;
|
|
9800
10099
|
const \u6A2A = e.fromSide === "left" || e.fromSide === "right";
|
|
@@ -9848,7 +10147,8 @@ var ENDPOINT_FAN_MIN = 20;
|
|
|
9848
10147
|
var ENDPOINT_FAN_RUNUP = 40;
|
|
9849
10148
|
var MIXED_ROOT_OVERLAP_MIN = 24;
|
|
9850
10149
|
function fanIncomingEndpoints(edges, nodes) {
|
|
9851
|
-
|
|
10150
|
+
const \u7D42\u70B9\u306E\u79FB\u52D5 = /* @__PURE__ */ new Map();
|
|
10151
|
+
if (edges.length < 2) return \u7D42\u70B9\u306E\u79FB\u52D5;
|
|
9852
10152
|
const nmap = new Map(nodes.map((n) => [n.id, n]));
|
|
9853
10153
|
const \u5E73\u5766\u306A\u533A\u9593 = new Map(edges.map((e) => [e.id, flattenPathSegments(extractPathSegments(e.d))]));
|
|
9854
10154
|
const \u8EF8\u306B\u5E73\u884C\u306A\u91CD\u306A\u308A\u9577\u3055 = (\u4E00\u65B9, \u4ED6\u65B9) => {
|
|
@@ -9918,6 +10218,7 @@ function fanIncomingEndpoints(edges, nodes) {
|
|
|
9918
10218
|
const d = \u4E2D\u592E\u304C\u585E\u304C\u3063\u3066\u3044\u308B ? \u4E26\u3073[k].\u6DF1\u3055 < \u8FBA\u306E\u4E2D\u5FC3 ? -(++\u8CA0\u5074\u306E\u5E2D * \u9593\u9694) : ++\u6B63\u5074\u306E\u5E2D * \u9593\u9694 : k * \u9593\u9694 - \u4E2D\u5FC3;
|
|
9919
10219
|
if (Math.abs(d) < 1e-3) continue;
|
|
9920
10220
|
const e = \u4E26\u3073[k].e;
|
|
10221
|
+
if (e.routing === "metro") continue;
|
|
9921
10222
|
const \u524D = e.d;
|
|
9922
10223
|
const \u524D\u306E\u4EA4\u5DEE = countEdgeCrossings(edges).count;
|
|
9923
10224
|
const \u9577\u3044\u52A9\u8D70 = \u4E26\u3073[k].\u9577\u3044\u52A9\u8D70;
|
|
@@ -9929,6 +10230,68 @@ function fanIncomingEndpoints(edges, nodes) {
|
|
|
9929
10230
|
if (countEdgeCrossings(edges).count <= \u524D\u306E\u4EA4\u5DEE) break;
|
|
9930
10231
|
e.d = \u524D;
|
|
9931
10232
|
}
|
|
10233
|
+
if (e.d !== \u524D) \u7D42\u70B9\u306E\u79FB\u52D5.set(e.id, \u6A2A ? { dx: 0, dy: d } : { dx: d, dy: 0 });
|
|
10234
|
+
}
|
|
10235
|
+
}
|
|
10236
|
+
return \u7D42\u70B9\u306E\u79FB\u52D5;
|
|
10237
|
+
}
|
|
10238
|
+
function followLabelsToFannedTails(edges, obstacles, shifts) {
|
|
10239
|
+
if (shifts.size === 0) return;
|
|
10240
|
+
const \u6E2C\u308A\u65B9 = \u7DDA\u306E\u6E2C\u308A\u65B9\u3092\u4F5C\u308B();
|
|
10241
|
+
const labels = edges.filter(hasRenderedLabel).map((e) => ({
|
|
10242
|
+
kind: "edge-label",
|
|
10243
|
+
id: e.id,
|
|
10244
|
+
...computeLabelBBoxWorld(e)
|
|
10245
|
+
}));
|
|
10246
|
+
const labelIndexByEdgeId = new Map(labels.map((label, index) => [label.id, index]));
|
|
10247
|
+
const edgeById = new Map(edges.map((e) => [e.id, e]));
|
|
10248
|
+
const \u5468\u308A = {
|
|
10249
|
+
\u7BB1\u305F\u3061: obstacles.filter((o) => o.kind === "node" || o.kind === "lane-label"),
|
|
10250
|
+
labels,
|
|
10251
|
+
edges,
|
|
10252
|
+
edgeById,
|
|
10253
|
+
\u6E2C\u308A\u65B9
|
|
10254
|
+
};
|
|
10255
|
+
for (const e of edges) {
|
|
10256
|
+
const \u79FB\u52D5 = shifts.get(e.id);
|
|
10257
|
+
if (!\u79FB\u52D5 || !hasRenderedLabel(e)) continue;
|
|
10258
|
+
const labelIndex = labelIndexByEdgeId.get(e.id);
|
|
10259
|
+
if (labelIndex === void 0) continue;
|
|
10260
|
+
const \u5143\u306E\u672D = labels[labelIndex];
|
|
10261
|
+
const \u81EA\u5206\u306E\u533A\u9593 = \u6E2C\u308A\u65B9.\u533A\u9593(e.id, e.d);
|
|
10262
|
+
if (e.overlay && measurePathLabelGapSegs(\u81EA\u5206\u306E\u533A\u9593, {
|
|
10263
|
+
x: \u5143\u306E\u672D.x + \u5143\u306E\u672D.w / 2,
|
|
10264
|
+
y: \u5143\u306E\u672D.y + \u5143\u306E\u672D.h / 2,
|
|
10265
|
+
w: 0,
|
|
10266
|
+
h: 0
|
|
10267
|
+
}) <= OVERLAY_LABEL_ON_PATH_TOLERANCE) continue;
|
|
10268
|
+
const \u6700\u5F8C = \u81EA\u5206\u306E\u533A\u9593.at(-1);
|
|
10269
|
+
if (!\u6700\u5F8C) continue;
|
|
10270
|
+
if (!segmentsCrossRect([\u6700\u5F8C], \u5143\u306E\u672D)) continue;
|
|
10271
|
+
const \u5019\u88DCa = {
|
|
10272
|
+
labelX: e.labelX + \u79FB\u52D5.dx,
|
|
10273
|
+
labelY: e.labelY + \u79FB\u52D5.dy,
|
|
10274
|
+
labelAnchor: e.labelAnchor
|
|
10275
|
+
};
|
|
10276
|
+
const \u5019\u88DCa\u306E\u7BB1 = computeLabelBBoxWorld({ ...e, ...\u5019\u88DCa });
|
|
10277
|
+
const \u6700\u5F8C\u306F\u7E26 = Math.abs(\u6700\u5F8C.x2 - \u6700\u5F8C.x1) <= Math.abs(\u6700\u5F8C.y2 - \u6700\u5F8C.y1);
|
|
10278
|
+
const \u5019\u88DC = [
|
|
10279
|
+
\u5019\u88DCa,
|
|
10280
|
+
{
|
|
10281
|
+
labelX: \u6700\u5F8C\u306F\u7E26 ? \u6700\u5F8C.x1 * 2 - (\u5019\u88DCa\u306E\u7BB1.x + \u5019\u88DCa\u306E\u7BB1.w / 2) : \u5019\u88DCa\u306E\u7BB1.x + \u5019\u88DCa\u306E\u7BB1.w / 2,
|
|
10282
|
+
labelY: \u6700\u5F8C\u306F\u7E26 ? \u5019\u88DCa\u306E\u7BB1.y + \u5019\u88DCa\u306E\u7BB1.h / 2 : \u6700\u5F8C.y1 * 2 - (\u5019\u88DCa\u306E\u7BB1.y + \u5019\u88DCa\u306E\u7BB1.h / 2),
|
|
10283
|
+
labelAnchor: "middle"
|
|
10284
|
+
}
|
|
10285
|
+
];
|
|
10286
|
+
for (const c of \u5019\u88DC) {
|
|
10287
|
+
const \u672D = { kind: "edge-label", id: e.id, ...computeLabelBBoxWorld({ ...e, ...c }) };
|
|
10288
|
+
if (segmentsCrossRect([\u6700\u5F8C], \u672D)) continue;
|
|
10289
|
+
if (\u672D\u306E\u79FB\u52D5\u3092\u585E\u3050\u76F8\u624B\u3092\u63A2\u3059(\u5468\u308A, \u5143\u306E\u672D, \u672D) !== null) continue;
|
|
10290
|
+
e.labelX = c.labelX;
|
|
10291
|
+
e.labelY = c.labelY;
|
|
10292
|
+
e.labelAnchor = c.labelAnchor;
|
|
10293
|
+
labels[labelIndex] = \u672D;
|
|
10294
|
+
break;
|
|
9932
10295
|
}
|
|
9933
10296
|
}
|
|
9934
10297
|
}
|
|
@@ -9945,7 +10308,7 @@ function \u672B\u5C3E\u3092\u8FBA\u306B\u6CBF\u3063\u3066\u305A\u3089\u3059(e, \
|
|
|
9945
10308
|
if ((e.d.match(/M/g) ?? []).length !== 1) return null;
|
|
9946
10309
|
const segs = extractPathSegments(e.d);
|
|
9947
10310
|
if (segs.length === 0) return null;
|
|
9948
|
-
if (segs.some((s) => s.cmd === "C")) return null;
|
|
10311
|
+
if (segs.some((s) => s.cmd === "C" || s.cmd === "A")) return null;
|
|
9949
10312
|
const last = segs[segs.length - 1];
|
|
9950
10313
|
if (last.cmd !== "L") return null;
|
|
9951
10314
|
const \u5782\u76F4\u306B\u5165\u308B = \u6A2A ? Math.abs(last.y2 - last.y1) < 0.5 && Math.abs(last.x2 - last.x1) > 0.5 : Math.abs(last.x2 - last.x1) < 0.5 && Math.abs(last.y2 - last.y1) > 0.5;
|
|
@@ -10211,9 +10574,9 @@ function recomputeContainedLanes(lanes, nodes) {
|
|
|
10211
10574
|
}
|
|
10212
10575
|
|
|
10213
10576
|
// src/layout/head-label.ts
|
|
10214
|
-
var \u7AEF\u306E\u5B57\u306E\u5927\u304D\u3055 =
|
|
10577
|
+
var \u7AEF\u306E\u5B57\u306E\u5927\u304D\u3055 = 26;
|
|
10215
10578
|
var \u7BB1\u306E\u9AD8\u3055 = Math.round(\u7AEF\u306E\u5B57\u306E\u5927\u304D\u3055 * 1.2);
|
|
10216
|
-
var \u7AEF\u306E\u5B57\u3068\u5370\u306E\u4F59\u767D =
|
|
10579
|
+
var \u7AEF\u306E\u5B57\u3068\u5370\u306E\u4F59\u767D = 12;
|
|
10217
10580
|
var \u7AEF\u306E\u5370\u306E\u5F35\u308A\u51FA\u3057 = EDGE_HEAD_MARKER_SIZE.\u65E2\u5B9A / 2;
|
|
10218
10581
|
var \u7AEF\u306E\u5B57\u3092\u623B\u3059\u8DDD\u96E2 = EDGE_HEAD_MARKER_SIZE.\u65E2\u5B9A + \u7AEF\u306E\u5B57\u3068\u5370\u306E\u4F59\u767D;
|
|
10219
10582
|
var \u7AEF\u306E\u5B57\u3068\u7DDA\u306E\u9699\u9593 = \u7AEF\u306E\u5370\u306E\u5F35\u308A\u51FA\u3057 + \u7AEF\u306E\u5B57\u3068\u5370\u306E\u4F59\u767D;
|
|
@@ -10236,13 +10599,16 @@ function \u5411\u304D\u3092\u53D6\u308B(end, \u5019\u88DC) {
|
|
|
10236
10599
|
}
|
|
10237
10600
|
return null;
|
|
10238
10601
|
}
|
|
10239
|
-
function \u7AEF\
|
|
10602
|
+
function \u7DDA\u306E\u7AEF\u306E\u5411\u304D(d, \u7AEF) {
|
|
10240
10603
|
const segs = extractPathSegments(d);
|
|
10241
10604
|
if (segs.length === 0) return null;
|
|
10242
10605
|
if (\u7AEF === "head") {
|
|
10243
10606
|
const last = segs[segs.length - 1];
|
|
10244
10607
|
const end2 = { x: last.x2, y: last.y2 };
|
|
10245
|
-
const \u5019\u88DC2 = segs.slice().reverse().flatMap((s) =>
|
|
10608
|
+
const \u5019\u88DC2 = segs.slice().reverse().flatMap((s) => {
|
|
10609
|
+
const \u5236\u5FA1\u70B9 = s.cmd === "C" ? [s.ctrl?.[1], s.ctrl?.[0]] : s.cmd === "Q" ? [s.ctrl?.[0]] : [];
|
|
10610
|
+
return [...\u5236\u5FA1\u70B9, { x: s.x1, y: s.y1 }];
|
|
10611
|
+
});
|
|
10246
10612
|
return \u5411\u304D\u3092\u53D6\u308B(end2, \u5019\u88DC2);
|
|
10247
10613
|
}
|
|
10248
10614
|
const first = segs[0];
|
|
@@ -10253,7 +10619,7 @@ function \u7AEF\u3067\u306E\u5411\u304D(d, \u7AEF) {
|
|
|
10253
10619
|
function \u7AEF\u306E\u5B57\u3092\u7F6E\u304F(edge, \u7AEF = "head") {
|
|
10254
10620
|
const text = (\u7AEF === "head" ? edge.headLabel : edge.tailLabel)?.trim();
|
|
10255
10621
|
if (!text) return null;
|
|
10256
|
-
const \u5411\u304D = \u7AEF\
|
|
10622
|
+
const \u5411\u304D = \u7DDA\u306E\u7AEF\u306E\u5411\u304D(edge.d, \u7AEF);
|
|
10257
10623
|
if (!\u5411\u304D) return null;
|
|
10258
10624
|
const { end, ux, uy } = \u5411\u304D;
|
|
10259
10625
|
const bx = end.x - ux * \u7AEF\u306E\u5B57\u3092\u623B\u3059\u8DDD\u96E2;
|
|
@@ -10581,22 +10947,23 @@ function layout(diag) {
|
|
|
10581
10947
|
}
|
|
10582
10948
|
}
|
|
10583
10949
|
const positionedEdgeIds = new Set(
|
|
10584
|
-
diag.edges.filter(
|
|
10950
|
+
diag.edges.filter(
|
|
10951
|
+
(e) => e.routing === "curve" || e.routing === "metro" || e.posX1 !== void 0 && e.posY1 !== void 0 && e.posX2 !== void 0 && e.posY2 !== void 0
|
|
10952
|
+
).map((e) => e.id)
|
|
10585
10953
|
);
|
|
10586
10954
|
bowSharedStraightPaths(edges, nodesFinal, positionedEdgeIds);
|
|
10587
10955
|
pullOutgoingFirstCorner(edges, nodesFinal);
|
|
10588
|
-
fanIncomingEndpoints(edges, nodesFinal);
|
|
10956
|
+
const fannedTailShifts = fanIncomingEndpoints(edges, nodesFinal);
|
|
10589
10957
|
separateSharedStraightRuns(edges, nodesFinal);
|
|
10590
10958
|
hopEdgeCrossings(edges);
|
|
10959
|
+
const labelClearanceObstacles = collectBBoxes(containedLanesFinal, nodesFinal, []).filter(
|
|
10960
|
+
(b) => b.kind === "node" || b.kind === "lane-label"
|
|
10961
|
+
);
|
|
10962
|
+
followLabelsToFannedTails(edges, labelClearanceObstacles, fannedTailShifts);
|
|
10591
10963
|
repositionParallelLabels(edges, nodesFinal);
|
|
10592
10964
|
slideLabelsAlongOwnPath(edges, nodesFinal);
|
|
10593
10965
|
if (!isChainEdgeLabelDisabled()) {
|
|
10594
|
-
edges = resolveLabelClearanceAfterPathPasses(
|
|
10595
|
-
edges,
|
|
10596
|
-
collectBBoxes(containedLanesFinal, nodesFinal, []).filter(
|
|
10597
|
-
(b) => b.kind === "node" || b.kind === "lane-label"
|
|
10598
|
-
)
|
|
10599
|
-
);
|
|
10966
|
+
edges = resolveLabelClearanceAfterPathPasses(edges, labelClearanceObstacles);
|
|
10600
10967
|
}
|
|
10601
10968
|
const bboxes = collectBBoxes(containedLanesFinal, nodesFinal, edges);
|
|
10602
10969
|
const collisions = detectCollisions(bboxes, edges);
|
|
@@ -11528,12 +11895,13 @@ function CdlEdgeView({
|
|
|
11528
11895
|
const isPassThrough = isDotted && Boolean(edge.dThrough);
|
|
11529
11896
|
const lineDotsD = isDotted ? shrinkPathEnd(edge.d, 12) : edge.d;
|
|
11530
11897
|
const glowPathId = `cdl-edge-${edge.id}`;
|
|
11531
|
-
const \u901A\u308A\u9053\u3092\u7E2E\u3081\u308B = EDGE_HEAD_MARKER_SIZE.\u65E2\u5B9A + \u8D70\u308B\u4E38\u306E\
|
|
11898
|
+
const \u901A\u308A\u9053\u3092\u7E2E\u3081\u308B = EDGE_HEAD_MARKER_SIZE.\u65E2\u5B9A + \u8D70\u308B\u4E38\u306E\u5916\u5074;
|
|
11532
11899
|
const glowPathD = shrinkPathStart(shrinkPathEnd(edge.d, \u901A\u308A\u9053\u3092\u7E2E\u3081\u308B), \u901A\u308A\u9053\u3092\u7E2E\u3081\u308B);
|
|
11533
11900
|
return /* @__PURE__ */ jsxs(
|
|
11534
11901
|
"g",
|
|
11535
11902
|
{
|
|
11536
11903
|
"data-cdl-edge": edge.id,
|
|
11904
|
+
"data-cdl-routing": edge.routing === "metro" ? "metro" : void 0,
|
|
11537
11905
|
"data-cdl-from": edge.from,
|
|
11538
11906
|
"data-cdl-to": edge.to,
|
|
11539
11907
|
"data-cdl-active": active ? "true" : "false",
|
|
@@ -11636,7 +12004,9 @@ function SolidEdgePath({
|
|
|
11636
12004
|
}
|
|
11637
12005
|
);
|
|
11638
12006
|
}
|
|
11639
|
-
var \u8D70\u308B\u4E38\u306E\u534A\u5F84 = { \u5916: 28, \u4E2D: 18, \u82AF:
|
|
12007
|
+
var \u8D70\u308B\u4E38\u306E\u534A\u5F84 = { \u5916: 28, \u4E2D: 18, \u82AF: 12 };
|
|
12008
|
+
var \u8D70\u308B\u4E38\u306E\u7E01\u306E\u898B\u8FBC\u307F = 2;
|
|
12009
|
+
var \u8D70\u308B\u4E38\u306E\u5916\u5074 = \u8D70\u308B\u4E38\u306E\u534A\u5F84.\u82AF + \u8D70\u308B\u4E38\u306E\u7E01\u306E\u898B\u8FBC\u307F;
|
|
11640
12010
|
function EdgeGlowCircles({ color, edgeId }) {
|
|
11641
12011
|
const ref = `#cdl-edge-${edgeId}`;
|
|
11642
12012
|
return /* @__PURE__ */ jsxs("g", { "data-cdl-particle": edgeId, "data-cdl-particle-path-ref": ref, children: [
|
|
@@ -12960,17 +13330,22 @@ function DynShapeNode({
|
|
|
12960
13330
|
return renderPolygon(shape, cx, cy, stateValues, fillColor, strokeColor, activeOpacity);
|
|
12961
13331
|
}
|
|
12962
13332
|
})();
|
|
13333
|
+
const \u63C3\u3048 = \u7BB1\u3044\u3063\u3071\u3044\u306B\u63CF\u304F2(shape.kind) ? "start" : "middle";
|
|
13334
|
+
return renderShapeWithOutsideLabels(\u5F62, node, \u63C3\u3048);
|
|
13335
|
+
}
|
|
13336
|
+
function renderShapeWithOutsideLabels(\u5F62, node, \u63C3\u3048) {
|
|
13337
|
+
const cx = node.cx;
|
|
13338
|
+
const y = node.cy - node.h / 2;
|
|
12963
13339
|
const \u540D\u524D = (node.title ?? "").trim();
|
|
12964
13340
|
const \u5024 = (node.subtitle ?? "").trim();
|
|
12965
13341
|
if (\u540D\u524D === "" && \u5024 === "") return \u5F62;
|
|
12966
|
-
const \u63C3\u3048 = \u7BB1\u3044\u3063\u3071\u3044\u306B\u63CF\u304F2(shape.kind) ? "start" : "middle";
|
|
12967
13342
|
return /* @__PURE__ */ jsxs("g", { children: [
|
|
12968
13343
|
\u5F62,
|
|
12969
13344
|
\u540D\u524D !== "" && /* @__PURE__ */ jsx(
|
|
12970
13345
|
"text",
|
|
12971
13346
|
{
|
|
12972
13347
|
"data-cdl-role": "shape-name",
|
|
12973
|
-
x: \u63C3\u3048 === "start" ?
|
|
13348
|
+
x: \u63C3\u3048 === "start" ? node.cx - node.w / 2 : cx,
|
|
12974
13349
|
y: y - NAME_GAP,
|
|
12975
13350
|
textAnchor: \u63C3\u3048,
|
|
12976
13351
|
fontSize: 13,
|
|
@@ -12984,7 +13359,7 @@ function DynShapeNode({
|
|
|
12984
13359
|
{
|
|
12985
13360
|
"data-cdl-role": "shape-value",
|
|
12986
13361
|
x: cx,
|
|
12987
|
-
y: y + h + VALUE_GAP,
|
|
13362
|
+
y: y + node.h + VALUE_GAP,
|
|
12988
13363
|
textAnchor: "middle",
|
|
12989
13364
|
fontSize: 12,
|
|
12990
13365
|
fill: "var(--cdl-text-dim, #5a6270)",
|
|
@@ -13234,6 +13609,27 @@ function interpolateColor(template, stateValues, fallback) {
|
|
|
13234
13609
|
if (!template) return fallback;
|
|
13235
13610
|
return interpolate(template, stateValues);
|
|
13236
13611
|
}
|
|
13612
|
+
var STATION_STROKE_ACTIVE = 4;
|
|
13613
|
+
var STATION_STROKE_IDLE = 3;
|
|
13614
|
+
var STATION_DEFAULT = "var(--cdl-tone-accent, #2d6a8f)";
|
|
13615
|
+
function StationNode({ node, active }) {
|
|
13616
|
+
const strokeWidth = active ? STATION_STROKE_ACTIVE : STATION_STROKE_IDLE;
|
|
13617
|
+
const radius = Math.max(0, Math.min(node.w, node.h) / 2 - strokeWidth / 2);
|
|
13618
|
+
const \u5F62 = /* @__PURE__ */ jsx(
|
|
13619
|
+
"circle",
|
|
13620
|
+
{
|
|
13621
|
+
"data-cdl-role": "node-body",
|
|
13622
|
+
"data-cdl-mark": "station",
|
|
13623
|
+
cx: node.cx,
|
|
13624
|
+
cy: node.cy,
|
|
13625
|
+
r: radius,
|
|
13626
|
+
fill: "var(--cdl-node-fill, #ffffff)",
|
|
13627
|
+
stroke: nodeAccent(node, STATION_DEFAULT),
|
|
13628
|
+
strokeWidth
|
|
13629
|
+
}
|
|
13630
|
+
);
|
|
13631
|
+
return renderShapeWithOutsideLabels(\u5F62, node, "middle");
|
|
13632
|
+
}
|
|
13237
13633
|
|
|
13238
13634
|
// src/kinds/label-stack.ts
|
|
13239
13635
|
function \u540D\u672D\u306E\u6BB5\u3092\u307B\u3069\u304F(\u771F\u306Ey, \u9593\u9694, \u4E0A\u9650, \u4E0B\u9650) {
|
|
@@ -20462,6 +20858,8 @@ function CdlNodeView({
|
|
|
20462
20858
|
return /* @__PURE__ */ jsx(MarkStartNode, { node: resolvedNode, active });
|
|
20463
20859
|
case "mark-end":
|
|
20464
20860
|
return /* @__PURE__ */ jsx(MarkEndNode, { node: resolvedNode, active });
|
|
20861
|
+
case "station":
|
|
20862
|
+
return /* @__PURE__ */ jsx(StationNode, { node: resolvedNode, active });
|
|
20465
20863
|
default:
|
|
20466
20864
|
return /* @__PURE__ */ jsx(GenericNode, { node: resolvedNode, active, value: node.value, stateValues, \u5024\u306E\u540D\u524D });
|
|
20467
20865
|
}
|
|
@@ -20694,15 +21092,15 @@ function CdlStage({
|
|
|
20694
21092
|
}, [laid]);
|
|
20695
21093
|
const edgeHeadMarkers = useMemo(() => {
|
|
20696
21094
|
const referenced = /* @__PURE__ */ new Set();
|
|
20697
|
-
const
|
|
21095
|
+
const add2 = (tone, head, fill) => {
|
|
20698
21096
|
for (const small of [false, true]) {
|
|
20699
21097
|
const id = edgeHeadMarkerName(tone, head, small, fill);
|
|
20700
21098
|
if (id !== void 0) referenced.add(id);
|
|
20701
21099
|
}
|
|
20702
21100
|
};
|
|
20703
21101
|
for (const edge of laid.edges) {
|
|
20704
|
-
|
|
20705
|
-
if (edge.tailHead !== void 0)
|
|
21102
|
+
add2(edge.tone, edge.head, edge.headFill);
|
|
21103
|
+
if (edge.tailHead !== void 0) add2(edge.tone, edge.tailHead, edge.tailHeadFill);
|
|
20706
21104
|
}
|
|
20707
21105
|
return Object.entries(TONE).flatMap(
|
|
20708
21106
|
([tone, color]) => [
|