@diagrammo/dgmo 0.6.1 → 0.6.3
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/.claude/commands/dgmo.md +294 -0
- package/AGENTS.md +148 -0
- package/dist/cli.cjs +338 -163
- package/dist/index.cjs +1080 -319
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -4
- package/dist/index.d.ts +28 -4
- package/dist/index.js +1078 -319
- package/dist/index.js.map +1 -1
- package/docs/ai-integration.md +33 -50
- package/package.json +8 -5
- package/src/c4/layout.ts +68 -10
- package/src/c4/parser.ts +0 -16
- package/src/c4/renderer.ts +1 -5
- package/src/class/layout.ts +0 -1
- package/src/class/parser.ts +28 -0
- package/src/class/renderer.ts +5 -26
- package/src/cli.ts +673 -2
- package/src/completion.ts +58 -0
- package/src/d3.ts +58 -106
- package/src/dgmo-router.ts +0 -57
- package/src/echarts.ts +96 -55
- package/src/er/classify.ts +206 -0
- package/src/er/layout.ts +259 -94
- package/src/er/parser.ts +30 -1
- package/src/er/renderer.ts +231 -18
- package/src/graph/flowchart-parser.ts +27 -4
- package/src/graph/flowchart-renderer.ts +1 -2
- package/src/graph/state-parser.ts +0 -1
- package/src/graph/state-renderer.ts +1 -3
- package/src/index.ts +10 -0
- package/src/infra/compute.ts +0 -7
- package/src/infra/layout.ts +60 -15
- package/src/infra/parser.ts +46 -4
- package/src/infra/renderer.ts +376 -47
- package/src/initiative-status/layout.ts +46 -30
- package/src/initiative-status/renderer.ts +5 -25
- package/src/kanban/parser.ts +0 -2
- package/src/org/layout.ts +0 -4
- package/src/org/renderer.ts +7 -28
- package/src/sequence/parser.ts +14 -11
- package/src/sequence/renderer.ts +0 -2
- package/src/sequence/tag-resolution.ts +0 -1
- package/src/sitemap/layout.ts +1 -14
- package/src/sitemap/parser.ts +1 -2
- package/src/sitemap/renderer.ts +0 -3
- package/src/utils/arrows.ts +7 -7
- package/src/utils/export-container.ts +40 -0
- package/.claude/skills/dgmo-chart/SKILL.md +0 -141
- package/.claude/skills/dgmo-flowchart/SKILL.md +0 -61
- package/.claude/skills/dgmo-generate/SKILL.md +0 -59
- package/.claude/skills/dgmo-sequence/SKILL.md +0 -104
package/dist/index.cjs
CHANGED
|
@@ -1809,12 +1809,12 @@ var SYNC_LABELED_RE, ASYNC_LABELED_RE, RETURN_SYNC_LABELED_RE, RETURN_ASYNC_LABE
|
|
|
1809
1809
|
var init_arrows = __esm({
|
|
1810
1810
|
"src/utils/arrows.ts"() {
|
|
1811
1811
|
"use strict";
|
|
1812
|
-
SYNC_LABELED_RE = /^(
|
|
1813
|
-
ASYNC_LABELED_RE = /^(
|
|
1814
|
-
RETURN_SYNC_LABELED_RE = /^(
|
|
1815
|
-
RETURN_ASYNC_LABELED_RE = /^(
|
|
1816
|
-
BIDI_SYNC_RE = /^(
|
|
1817
|
-
BIDI_ASYNC_RE = /^(
|
|
1812
|
+
SYNC_LABELED_RE = /^(.+?)\s+-(.+)->\s+(.+)$/;
|
|
1813
|
+
ASYNC_LABELED_RE = /^(.+?)\s+~(.+)~>\s+(.+)$/;
|
|
1814
|
+
RETURN_SYNC_LABELED_RE = /^(.+?)\s+<-(.+)-\s+(.+)$/;
|
|
1815
|
+
RETURN_ASYNC_LABELED_RE = /^(.+?)\s+<~(.+)~\s+(.+)$/;
|
|
1816
|
+
BIDI_SYNC_RE = /^(.+?)\s+<-(.+)->\s+(.+)$/;
|
|
1817
|
+
BIDI_ASYNC_RE = /^(.+?)\s+<~(.+)~>\s+(.+)$/;
|
|
1818
1818
|
ARROW_CHARS = ["->", "~>"];
|
|
1819
1819
|
}
|
|
1820
1820
|
});
|
|
@@ -2223,7 +2223,7 @@ function parseSequenceDgmo(content) {
|
|
|
2223
2223
|
continue;
|
|
2224
2224
|
}
|
|
2225
2225
|
const bidiPlainMatch = arrowCore.match(
|
|
2226
|
-
/^(
|
|
2226
|
+
/^(.+?)\s*(?:<->|<~>)\s*(.+)/
|
|
2227
2227
|
);
|
|
2228
2228
|
if (bidiPlainMatch) {
|
|
2229
2229
|
pushError(
|
|
@@ -2232,8 +2232,8 @@ function parseSequenceDgmo(content) {
|
|
|
2232
2232
|
);
|
|
2233
2233
|
continue;
|
|
2234
2234
|
}
|
|
2235
|
-
const bareReturnSync = arrowCore.match(/^(
|
|
2236
|
-
const bareReturnAsync = arrowCore.match(/^(
|
|
2235
|
+
const bareReturnSync = arrowCore.match(/^(.+?)\s+<-\s+(.+)$/);
|
|
2236
|
+
const bareReturnAsync = arrowCore.match(/^(.+?)\s+<~\s+(.+)$/);
|
|
2237
2237
|
const bareReturn = bareReturnSync || bareReturnAsync;
|
|
2238
2238
|
if (bareReturn) {
|
|
2239
2239
|
const to = bareReturn[1];
|
|
@@ -2244,8 +2244,8 @@ function parseSequenceDgmo(content) {
|
|
|
2244
2244
|
);
|
|
2245
2245
|
continue;
|
|
2246
2246
|
}
|
|
2247
|
-
const bareCallSync = arrowCore.match(/^(
|
|
2248
|
-
const bareCallAsync = arrowCore.match(/^(
|
|
2247
|
+
const bareCallSync = arrowCore.match(/^(.+?)\s*->\s*(.+)$/);
|
|
2248
|
+
const bareCallAsync = arrowCore.match(/^(.+?)\s*~>\s*(.+)$/);
|
|
2249
2249
|
const bareCall = bareCallSync || bareCallAsync;
|
|
2250
2250
|
if (bareCall) {
|
|
2251
2251
|
contentStarted = true;
|
|
@@ -2497,21 +2497,22 @@ var init_parser = __esm({
|
|
|
2497
2497
|
"networking",
|
|
2498
2498
|
"frontend"
|
|
2499
2499
|
]);
|
|
2500
|
-
IS_A_PATTERN = /^(
|
|
2501
|
-
POSITION_ONLY_PATTERN = /^(
|
|
2500
|
+
IS_A_PATTERN = /^([^:]+?)\s+is\s+an?\s+(\w+)(?:\s+(.+))?$/i;
|
|
2501
|
+
POSITION_ONLY_PATTERN = /^([^:]+?)\s+position\s+(-?\d+)$/i;
|
|
2502
2502
|
COLORED_PARTICIPANT_PATTERN = /^(\S+?)\(([^)]+)\)\s*$/;
|
|
2503
2503
|
GROUP_HEADING_PATTERN = /^\[(.+?)(?:\(([^)]+)\))?\]\s*$/;
|
|
2504
2504
|
LEGACY_GROUP_PATTERN = /^##\s+(.+?)(?:\(([^)]+)\))?\s*$/;
|
|
2505
2505
|
SECTION_PATTERN = /^==\s+(.+?)(?:\s*==)?\s*$/;
|
|
2506
2506
|
ARROW_PATTERN = /\S+\s*(?:<-\S+-|<~\S+~|-\S+->|~\S+~>|->|~>|<-|<~)\s*\S+/;
|
|
2507
|
-
NOTE_SINGLE = /^note(?:\s+(right|left)\s+of\s+(
|
|
2508
|
-
NOTE_MULTI = /^note(?:\s+(right|left)\s+of\s+(
|
|
2507
|
+
NOTE_SINGLE = /^note(?:\s+(right|left)\s+of\s+(.+?))?\s*:\s*(.+)$/i;
|
|
2508
|
+
NOTE_MULTI = /^note(?:\s+(right|left)\s+of\s+(.+?))?\s*:?\s*$/i;
|
|
2509
2509
|
}
|
|
2510
2510
|
});
|
|
2511
2511
|
|
|
2512
2512
|
// src/graph/flowchart-parser.ts
|
|
2513
2513
|
var flowchart_parser_exports = {};
|
|
2514
2514
|
__export(flowchart_parser_exports, {
|
|
2515
|
+
extractSymbols: () => extractSymbols,
|
|
2515
2516
|
looksLikeFlowchart: () => looksLikeFlowchart,
|
|
2516
2517
|
parseFlowchart: () => parseFlowchart
|
|
2517
2518
|
});
|
|
@@ -2555,7 +2556,6 @@ function parseNodeRef(text, palette) {
|
|
|
2555
2556
|
}
|
|
2556
2557
|
function splitArrows(line10) {
|
|
2557
2558
|
const segments = [];
|
|
2558
|
-
const arrowRe = /(?:^|\s)-([^>\s(][^(>]*?)?\s*(?:\(([^)]+)\))?\s*->|(?:^|\s)->/g;
|
|
2559
2559
|
let lastIndex = 0;
|
|
2560
2560
|
const arrowPositions = [];
|
|
2561
2561
|
let searchFrom = 0;
|
|
@@ -2796,7 +2796,20 @@ function looksLikeFlowchart(content) {
|
|
|
2796
2796
|
/->[ \t]*[\[(<\/]/.test(content);
|
|
2797
2797
|
return shapeNearArrow;
|
|
2798
2798
|
}
|
|
2799
|
-
|
|
2799
|
+
function extractSymbols(docText) {
|
|
2800
|
+
const entities = [];
|
|
2801
|
+
let inMetadata = true;
|
|
2802
|
+
for (const rawLine of docText.split("\n")) {
|
|
2803
|
+
const line10 = rawLine.trim();
|
|
2804
|
+
if (inMetadata && /^[a-z-]+\s*:/i.test(line10)) continue;
|
|
2805
|
+
inMetadata = false;
|
|
2806
|
+
if (line10.length === 0 || /^\s/.test(rawLine)) continue;
|
|
2807
|
+
const m = NODE_ID_RE.exec(line10);
|
|
2808
|
+
if (m && !entities.includes(m[1])) entities.push(m[1]);
|
|
2809
|
+
}
|
|
2810
|
+
return { kind: "flowchart", entities, keywords: [] };
|
|
2811
|
+
}
|
|
2812
|
+
var LEGACY_GROUP_RE, NODE_ID_RE;
|
|
2800
2813
|
var init_flowchart_parser = __esm({
|
|
2801
2814
|
"src/graph/flowchart-parser.ts"() {
|
|
2802
2815
|
"use strict";
|
|
@@ -2804,6 +2817,7 @@ var init_flowchart_parser = __esm({
|
|
|
2804
2817
|
init_diagnostics();
|
|
2805
2818
|
init_parsing();
|
|
2806
2819
|
LEGACY_GROUP_RE = /^##\s+/;
|
|
2820
|
+
NODE_ID_RE = /^([a-zA-Z_][\w-]*)[\s([</{]/;
|
|
2807
2821
|
}
|
|
2808
2822
|
});
|
|
2809
2823
|
|
|
@@ -3079,6 +3093,7 @@ var init_state_parser = __esm({
|
|
|
3079
3093
|
// src/class/parser.ts
|
|
3080
3094
|
var parser_exports2 = {};
|
|
3081
3095
|
__export(parser_exports2, {
|
|
3096
|
+
extractSymbols: () => extractSymbols2,
|
|
3082
3097
|
looksLikeClassDiagram: () => looksLikeClassDiagram,
|
|
3083
3098
|
parseClassDiagram: () => parseClassDiagram
|
|
3084
3099
|
});
|
|
@@ -3326,6 +3341,23 @@ function looksLikeClassDiagram(content) {
|
|
|
3326
3341
|
if (hasRelationship && hasClassDecl && hasIndentedMember) return true;
|
|
3327
3342
|
return false;
|
|
3328
3343
|
}
|
|
3344
|
+
function extractSymbols2(docText) {
|
|
3345
|
+
const entities = [];
|
|
3346
|
+
let inMetadata = true;
|
|
3347
|
+
for (const rawLine of docText.split("\n")) {
|
|
3348
|
+
const line10 = rawLine.trim();
|
|
3349
|
+
if (inMetadata && /^[a-z-]+\s*:/i.test(line10)) continue;
|
|
3350
|
+
inMetadata = false;
|
|
3351
|
+
if (line10.length === 0 || /^\s/.test(rawLine)) continue;
|
|
3352
|
+
const m = CLASS_DECL_RE.exec(line10);
|
|
3353
|
+
if (m && !entities.includes(m[1])) entities.push(m[1]);
|
|
3354
|
+
}
|
|
3355
|
+
return {
|
|
3356
|
+
kind: "class",
|
|
3357
|
+
entities,
|
|
3358
|
+
keywords: ["extends", "implements", "abstract", "interface", "enum"]
|
|
3359
|
+
};
|
|
3360
|
+
}
|
|
3329
3361
|
var CLASS_DECL_RE, REL_ARROW_RE, VISIBILITY_RE, STATIC_SUFFIX_RE, METHOD_RE, FIELD_RE, ARROW_TO_TYPE;
|
|
3330
3362
|
var init_parser2 = __esm({
|
|
3331
3363
|
"src/class/parser.ts"() {
|
|
@@ -3353,6 +3385,7 @@ var init_parser2 = __esm({
|
|
|
3353
3385
|
// src/er/parser.ts
|
|
3354
3386
|
var parser_exports3 = {};
|
|
3355
3387
|
__export(parser_exports3, {
|
|
3388
|
+
extractSymbols: () => extractSymbols3,
|
|
3356
3389
|
looksLikeERDiagram: () => looksLikeERDiagram,
|
|
3357
3390
|
parseERDiagram: () => parseERDiagram
|
|
3358
3391
|
});
|
|
@@ -3655,6 +3688,25 @@ function looksLikeERDiagram(content) {
|
|
|
3655
3688
|
if (hasRelationship && hasTableDecl) return true;
|
|
3656
3689
|
return false;
|
|
3657
3690
|
}
|
|
3691
|
+
function extractSymbols3(docText) {
|
|
3692
|
+
const entities = [];
|
|
3693
|
+
let inMetadata = true;
|
|
3694
|
+
for (const rawLine of docText.split("\n")) {
|
|
3695
|
+
const line10 = rawLine.trim();
|
|
3696
|
+
if (inMetadata && /^chart\s*:/i.test(line10)) continue;
|
|
3697
|
+
if (inMetadata && /^[a-z-]+\s*:/i.test(line10)) continue;
|
|
3698
|
+
inMetadata = false;
|
|
3699
|
+
if (line10.length === 0) continue;
|
|
3700
|
+
if (/^\s/.test(rawLine)) continue;
|
|
3701
|
+
const m = TABLE_DECL_RE.exec(line10);
|
|
3702
|
+
if (m) entities.push(m[1]);
|
|
3703
|
+
}
|
|
3704
|
+
return {
|
|
3705
|
+
kind: "er",
|
|
3706
|
+
entities,
|
|
3707
|
+
keywords: ["pk", "fk", "unique", "nullable", "1", "*", "?"]
|
|
3708
|
+
};
|
|
3709
|
+
}
|
|
3658
3710
|
var TABLE_DECL_RE, COLUMN_RE, INDENT_REL_RE, CONSTRAINT_MAP, REL_SYMBOLIC_RE, REL_KEYWORD_RE, KEYWORD_TO_SYMBOL;
|
|
3659
3711
|
var init_parser3 = __esm({
|
|
3660
3712
|
"src/er/parser.ts"() {
|
|
@@ -4136,10 +4188,12 @@ function buildExtendedChartOption(parsed, palette, isDark) {
|
|
|
4136
4188
|
);
|
|
4137
4189
|
}
|
|
4138
4190
|
if (parsed.type === "chord") {
|
|
4191
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
4139
4192
|
return buildChordOption(
|
|
4140
4193
|
parsed,
|
|
4141
4194
|
textColor,
|
|
4142
4195
|
colors,
|
|
4196
|
+
bg,
|
|
4143
4197
|
titleConfig,
|
|
4144
4198
|
tooltipTheme
|
|
4145
4199
|
);
|
|
@@ -4157,6 +4211,7 @@ function buildExtendedChartOption(parsed, palette, isDark) {
|
|
|
4157
4211
|
);
|
|
4158
4212
|
}
|
|
4159
4213
|
if (parsed.type === "scatter") {
|
|
4214
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
4160
4215
|
return buildScatterOption(
|
|
4161
4216
|
parsed,
|
|
4162
4217
|
palette,
|
|
@@ -4164,15 +4219,18 @@ function buildExtendedChartOption(parsed, palette, isDark) {
|
|
|
4164
4219
|
axisLineColor,
|
|
4165
4220
|
gridOpacity,
|
|
4166
4221
|
colors,
|
|
4222
|
+
bg,
|
|
4167
4223
|
titleConfig,
|
|
4168
4224
|
tooltipTheme
|
|
4169
4225
|
);
|
|
4170
4226
|
}
|
|
4171
4227
|
if (parsed.type === "funnel") {
|
|
4228
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
4172
4229
|
return buildFunnelOption(
|
|
4173
4230
|
parsed,
|
|
4174
4231
|
textColor,
|
|
4175
4232
|
colors,
|
|
4233
|
+
bg,
|
|
4176
4234
|
titleConfig,
|
|
4177
4235
|
tooltipTheme
|
|
4178
4236
|
);
|
|
@@ -4180,6 +4238,7 @@ function buildExtendedChartOption(parsed, palette, isDark) {
|
|
|
4180
4238
|
return buildHeatmapOption(
|
|
4181
4239
|
parsed,
|
|
4182
4240
|
palette,
|
|
4241
|
+
isDark,
|
|
4183
4242
|
textColor,
|
|
4184
4243
|
axisLineColor,
|
|
4185
4244
|
titleConfig,
|
|
@@ -4236,7 +4295,7 @@ function buildSankeyOption(parsed, textColor, colors, titleConfig, tooltipTheme)
|
|
|
4236
4295
|
]
|
|
4237
4296
|
};
|
|
4238
4297
|
}
|
|
4239
|
-
function buildChordOption(parsed, textColor, colors, titleConfig, tooltipTheme) {
|
|
4298
|
+
function buildChordOption(parsed, textColor, colors, bg, titleConfig, tooltipTheme) {
|
|
4240
4299
|
const nodeSet = /* @__PURE__ */ new Set();
|
|
4241
4300
|
if (parsed.links) {
|
|
4242
4301
|
for (const link of parsed.links) {
|
|
@@ -4256,12 +4315,13 @@ function buildChordOption(parsed, textColor, colors, titleConfig, tooltipTheme)
|
|
|
4256
4315
|
}
|
|
4257
4316
|
}
|
|
4258
4317
|
}
|
|
4259
|
-
const categories = nodeNames.map((name, index) =>
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4318
|
+
const categories = nodeNames.map((name, index) => {
|
|
4319
|
+
const stroke2 = colors[index % colors.length];
|
|
4320
|
+
return {
|
|
4321
|
+
name,
|
|
4322
|
+
itemStyle: { color: mix(stroke2, bg, 30), borderColor: stroke2, borderWidth: CHART_BORDER_WIDTH }
|
|
4323
|
+
};
|
|
4324
|
+
});
|
|
4265
4325
|
return {
|
|
4266
4326
|
...CHART_BASE,
|
|
4267
4327
|
title: titleConfig,
|
|
@@ -4429,7 +4489,7 @@ function buildFunctionOption(parsed, palette, textColor, axisLineColor, gridOpac
|
|
|
4429
4489
|
series
|
|
4430
4490
|
};
|
|
4431
4491
|
}
|
|
4432
|
-
function buildScatterOption(parsed, palette, textColor, axisLineColor, gridOpacity, colors, titleConfig, tooltipTheme) {
|
|
4492
|
+
function buildScatterOption(parsed, palette, textColor, axisLineColor, gridOpacity, colors, bg, titleConfig, tooltipTheme) {
|
|
4433
4493
|
const points = parsed.scatterPoints ?? [];
|
|
4434
4494
|
const defaultSize = 15;
|
|
4435
4495
|
const hasCategories = points.some((p) => p.category !== void 0);
|
|
@@ -4461,27 +4521,30 @@ function buildScatterOption(parsed, palette, textColor, axisLineColor, gridOpaci
|
|
|
4461
4521
|
const data = categoryPoints.map((p) => ({
|
|
4462
4522
|
name: p.name,
|
|
4463
4523
|
value: hasSize ? [p.x, p.y, p.size ?? 0] : [p.x, p.y],
|
|
4464
|
-
...p.color && {
|
|
4524
|
+
...p.color && {
|
|
4525
|
+
itemStyle: { color: mix(p.color, bg, 30), borderColor: p.color, borderWidth: CHART_BORDER_WIDTH }
|
|
4526
|
+
}
|
|
4465
4527
|
}));
|
|
4466
4528
|
return {
|
|
4467
4529
|
name: category,
|
|
4468
4530
|
type: "scatter",
|
|
4469
4531
|
data,
|
|
4470
4532
|
...hasSize ? { symbolSize: (val) => val[2] } : { symbolSize: defaultSize },
|
|
4471
|
-
itemStyle: { color: catColor },
|
|
4533
|
+
itemStyle: { color: mix(catColor, bg, 30), borderColor: catColor, borderWidth: CHART_BORDER_WIDTH },
|
|
4472
4534
|
label: labelConfig,
|
|
4473
4535
|
emphasis: emphasisConfig
|
|
4474
4536
|
};
|
|
4475
4537
|
});
|
|
4476
4538
|
} else {
|
|
4477
|
-
const data = points.map((p, index) =>
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4539
|
+
const data = points.map((p, index) => {
|
|
4540
|
+
const stroke2 = p.color ?? colors[index % colors.length];
|
|
4541
|
+
return {
|
|
4542
|
+
name: p.name,
|
|
4543
|
+
value: hasSize ? [p.x, p.y, p.size ?? 0] : [p.x, p.y],
|
|
4544
|
+
...hasSize ? { symbolSize: p.size ?? defaultSize } : { symbolSize: defaultSize },
|
|
4545
|
+
itemStyle: { color: mix(stroke2, bg, 30), borderColor: stroke2, borderWidth: CHART_BORDER_WIDTH }
|
|
4546
|
+
};
|
|
4547
|
+
});
|
|
4485
4548
|
series = [
|
|
4486
4549
|
{
|
|
4487
4550
|
type: "scatter",
|
|
@@ -4584,7 +4647,8 @@ function buildScatterOption(parsed, palette, textColor, axisLineColor, gridOpaci
|
|
|
4584
4647
|
series
|
|
4585
4648
|
};
|
|
4586
4649
|
}
|
|
4587
|
-
function buildHeatmapOption(parsed, palette, textColor, axisLineColor, titleConfig, tooltipTheme) {
|
|
4650
|
+
function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, titleConfig, tooltipTheme) {
|
|
4651
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
4588
4652
|
const heatmapRows = parsed.heatmapRows ?? [];
|
|
4589
4653
|
const columns = parsed.columns ?? [];
|
|
4590
4654
|
const rowLabels = heatmapRows.map((r) => r.label);
|
|
@@ -4655,10 +4719,10 @@ function buildHeatmapOption(parsed, palette, textColor, axisLineColor, titleConf
|
|
|
4655
4719
|
top: "center",
|
|
4656
4720
|
inRange: {
|
|
4657
4721
|
color: [
|
|
4658
|
-
palette.primary,
|
|
4659
|
-
palette.colors.cyan,
|
|
4660
|
-
palette.colors.yellow,
|
|
4661
|
-
palette.colors.orange
|
|
4722
|
+
mix(palette.primary, bg, 30),
|
|
4723
|
+
mix(palette.colors.cyan, bg, 30),
|
|
4724
|
+
mix(palette.colors.yellow, bg, 30),
|
|
4725
|
+
mix(palette.colors.orange, bg, 30)
|
|
4662
4726
|
]
|
|
4663
4727
|
},
|
|
4664
4728
|
textStyle: {
|
|
@@ -4669,9 +4733,13 @@ function buildHeatmapOption(parsed, palette, textColor, axisLineColor, titleConf
|
|
|
4669
4733
|
{
|
|
4670
4734
|
type: "heatmap",
|
|
4671
4735
|
data,
|
|
4736
|
+
itemStyle: {
|
|
4737
|
+
borderWidth: 2,
|
|
4738
|
+
borderColor: bg
|
|
4739
|
+
},
|
|
4672
4740
|
label: {
|
|
4673
4741
|
show: true,
|
|
4674
|
-
color:
|
|
4742
|
+
color: textColor,
|
|
4675
4743
|
fontSize: 14,
|
|
4676
4744
|
fontWeight: "bold"
|
|
4677
4745
|
},
|
|
@@ -4686,17 +4754,21 @@ function buildHeatmapOption(parsed, palette, textColor, axisLineColor, titleConf
|
|
|
4686
4754
|
]
|
|
4687
4755
|
};
|
|
4688
4756
|
}
|
|
4689
|
-
function buildFunnelOption(parsed, textColor, colors, titleConfig, tooltipTheme) {
|
|
4757
|
+
function buildFunnelOption(parsed, textColor, colors, bg, titleConfig, tooltipTheme) {
|
|
4690
4758
|
const sorted = [...parsed.data].sort((a, b) => b.value - a.value);
|
|
4691
4759
|
const topValue = sorted.length > 0 ? sorted[0].value : 1;
|
|
4692
|
-
const data = sorted.map((d) =>
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4760
|
+
const data = sorted.map((d) => {
|
|
4761
|
+
const stroke2 = d.color ?? colors[parsed.data.indexOf(d) % colors.length];
|
|
4762
|
+
return {
|
|
4763
|
+
name: d.label,
|
|
4764
|
+
value: d.value,
|
|
4765
|
+
itemStyle: {
|
|
4766
|
+
color: mix(stroke2, bg, 30),
|
|
4767
|
+
borderColor: stroke2,
|
|
4768
|
+
borderWidth: CHART_BORDER_WIDTH
|
|
4769
|
+
}
|
|
4770
|
+
};
|
|
4771
|
+
});
|
|
4700
4772
|
const prevValueMap = /* @__PURE__ */ new Map();
|
|
4701
4773
|
for (let i = 0; i < sorted.length; i++) {
|
|
4702
4774
|
prevValueMap.set(
|
|
@@ -4842,23 +4914,24 @@ function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacit
|
|
|
4842
4914
|
function buildSimpleChartOption(parsed, palette, isDark, chartWidth) {
|
|
4843
4915
|
if (parsed.error) return {};
|
|
4844
4916
|
const { textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme } = buildChartCommons(parsed, palette, isDark);
|
|
4917
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
4845
4918
|
switch (parsed.type) {
|
|
4846
4919
|
case "bar":
|
|
4847
|
-
return buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth);
|
|
4920
|
+
return buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, tooltipTheme, chartWidth);
|
|
4848
4921
|
case "bar-stacked":
|
|
4849
|
-
return buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth);
|
|
4922
|
+
return buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, tooltipTheme, chartWidth);
|
|
4850
4923
|
case "line":
|
|
4851
4924
|
return parsed.seriesNames ? buildMultiLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) : buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
|
|
4852
4925
|
case "area":
|
|
4853
4926
|
return buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
|
|
4854
4927
|
case "pie":
|
|
4855
|
-
return buildPieOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), titleConfig, tooltipTheme, false);
|
|
4928
|
+
return buildPieOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), bg, titleConfig, tooltipTheme, false);
|
|
4856
4929
|
case "doughnut":
|
|
4857
|
-
return buildPieOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), titleConfig, tooltipTheme, true);
|
|
4930
|
+
return buildPieOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), bg, titleConfig, tooltipTheme, true);
|
|
4858
4931
|
case "radar":
|
|
4859
|
-
return buildRadarOption(parsed, palette, textColor, gridOpacity,
|
|
4932
|
+
return buildRadarOption(parsed, palette, isDark, textColor, gridOpacity, titleConfig, tooltipTheme);
|
|
4860
4933
|
case "polar-area":
|
|
4861
|
-
return buildPolarAreaOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), titleConfig, tooltipTheme);
|
|
4934
|
+
return buildPolarAreaOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), bg, titleConfig, tooltipTheme);
|
|
4862
4935
|
}
|
|
4863
4936
|
}
|
|
4864
4937
|
function makeChartGrid(options) {
|
|
@@ -4870,14 +4943,17 @@ function makeChartGrid(options) {
|
|
|
4870
4943
|
containLabel: true
|
|
4871
4944
|
};
|
|
4872
4945
|
}
|
|
4873
|
-
function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
|
|
4946
|
+
function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, tooltipTheme, chartWidth) {
|
|
4874
4947
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
4875
4948
|
const isHorizontal = parsed.orientation === "horizontal";
|
|
4876
4949
|
const labels = parsed.data.map((d) => d.label);
|
|
4877
|
-
const data = parsed.data.map((d, i) =>
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4950
|
+
const data = parsed.data.map((d, i) => {
|
|
4951
|
+
const stroke2 = d.color ?? colors[i % colors.length];
|
|
4952
|
+
return {
|
|
4953
|
+
value: d.value,
|
|
4954
|
+
itemStyle: { color: mix(stroke2, bg, 30), borderColor: stroke2, borderWidth: CHART_BORDER_WIDTH }
|
|
4955
|
+
};
|
|
4956
|
+
});
|
|
4881
4957
|
const hCatGap = isHorizontal && yLabel ? Math.max(40, Math.max(...labels.map((l) => l.length)) * 8 + 16) : void 0;
|
|
4882
4958
|
const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap, !isHorizontal ? chartWidth : void 0);
|
|
4883
4959
|
const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel);
|
|
@@ -5058,12 +5134,15 @@ function segmentLabelFormatter(mode) {
|
|
|
5058
5134
|
return "{b} \u2014 {c} ({d}%)";
|
|
5059
5135
|
}
|
|
5060
5136
|
}
|
|
5061
|
-
function buildPieOption(parsed, textColor, colors, titleConfig, tooltipTheme, isDoughnut) {
|
|
5062
|
-
const data = parsed.data.map((d, i) =>
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5137
|
+
function buildPieOption(parsed, textColor, colors, bg, titleConfig, tooltipTheme, isDoughnut) {
|
|
5138
|
+
const data = parsed.data.map((d, i) => {
|
|
5139
|
+
const stroke2 = d.color ?? colors[i % colors.length];
|
|
5140
|
+
return {
|
|
5141
|
+
name: d.label,
|
|
5142
|
+
value: d.value,
|
|
5143
|
+
itemStyle: { color: mix(stroke2, bg, 30), borderColor: stroke2, borderWidth: CHART_BORDER_WIDTH }
|
|
5144
|
+
};
|
|
5145
|
+
});
|
|
5067
5146
|
return {
|
|
5068
5147
|
...CHART_BASE,
|
|
5069
5148
|
title: titleConfig,
|
|
@@ -5088,7 +5167,8 @@ function buildPieOption(parsed, textColor, colors, titleConfig, tooltipTheme, is
|
|
|
5088
5167
|
]
|
|
5089
5168
|
};
|
|
5090
5169
|
}
|
|
5091
|
-
function buildRadarOption(parsed, palette, textColor, gridOpacity,
|
|
5170
|
+
function buildRadarOption(parsed, palette, isDark, textColor, gridOpacity, titleConfig, tooltipTheme) {
|
|
5171
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
5092
5172
|
const radarColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
|
|
5093
5173
|
const values = parsed.data.map((d) => d.value);
|
|
5094
5174
|
const maxValue = Math.max(...values) * 1.15;
|
|
@@ -5125,7 +5205,7 @@ function buildRadarOption(parsed, palette, textColor, gridOpacity, colors, title
|
|
|
5125
5205
|
{
|
|
5126
5206
|
value: values,
|
|
5127
5207
|
name: parsed.series ?? "Value",
|
|
5128
|
-
areaStyle: { color: radarColor,
|
|
5208
|
+
areaStyle: { color: mix(radarColor, bg, 30) },
|
|
5129
5209
|
lineStyle: { color: radarColor },
|
|
5130
5210
|
itemStyle: { color: radarColor },
|
|
5131
5211
|
symbol: "circle",
|
|
@@ -5144,12 +5224,15 @@ function buildRadarOption(parsed, palette, textColor, gridOpacity, colors, title
|
|
|
5144
5224
|
]
|
|
5145
5225
|
};
|
|
5146
5226
|
}
|
|
5147
|
-
function buildPolarAreaOption(parsed, textColor, colors, titleConfig, tooltipTheme) {
|
|
5148
|
-
const data = parsed.data.map((d, i) =>
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5227
|
+
function buildPolarAreaOption(parsed, textColor, colors, bg, titleConfig, tooltipTheme) {
|
|
5228
|
+
const data = parsed.data.map((d, i) => {
|
|
5229
|
+
const stroke2 = d.color ?? colors[i % colors.length];
|
|
5230
|
+
return {
|
|
5231
|
+
name: d.label,
|
|
5232
|
+
value: d.value,
|
|
5233
|
+
itemStyle: { color: mix(stroke2, bg, 30), borderColor: stroke2, borderWidth: CHART_BORDER_WIDTH }
|
|
5234
|
+
};
|
|
5235
|
+
});
|
|
5153
5236
|
return {
|
|
5154
5237
|
...CHART_BASE,
|
|
5155
5238
|
title: titleConfig,
|
|
@@ -5175,7 +5258,7 @@ function buildPolarAreaOption(parsed, textColor, colors, titleConfig, tooltipThe
|
|
|
5175
5258
|
]
|
|
5176
5259
|
};
|
|
5177
5260
|
}
|
|
5178
|
-
function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
|
|
5261
|
+
function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, tooltipTheme, chartWidth) {
|
|
5179
5262
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
5180
5263
|
const isHorizontal = parsed.orientation === "horizontal";
|
|
5181
5264
|
const seriesNames = parsed.seriesNames ?? [];
|
|
@@ -5190,12 +5273,12 @@ function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor,
|
|
|
5190
5273
|
type: "bar",
|
|
5191
5274
|
stack: "total",
|
|
5192
5275
|
data,
|
|
5193
|
-
itemStyle: { color },
|
|
5276
|
+
itemStyle: { color: mix(color, bg, 30), borderColor: color, borderWidth: CHART_BORDER_WIDTH },
|
|
5194
5277
|
label: {
|
|
5195
5278
|
show: true,
|
|
5196
5279
|
position: "inside",
|
|
5197
5280
|
formatter: "{c}",
|
|
5198
|
-
color:
|
|
5281
|
+
color: textColor,
|
|
5199
5282
|
fontSize: 14,
|
|
5200
5283
|
fontWeight: "bold",
|
|
5201
5284
|
fontFamily: FONT_FAMILY
|
|
@@ -5267,7 +5350,7 @@ async function renderExtendedChartForExport(content, theme, palette, options) {
|
|
|
5267
5350
|
chart.dispose();
|
|
5268
5351
|
}
|
|
5269
5352
|
}
|
|
5270
|
-
var echarts, EMPHASIS_SELF, CHART_BASE, ECHART_EXPORT_WIDTH, ECHART_EXPORT_HEIGHT, STANDARD_CHART_TYPES;
|
|
5353
|
+
var echarts, EMPHASIS_SELF, CHART_BASE, CHART_BORDER_WIDTH, ECHART_EXPORT_WIDTH, ECHART_EXPORT_HEIGHT, STANDARD_CHART_TYPES;
|
|
5271
5354
|
var init_echarts = __esm({
|
|
5272
5355
|
"src/echarts.ts"() {
|
|
5273
5356
|
"use strict";
|
|
@@ -5275,12 +5358,14 @@ var init_echarts = __esm({
|
|
|
5275
5358
|
init_fonts();
|
|
5276
5359
|
init_branding();
|
|
5277
5360
|
init_palettes();
|
|
5361
|
+
init_color_utils();
|
|
5278
5362
|
init_chart();
|
|
5279
5363
|
init_diagnostics();
|
|
5280
5364
|
init_colors();
|
|
5281
5365
|
init_parsing();
|
|
5282
5366
|
EMPHASIS_SELF = { focus: "self", blurScope: "global" };
|
|
5283
5367
|
CHART_BASE = { backgroundColor: "transparent", animation: false };
|
|
5368
|
+
CHART_BORDER_WIDTH = 2;
|
|
5284
5369
|
ECHART_EXPORT_WIDTH = 1200;
|
|
5285
5370
|
ECHART_EXPORT_HEIGHT = 800;
|
|
5286
5371
|
STANDARD_CHART_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -6995,6 +7080,7 @@ var init_types2 = __esm({
|
|
|
6995
7080
|
// src/infra/parser.ts
|
|
6996
7081
|
var parser_exports9 = {};
|
|
6997
7082
|
__export(parser_exports9, {
|
|
7083
|
+
extractSymbols: () => extractSymbols4,
|
|
6998
7084
|
parseInfra: () => parseInfra
|
|
6999
7085
|
});
|
|
7000
7086
|
function nodeId2(name) {
|
|
@@ -7037,7 +7123,6 @@ function parseInfra(content) {
|
|
|
7037
7123
|
error: null
|
|
7038
7124
|
};
|
|
7039
7125
|
const nodeMap = /* @__PURE__ */ new Map();
|
|
7040
|
-
const edgeNodeId = "edge";
|
|
7041
7126
|
const setError = (line10, message) => {
|
|
7042
7127
|
const diag = makeDgmoError(line10, message);
|
|
7043
7128
|
result.diagnostics.push(diag);
|
|
@@ -7403,6 +7488,38 @@ function parseInfra(content) {
|
|
|
7403
7488
|
}
|
|
7404
7489
|
return result;
|
|
7405
7490
|
}
|
|
7491
|
+
function extractSymbols4(docText) {
|
|
7492
|
+
const entities = [];
|
|
7493
|
+
let inMetadata = true;
|
|
7494
|
+
let inTagGroup = false;
|
|
7495
|
+
for (const rawLine of docText.split("\n")) {
|
|
7496
|
+
const line10 = rawLine.trim();
|
|
7497
|
+
if (line10.length === 0) continue;
|
|
7498
|
+
const indented = /^\s/.test(rawLine);
|
|
7499
|
+
if (inMetadata) {
|
|
7500
|
+
if (!indented && !/^[a-z-]+\s*:/i.test(line10)) inMetadata = false;
|
|
7501
|
+
else continue;
|
|
7502
|
+
}
|
|
7503
|
+
if (!indented) {
|
|
7504
|
+
if (/^tag\s*:/i.test(line10)) {
|
|
7505
|
+
inTagGroup = true;
|
|
7506
|
+
continue;
|
|
7507
|
+
}
|
|
7508
|
+
inTagGroup = false;
|
|
7509
|
+
if (/^\[/.test(line10)) continue;
|
|
7510
|
+
const m = COMPONENT_RE.exec(line10);
|
|
7511
|
+
if (m && !entities.includes(m[1])) entities.push(m[1]);
|
|
7512
|
+
} else {
|
|
7513
|
+
if (inTagGroup) continue;
|
|
7514
|
+
if (/^->/.test(line10)) continue;
|
|
7515
|
+
if (/^-[^>]+-?>/.test(line10)) continue;
|
|
7516
|
+
if (/^\w[\w-]*\s*:/.test(line10)) continue;
|
|
7517
|
+
const m = COMPONENT_RE.exec(line10);
|
|
7518
|
+
if (m && !entities.includes(m[1])) entities.push(m[1]);
|
|
7519
|
+
}
|
|
7520
|
+
}
|
|
7521
|
+
return { kind: "infra", entities, keywords: [] };
|
|
7522
|
+
}
|
|
7406
7523
|
var CONNECTION_RE, SIMPLE_CONNECTION_RE, GROUP_RE, TAG_GROUP_RE, TAG_VALUE_RE, COMPONENT_RE, PIPE_META_RE, PROPERTY_RE, PERCENT_RE, RANGE_RE, EDGE_NODE_NAMES;
|
|
7407
7524
|
var init_parser9 = __esm({
|
|
7408
7525
|
"src/infra/parser.ts"() {
|
|
@@ -8265,7 +8382,6 @@ function layoutOrg(parsed, hiddenCounts, activeTagGroup, hiddenAttributes, expan
|
|
|
8265
8382
|
const visibleGroups = activeTagGroup != null ? legendGroups.filter((g) => g.name.toLowerCase() === activeTagGroup.toLowerCase()) : legendGroups;
|
|
8266
8383
|
const allExpanded = expandAllLegend && activeTagGroup == null;
|
|
8267
8384
|
const effectiveW = (g) => activeTagGroup != null || allExpanded ? g.width : g.minifiedWidth;
|
|
8268
|
-
const effectiveH = (g) => activeTagGroup != null || allExpanded ? g.height : g.minifiedHeight;
|
|
8269
8385
|
if (visibleGroups.length > 0) {
|
|
8270
8386
|
if (legendPosition === "bottom") {
|
|
8271
8387
|
const totalGroupsWidth = visibleGroups.reduce((s, g) => s + effectiveW(g), 0) + (visibleGroups.length - 1) * LEGEND_GROUP_GAP2;
|
|
@@ -8419,6 +8535,35 @@ var init_collapse = __esm({
|
|
|
8419
8535
|
}
|
|
8420
8536
|
});
|
|
8421
8537
|
|
|
8538
|
+
// src/utils/export-container.ts
|
|
8539
|
+
function runInExportContainer(width, height, fn) {
|
|
8540
|
+
const container = document.createElement("div");
|
|
8541
|
+
container.style.width = `${width}px`;
|
|
8542
|
+
container.style.height = `${height}px`;
|
|
8543
|
+
container.style.position = "absolute";
|
|
8544
|
+
container.style.left = "-9999px";
|
|
8545
|
+
document.body.appendChild(container);
|
|
8546
|
+
try {
|
|
8547
|
+
return fn(container);
|
|
8548
|
+
} finally {
|
|
8549
|
+
document.body.removeChild(container);
|
|
8550
|
+
}
|
|
8551
|
+
}
|
|
8552
|
+
function extractExportSvg(container, theme) {
|
|
8553
|
+
const svgEl = container.querySelector("svg");
|
|
8554
|
+
if (!svgEl) return "";
|
|
8555
|
+
if (theme === "transparent") svgEl.style.background = "none";
|
|
8556
|
+
svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
8557
|
+
svgEl.style.fontFamily = FONT_FAMILY;
|
|
8558
|
+
return svgEl.outerHTML;
|
|
8559
|
+
}
|
|
8560
|
+
var init_export_container = __esm({
|
|
8561
|
+
"src/utils/export-container.ts"() {
|
|
8562
|
+
"use strict";
|
|
8563
|
+
init_fonts();
|
|
8564
|
+
}
|
|
8565
|
+
});
|
|
8566
|
+
|
|
8422
8567
|
// src/org/renderer.ts
|
|
8423
8568
|
var renderer_exports = {};
|
|
8424
8569
|
__export(renderer_exports, {
|
|
@@ -8673,31 +8818,16 @@ function renderOrgForExport(content, theme, palette) {
|
|
|
8673
8818
|
const exportHidden = hideOption ? new Set(hideOption.split(",").map((s) => s.trim().toLowerCase())) : void 0;
|
|
8674
8819
|
const layout = layoutOrg(parsed, void 0, void 0, exportHidden);
|
|
8675
8820
|
const isDark = theme === "dark";
|
|
8676
|
-
const container = document.createElement("div");
|
|
8677
8821
|
const titleOffset = parsed.title ? TITLE_HEIGHT : 0;
|
|
8678
8822
|
const exportWidth = layout.width + DIAGRAM_PADDING * 2;
|
|
8679
8823
|
const exportHeight = layout.height + DIAGRAM_PADDING * 2 + titleOffset;
|
|
8680
|
-
container
|
|
8681
|
-
container.style.height = `${exportHeight}px`;
|
|
8682
|
-
container.style.position = "absolute";
|
|
8683
|
-
container.style.left = "-9999px";
|
|
8684
|
-
document.body.appendChild(container);
|
|
8685
|
-
try {
|
|
8824
|
+
return runInExportContainer(exportWidth, exportHeight, (container) => {
|
|
8686
8825
|
renderOrg(container, parsed, layout, palette, isDark, void 0, {
|
|
8687
8826
|
width: exportWidth,
|
|
8688
8827
|
height: exportHeight
|
|
8689
8828
|
});
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
if (theme === "transparent") {
|
|
8693
|
-
svgEl.style.background = "none";
|
|
8694
|
-
}
|
|
8695
|
-
svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
8696
|
-
svgEl.style.fontFamily = FONT_FAMILY;
|
|
8697
|
-
return svgEl.outerHTML;
|
|
8698
|
-
} finally {
|
|
8699
|
-
document.body.removeChild(container);
|
|
8700
|
-
}
|
|
8829
|
+
return extractExportSvg(container, theme);
|
|
8830
|
+
});
|
|
8701
8831
|
}
|
|
8702
8832
|
var d3Selection, DIAGRAM_PADDING, MAX_SCALE, TITLE_HEIGHT, TITLE_FONT_SIZE, LABEL_FONT_SIZE, META_FONT_SIZE, META_LINE_HEIGHT2, HEADER_HEIGHT2, SEPARATOR_GAP2, EDGE_STROKE_WIDTH, NODE_STROKE_WIDTH, CARD_RADIUS, CONTAINER_RADIUS, CONTAINER_LABEL_FONT_SIZE, CONTAINER_META_FONT_SIZE, CONTAINER_META_LINE_HEIGHT2, CONTAINER_HEADER_HEIGHT, COLLAPSE_BAR_HEIGHT, COLLAPSE_BAR_INSET, LEGEND_FIXED_GAP;
|
|
8703
8833
|
var init_renderer = __esm({
|
|
@@ -8705,6 +8835,7 @@ var init_renderer = __esm({
|
|
|
8705
8835
|
"use strict";
|
|
8706
8836
|
d3Selection = __toESM(require("d3-selection"), 1);
|
|
8707
8837
|
init_fonts();
|
|
8838
|
+
init_export_container();
|
|
8708
8839
|
init_color_utils();
|
|
8709
8840
|
init_parser4();
|
|
8710
8841
|
init_layout();
|
|
@@ -10290,7 +10421,6 @@ function renderClassDiagram(container, parsed, layout, palette, isDark, onClickI
|
|
|
10290
10421
|
const scaleY = (availH - DIAGRAM_PADDING4 * 2) / diagramH;
|
|
10291
10422
|
const scale = Math.min(MAX_SCALE3, scaleX, scaleY);
|
|
10292
10423
|
const scaledW = diagramW * scale;
|
|
10293
|
-
const scaledH = diagramH * scale;
|
|
10294
10424
|
const offsetX = (width - scaledW) / 2;
|
|
10295
10425
|
const offsetY = titleHeight + DIAGRAM_PADDING4;
|
|
10296
10426
|
const svg = d3Selection4.select(container).append("svg").attr("width", width).attr("height", height).style("font-family", FONT_FAMILY);
|
|
@@ -10421,15 +10551,9 @@ function renderClassDiagramForExport(content, theme, palette) {
|
|
|
10421
10551
|
if (parsed.error || parsed.classes.length === 0) return "";
|
|
10422
10552
|
const layout = layoutClassDiagram(parsed);
|
|
10423
10553
|
const isDark = theme === "dark";
|
|
10424
|
-
const container = document.createElement("div");
|
|
10425
10554
|
const exportWidth = layout.width + DIAGRAM_PADDING4 * 2;
|
|
10426
10555
|
const exportHeight = layout.height + DIAGRAM_PADDING4 * 2 + (parsed.title ? 40 : 0);
|
|
10427
|
-
container
|
|
10428
|
-
container.style.height = `${exportHeight}px`;
|
|
10429
|
-
container.style.position = "absolute";
|
|
10430
|
-
container.style.left = "-9999px";
|
|
10431
|
-
document.body.appendChild(container);
|
|
10432
|
-
try {
|
|
10556
|
+
return runInExportContainer(exportWidth, exportHeight, (container) => {
|
|
10433
10557
|
renderClassDiagram(
|
|
10434
10558
|
container,
|
|
10435
10559
|
parsed,
|
|
@@ -10439,17 +10563,8 @@ function renderClassDiagramForExport(content, theme, palette) {
|
|
|
10439
10563
|
void 0,
|
|
10440
10564
|
{ width: exportWidth, height: exportHeight }
|
|
10441
10565
|
);
|
|
10442
|
-
|
|
10443
|
-
|
|
10444
|
-
if (theme === "transparent") {
|
|
10445
|
-
svgEl.style.background = "none";
|
|
10446
|
-
}
|
|
10447
|
-
svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
10448
|
-
svgEl.style.fontFamily = FONT_FAMILY;
|
|
10449
|
-
return svgEl.outerHTML;
|
|
10450
|
-
} finally {
|
|
10451
|
-
document.body.removeChild(container);
|
|
10452
|
-
}
|
|
10566
|
+
return extractExportSvg(container, theme);
|
|
10567
|
+
});
|
|
10453
10568
|
}
|
|
10454
10569
|
var d3Selection4, d3Shape2, DIAGRAM_PADDING4, MAX_SCALE3, CLASS_FONT_SIZE, MEMBER_FONT_SIZE, EDGE_LABEL_FONT_SIZE2, EDGE_STROKE_WIDTH3, NODE_STROKE_WIDTH3, MEMBER_LINE_HEIGHT2, COMPARTMENT_PADDING_Y2, MEMBER_PADDING_X, lineGenerator2;
|
|
10455
10570
|
var init_renderer4 = __esm({
|
|
@@ -10458,6 +10573,7 @@ var init_renderer4 = __esm({
|
|
|
10458
10573
|
d3Selection4 = __toESM(require("d3-selection"), 1);
|
|
10459
10574
|
d3Shape2 = __toESM(require("d3-shape"), 1);
|
|
10460
10575
|
init_fonts();
|
|
10576
|
+
init_export_container();
|
|
10461
10577
|
init_color_utils();
|
|
10462
10578
|
init_parser2();
|
|
10463
10579
|
init_layout3();
|
|
@@ -10497,110 +10613,211 @@ function computeNodeDimensions2(table) {
|
|
|
10497
10613
|
const height = headerHeight + columnsHeight + (columnsHeight === 0 ? 4 : 0);
|
|
10498
10614
|
return { width, height, headerHeight, columnsHeight };
|
|
10499
10615
|
}
|
|
10616
|
+
function findConnectedComponents(tableIds, relationships) {
|
|
10617
|
+
const adj = /* @__PURE__ */ new Map();
|
|
10618
|
+
for (const id of tableIds) adj.set(id, /* @__PURE__ */ new Set());
|
|
10619
|
+
for (const rel of relationships) {
|
|
10620
|
+
adj.get(rel.source)?.add(rel.target);
|
|
10621
|
+
adj.get(rel.target)?.add(rel.source);
|
|
10622
|
+
}
|
|
10623
|
+
const visited = /* @__PURE__ */ new Set();
|
|
10624
|
+
const components = [];
|
|
10625
|
+
for (const id of tableIds) {
|
|
10626
|
+
if (visited.has(id)) continue;
|
|
10627
|
+
const comp = [];
|
|
10628
|
+
const queue = [id];
|
|
10629
|
+
while (queue.length > 0) {
|
|
10630
|
+
const cur = queue.shift();
|
|
10631
|
+
if (visited.has(cur)) continue;
|
|
10632
|
+
visited.add(cur);
|
|
10633
|
+
comp.push(cur);
|
|
10634
|
+
for (const nb of adj.get(cur) ?? []) {
|
|
10635
|
+
if (!visited.has(nb)) queue.push(nb);
|
|
10636
|
+
}
|
|
10637
|
+
}
|
|
10638
|
+
components.push(comp);
|
|
10639
|
+
}
|
|
10640
|
+
return components;
|
|
10641
|
+
}
|
|
10642
|
+
function layoutComponent(tables, rels, dimMap) {
|
|
10643
|
+
const nodePositions = /* @__PURE__ */ new Map();
|
|
10644
|
+
const edgePoints = /* @__PURE__ */ new Map();
|
|
10645
|
+
if (tables.length === 1) {
|
|
10646
|
+
const dims = dimMap.get(tables[0].id);
|
|
10647
|
+
nodePositions.set(tables[0].id, { x: dims.width / 2, y: dims.height / 2, ...dims });
|
|
10648
|
+
return { nodePositions, edgePoints, width: dims.width, height: dims.height };
|
|
10649
|
+
}
|
|
10650
|
+
const g = new import_dagre3.default.graphlib.Graph({ multigraph: true });
|
|
10651
|
+
g.setGraph({ rankdir: "LR", nodesep: 40, ranksep: 80, edgesep: 20 });
|
|
10652
|
+
g.setDefaultEdgeLabel(() => ({}));
|
|
10653
|
+
for (const table of tables) {
|
|
10654
|
+
const dims = dimMap.get(table.id);
|
|
10655
|
+
g.setNode(table.id, { width: dims.width, height: dims.height });
|
|
10656
|
+
}
|
|
10657
|
+
for (const rel of rels) {
|
|
10658
|
+
g.setEdge(rel.source, rel.target, { label: rel.label ?? "" }, String(rel.lineNumber));
|
|
10659
|
+
}
|
|
10660
|
+
import_dagre3.default.layout(g);
|
|
10661
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
10662
|
+
for (const table of tables) {
|
|
10663
|
+
const pos = g.node(table.id);
|
|
10664
|
+
const dims = dimMap.get(table.id);
|
|
10665
|
+
minX = Math.min(minX, pos.x - dims.width / 2);
|
|
10666
|
+
minY = Math.min(minY, pos.y - dims.height / 2);
|
|
10667
|
+
maxX = Math.max(maxX, pos.x + dims.width / 2);
|
|
10668
|
+
maxY = Math.max(maxY, pos.y + dims.height / 2);
|
|
10669
|
+
}
|
|
10670
|
+
for (const rel of rels) {
|
|
10671
|
+
const ed = g.edge(rel.source, rel.target, String(rel.lineNumber));
|
|
10672
|
+
for (const pt of ed?.points ?? []) {
|
|
10673
|
+
minX = Math.min(minX, pt.x);
|
|
10674
|
+
minY = Math.min(minY, pt.y);
|
|
10675
|
+
maxX = Math.max(maxX, pt.x);
|
|
10676
|
+
maxY = Math.max(maxY, pt.y);
|
|
10677
|
+
}
|
|
10678
|
+
if (rel.label && (ed?.points ?? []).length > 0) {
|
|
10679
|
+
const pts = ed.points;
|
|
10680
|
+
const mid = pts[Math.floor(pts.length / 2)];
|
|
10681
|
+
const hw = (rel.label.length * 7 + 8) / 2;
|
|
10682
|
+
minX = Math.min(minX, mid.x - hw);
|
|
10683
|
+
maxX = Math.max(maxX, mid.x + hw);
|
|
10684
|
+
}
|
|
10685
|
+
}
|
|
10686
|
+
for (const table of tables) {
|
|
10687
|
+
const pos = g.node(table.id);
|
|
10688
|
+
const dims = dimMap.get(table.id);
|
|
10689
|
+
nodePositions.set(table.id, {
|
|
10690
|
+
x: pos.x - minX,
|
|
10691
|
+
y: pos.y - minY,
|
|
10692
|
+
...dims
|
|
10693
|
+
});
|
|
10694
|
+
}
|
|
10695
|
+
for (const rel of rels) {
|
|
10696
|
+
const ed = g.edge(rel.source, rel.target, String(rel.lineNumber));
|
|
10697
|
+
edgePoints.set(
|
|
10698
|
+
rel.lineNumber,
|
|
10699
|
+
(ed?.points ?? []).map((pt) => ({ x: pt.x - minX, y: pt.y - minY }))
|
|
10700
|
+
);
|
|
10701
|
+
}
|
|
10702
|
+
return {
|
|
10703
|
+
nodePositions,
|
|
10704
|
+
edgePoints,
|
|
10705
|
+
width: Math.max(0, maxX - minX),
|
|
10706
|
+
height: Math.max(0, maxY - minY)
|
|
10707
|
+
};
|
|
10708
|
+
}
|
|
10709
|
+
function packComponents(items) {
|
|
10710
|
+
if (items.length === 0) return [];
|
|
10711
|
+
const sorted = [...items].sort((a, b) => {
|
|
10712
|
+
const aConnected = a.compIds.length > 1 ? 1 : 0;
|
|
10713
|
+
const bConnected = b.compIds.length > 1 ? 1 : 0;
|
|
10714
|
+
if (aConnected !== bConnected) return bConnected - aConnected;
|
|
10715
|
+
return b.compLayout.height - a.compLayout.height;
|
|
10716
|
+
});
|
|
10717
|
+
const totalArea = items.reduce(
|
|
10718
|
+
(s, c) => s + (c.compLayout.width || MIN_WIDTH2) * (c.compLayout.height || HEADER_BASE2),
|
|
10719
|
+
0
|
|
10720
|
+
);
|
|
10721
|
+
const targetW = Math.max(
|
|
10722
|
+
Math.sqrt(totalArea) * 1.5,
|
|
10723
|
+
sorted[0].compLayout.width
|
|
10724
|
+
// at least as wide as the widest component
|
|
10725
|
+
);
|
|
10726
|
+
const placements = [];
|
|
10727
|
+
let curX = 0;
|
|
10728
|
+
let curY = 0;
|
|
10729
|
+
let rowH = 0;
|
|
10730
|
+
for (const item of sorted) {
|
|
10731
|
+
const w = item.compLayout.width || MIN_WIDTH2;
|
|
10732
|
+
const h = item.compLayout.height || HEADER_BASE2;
|
|
10733
|
+
if (curX > 0 && curX + w > targetW) {
|
|
10734
|
+
curY += rowH + COMP_GAP;
|
|
10735
|
+
curX = 0;
|
|
10736
|
+
rowH = 0;
|
|
10737
|
+
}
|
|
10738
|
+
placements.push({ compIds: item.compIds, compLayout: item.compLayout, offsetX: curX, offsetY: curY });
|
|
10739
|
+
curX += w + COMP_GAP;
|
|
10740
|
+
rowH = Math.max(rowH, h);
|
|
10741
|
+
}
|
|
10742
|
+
return placements;
|
|
10743
|
+
}
|
|
10500
10744
|
function layoutERDiagram(parsed) {
|
|
10501
10745
|
if (parsed.tables.length === 0) {
|
|
10502
10746
|
return { nodes: [], edges: [], width: 0, height: 0 };
|
|
10503
10747
|
}
|
|
10504
|
-
const g = new import_dagre3.default.graphlib.Graph();
|
|
10505
|
-
g.setGraph({
|
|
10506
|
-
rankdir: "TB",
|
|
10507
|
-
nodesep: 60,
|
|
10508
|
-
ranksep: 80,
|
|
10509
|
-
edgesep: 20
|
|
10510
|
-
});
|
|
10511
|
-
g.setDefaultEdgeLabel(() => ({}));
|
|
10512
10748
|
const dimMap = /* @__PURE__ */ new Map();
|
|
10513
10749
|
for (const table of parsed.tables) {
|
|
10514
|
-
|
|
10515
|
-
dimMap.set(table.id, dims);
|
|
10516
|
-
g.setNode(table.id, {
|
|
10517
|
-
label: table.name,
|
|
10518
|
-
width: dims.width,
|
|
10519
|
-
height: dims.height
|
|
10520
|
-
});
|
|
10750
|
+
dimMap.set(table.id, computeNodeDimensions2(table));
|
|
10521
10751
|
}
|
|
10522
|
-
|
|
10523
|
-
|
|
10752
|
+
const compIdSets = findConnectedComponents(
|
|
10753
|
+
parsed.tables.map((t) => t.id),
|
|
10754
|
+
parsed.relationships
|
|
10755
|
+
);
|
|
10756
|
+
const tableById = new Map(parsed.tables.map((t) => [t.id, t]));
|
|
10757
|
+
const componentItems = compIdSets.map((ids) => {
|
|
10758
|
+
const tables = ids.map((id) => tableById.get(id));
|
|
10759
|
+
const rels = parsed.relationships.filter((r) => ids.includes(r.source));
|
|
10760
|
+
return { compIds: ids, compLayout: layoutComponent(tables, rels, dimMap) };
|
|
10761
|
+
});
|
|
10762
|
+
const packed = packComponents(componentItems);
|
|
10763
|
+
const placementByTableId = /* @__PURE__ */ new Map();
|
|
10764
|
+
for (const p of packed) {
|
|
10765
|
+
for (const id of p.compIds) placementByTableId.set(id, p);
|
|
10766
|
+
}
|
|
10767
|
+
const placementByRelLine = /* @__PURE__ */ new Map();
|
|
10768
|
+
for (const p of packed) {
|
|
10769
|
+
for (const lineNum of p.compLayout.edgePoints.keys()) {
|
|
10770
|
+
placementByRelLine.set(lineNum, p);
|
|
10771
|
+
}
|
|
10524
10772
|
}
|
|
10525
|
-
import_dagre3.default.layout(g);
|
|
10526
10773
|
const layoutNodes = parsed.tables.map((table) => {
|
|
10527
|
-
const
|
|
10528
|
-
const
|
|
10774
|
+
const p = placementByTableId.get(table.id);
|
|
10775
|
+
const pos = p.compLayout.nodePositions.get(table.id);
|
|
10529
10776
|
return {
|
|
10530
10777
|
...table,
|
|
10531
|
-
x: pos.x,
|
|
10532
|
-
y: pos.y,
|
|
10533
|
-
width:
|
|
10534
|
-
height:
|
|
10535
|
-
headerHeight:
|
|
10536
|
-
columnsHeight:
|
|
10778
|
+
x: pos.x + p.offsetX + HALF_MARGIN,
|
|
10779
|
+
y: pos.y + p.offsetY + HALF_MARGIN,
|
|
10780
|
+
width: pos.width,
|
|
10781
|
+
height: pos.height,
|
|
10782
|
+
headerHeight: pos.headerHeight,
|
|
10783
|
+
columnsHeight: pos.columnsHeight
|
|
10537
10784
|
};
|
|
10538
10785
|
});
|
|
10539
10786
|
const layoutEdges = parsed.relationships.map((rel) => {
|
|
10540
|
-
const
|
|
10787
|
+
const p = placementByRelLine.get(rel.lineNumber);
|
|
10788
|
+
const pts = p?.compLayout.edgePoints.get(rel.lineNumber) ?? [];
|
|
10541
10789
|
return {
|
|
10542
10790
|
source: rel.source,
|
|
10543
10791
|
target: rel.target,
|
|
10544
10792
|
cardinality: rel.cardinality,
|
|
10545
|
-
points:
|
|
10793
|
+
points: pts.map((pt) => ({
|
|
10794
|
+
x: pt.x + (p?.offsetX ?? 0) + HALF_MARGIN,
|
|
10795
|
+
y: pt.y + (p?.offsetY ?? 0) + HALF_MARGIN
|
|
10796
|
+
})),
|
|
10546
10797
|
label: rel.label,
|
|
10547
10798
|
lineNumber: rel.lineNumber
|
|
10548
10799
|
};
|
|
10549
10800
|
});
|
|
10550
|
-
let minX = Infinity;
|
|
10551
|
-
let minY = Infinity;
|
|
10552
10801
|
let maxX = 0;
|
|
10553
10802
|
let maxY = 0;
|
|
10554
10803
|
for (const node of layoutNodes) {
|
|
10555
|
-
|
|
10556
|
-
|
|
10557
|
-
const top = node.y - node.height / 2;
|
|
10558
|
-
const bottom = node.y + node.height / 2;
|
|
10559
|
-
if (left < minX) minX = left;
|
|
10560
|
-
if (right > maxX) maxX = right;
|
|
10561
|
-
if (top < minY) minY = top;
|
|
10562
|
-
if (bottom > maxY) maxY = bottom;
|
|
10804
|
+
maxX = Math.max(maxX, node.x + node.width / 2);
|
|
10805
|
+
maxY = Math.max(maxY, node.y + node.height / 2);
|
|
10563
10806
|
}
|
|
10564
10807
|
for (const edge of layoutEdges) {
|
|
10565
10808
|
for (const pt of edge.points) {
|
|
10566
|
-
|
|
10567
|
-
|
|
10568
|
-
if (pt.y < minY) minY = pt.y;
|
|
10569
|
-
if (pt.y > maxY) maxY = pt.y;
|
|
10570
|
-
}
|
|
10571
|
-
if (edge.label && edge.points.length > 0) {
|
|
10572
|
-
const midPt = edge.points[Math.floor(edge.points.length / 2)];
|
|
10573
|
-
const labelHalfW = (edge.label.length * 7 + 8) / 2;
|
|
10574
|
-
if (midPt.x + labelHalfW > maxX) maxX = midPt.x + labelHalfW;
|
|
10575
|
-
if (midPt.x - labelHalfW < minX) minX = midPt.x - labelHalfW;
|
|
10809
|
+
maxX = Math.max(maxX, pt.x);
|
|
10810
|
+
maxY = Math.max(maxY, pt.y);
|
|
10576
10811
|
}
|
|
10577
10812
|
}
|
|
10578
|
-
const EDGE_MARGIN2 = 60;
|
|
10579
|
-
const HALF_MARGIN = EDGE_MARGIN2 / 2;
|
|
10580
|
-
const shiftX = -minX + HALF_MARGIN;
|
|
10581
|
-
const shiftY = -minY + HALF_MARGIN;
|
|
10582
|
-
for (const node of layoutNodes) {
|
|
10583
|
-
node.x += shiftX;
|
|
10584
|
-
node.y += shiftY;
|
|
10585
|
-
}
|
|
10586
|
-
for (const edge of layoutEdges) {
|
|
10587
|
-
for (const pt of edge.points) {
|
|
10588
|
-
pt.x += shiftX;
|
|
10589
|
-
pt.y += shiftY;
|
|
10590
|
-
}
|
|
10591
|
-
}
|
|
10592
|
-
maxX += shiftX;
|
|
10593
|
-
maxY += shiftY;
|
|
10594
|
-
const totalWidth = maxX + HALF_MARGIN;
|
|
10595
|
-
const totalHeight = maxY + HALF_MARGIN;
|
|
10596
10813
|
return {
|
|
10597
10814
|
nodes: layoutNodes,
|
|
10598
10815
|
edges: layoutEdges,
|
|
10599
|
-
width:
|
|
10600
|
-
height:
|
|
10816
|
+
width: maxX + HALF_MARGIN,
|
|
10817
|
+
height: maxY + HALF_MARGIN
|
|
10601
10818
|
};
|
|
10602
10819
|
}
|
|
10603
|
-
var import_dagre3, MIN_WIDTH2, CHAR_WIDTH4, PADDING_X2, HEADER_BASE2, MEMBER_LINE_HEIGHT3, COMPARTMENT_PADDING_Y3, SEPARATOR_HEIGHT2;
|
|
10820
|
+
var import_dagre3, MIN_WIDTH2, CHAR_WIDTH4, PADDING_X2, HEADER_BASE2, MEMBER_LINE_HEIGHT3, COMPARTMENT_PADDING_Y3, SEPARATOR_HEIGHT2, HALF_MARGIN, COMP_GAP;
|
|
10604
10821
|
var init_layout4 = __esm({
|
|
10605
10822
|
"src/er/layout.ts"() {
|
|
10606
10823
|
"use strict";
|
|
@@ -10612,6 +10829,135 @@ var init_layout4 = __esm({
|
|
|
10612
10829
|
MEMBER_LINE_HEIGHT3 = 18;
|
|
10613
10830
|
COMPARTMENT_PADDING_Y3 = 8;
|
|
10614
10831
|
SEPARATOR_HEIGHT2 = 1;
|
|
10832
|
+
HALF_MARGIN = 30;
|
|
10833
|
+
COMP_GAP = 60;
|
|
10834
|
+
}
|
|
10835
|
+
});
|
|
10836
|
+
|
|
10837
|
+
// src/er/classify.ts
|
|
10838
|
+
function classifyEREntities(tables, relationships) {
|
|
10839
|
+
const result = /* @__PURE__ */ new Map();
|
|
10840
|
+
if (tables.length === 0) return result;
|
|
10841
|
+
const indegreeMap = {};
|
|
10842
|
+
for (const t of tables) indegreeMap[t.id] = 0;
|
|
10843
|
+
for (const rel of relationships) {
|
|
10844
|
+
if (rel.source === rel.target) continue;
|
|
10845
|
+
if (rel.cardinality.from === "1" && rel.cardinality.to !== "1") {
|
|
10846
|
+
indegreeMap[rel.source] = (indegreeMap[rel.source] ?? 0) + 1;
|
|
10847
|
+
}
|
|
10848
|
+
if (rel.cardinality.to === "1" && rel.cardinality.from !== "1") {
|
|
10849
|
+
indegreeMap[rel.target] = (indegreeMap[rel.target] ?? 0) + 1;
|
|
10850
|
+
}
|
|
10851
|
+
}
|
|
10852
|
+
const tableStarNeighbors = /* @__PURE__ */ new Map();
|
|
10853
|
+
for (const rel of relationships) {
|
|
10854
|
+
if (rel.source === rel.target) continue;
|
|
10855
|
+
if (rel.cardinality.from === "*") {
|
|
10856
|
+
if (!tableStarNeighbors.has(rel.source)) tableStarNeighbors.set(rel.source, /* @__PURE__ */ new Set());
|
|
10857
|
+
tableStarNeighbors.get(rel.source).add(rel.target);
|
|
10858
|
+
}
|
|
10859
|
+
if (rel.cardinality.to === "*") {
|
|
10860
|
+
if (!tableStarNeighbors.has(rel.target)) tableStarNeighbors.set(rel.target, /* @__PURE__ */ new Set());
|
|
10861
|
+
tableStarNeighbors.get(rel.target).add(rel.source);
|
|
10862
|
+
}
|
|
10863
|
+
}
|
|
10864
|
+
const mmParticipants = /* @__PURE__ */ new Set();
|
|
10865
|
+
for (const [id, neighbors] of tableStarNeighbors) {
|
|
10866
|
+
if (neighbors.size >= 2) mmParticipants.add(id);
|
|
10867
|
+
}
|
|
10868
|
+
const indegreeValues = Object.values(indegreeMap);
|
|
10869
|
+
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
10870
|
+
const variance = indegreeValues.reduce((a, b) => a + (b - mean) ** 2, 0) / indegreeValues.length;
|
|
10871
|
+
const stddev = Math.sqrt(variance);
|
|
10872
|
+
const sorted = [...indegreeValues].sort((a, b) => a - b);
|
|
10873
|
+
const median = sorted.length % 2 === 0 ? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2 : sorted[Math.floor(sorted.length / 2)];
|
|
10874
|
+
for (const table of tables) {
|
|
10875
|
+
const id = table.id;
|
|
10876
|
+
const cols = table.columns;
|
|
10877
|
+
const fkCols = cols.filter((c) => c.constraints.includes("fk"));
|
|
10878
|
+
const pkFkCols = cols.filter(
|
|
10879
|
+
(c) => c.constraints.includes("pk") && c.constraints.includes("fk")
|
|
10880
|
+
);
|
|
10881
|
+
const fkCount = fkCols.length;
|
|
10882
|
+
const fkRatio = cols.length === 0 ? 0 : fkCount / cols.length;
|
|
10883
|
+
const indegree = indegreeMap[id] ?? 0;
|
|
10884
|
+
const nameLower = table.name.toLowerCase();
|
|
10885
|
+
const externalRels = relationships.filter(
|
|
10886
|
+
(r) => (r.source === id || r.target === id) && r.source !== r.target
|
|
10887
|
+
);
|
|
10888
|
+
const hasSelfRef = relationships.some((r) => r.source === id && r.target === id);
|
|
10889
|
+
const externalTargets = /* @__PURE__ */ new Set();
|
|
10890
|
+
for (const rel of externalRels) {
|
|
10891
|
+
externalTargets.add(rel.source === id ? rel.target : rel.source);
|
|
10892
|
+
}
|
|
10893
|
+
if (hasSelfRef && externalRels.length === 0) {
|
|
10894
|
+
result.set(id, "self-referential");
|
|
10895
|
+
continue;
|
|
10896
|
+
}
|
|
10897
|
+
const isInheritancePattern = pkFkCols.length >= 2 && externalTargets.size === 1;
|
|
10898
|
+
const junctionByRatio = fkRatio >= 0.6 && !isInheritancePattern;
|
|
10899
|
+
const junctionByCompositePk = pkFkCols.length >= 2 && externalTargets.size >= 2;
|
|
10900
|
+
const junctionByMm = mmParticipants.has(id);
|
|
10901
|
+
if (junctionByRatio || junctionByCompositePk || junctionByMm) {
|
|
10902
|
+
result.set(id, "junction");
|
|
10903
|
+
continue;
|
|
10904
|
+
}
|
|
10905
|
+
if (fkRatio >= 0.4 && fkRatio < 0.6 && pkFkCols.length < 2 && !mmParticipants.has(id)) {
|
|
10906
|
+
result.set(id, "ambiguous");
|
|
10907
|
+
continue;
|
|
10908
|
+
}
|
|
10909
|
+
const nameMatchesLookup = LOOKUP_NAME_SUFFIXES.some((s) => nameLower.endsWith(s));
|
|
10910
|
+
if (nameMatchesLookup && cols.length <= 6 && fkCount <= 1 && indegree > median) {
|
|
10911
|
+
result.set(id, "lookup");
|
|
10912
|
+
continue;
|
|
10913
|
+
}
|
|
10914
|
+
if (tables.length >= 6 && indegree > 0 && indegree > mean + 1.5 * stddev && indegree >= 2 * mean) {
|
|
10915
|
+
result.set(id, "hub");
|
|
10916
|
+
continue;
|
|
10917
|
+
}
|
|
10918
|
+
if (fkCount > 0) {
|
|
10919
|
+
result.set(id, "dependent");
|
|
10920
|
+
continue;
|
|
10921
|
+
}
|
|
10922
|
+
result.set(id, "core");
|
|
10923
|
+
}
|
|
10924
|
+
return result;
|
|
10925
|
+
}
|
|
10926
|
+
var ROLE_COLORS, ROLE_LABELS, ROLE_ORDER, LOOKUP_NAME_SUFFIXES;
|
|
10927
|
+
var init_classify = __esm({
|
|
10928
|
+
"src/er/classify.ts"() {
|
|
10929
|
+
"use strict";
|
|
10930
|
+
ROLE_COLORS = {
|
|
10931
|
+
core: "green",
|
|
10932
|
+
dependent: "blue",
|
|
10933
|
+
junction: "red",
|
|
10934
|
+
ambiguous: "purple",
|
|
10935
|
+
lookup: "yellow",
|
|
10936
|
+
hub: "orange",
|
|
10937
|
+
"self-referential": "teal",
|
|
10938
|
+
unclassified: "gray"
|
|
10939
|
+
};
|
|
10940
|
+
ROLE_LABELS = {
|
|
10941
|
+
core: "Core entity",
|
|
10942
|
+
dependent: "Dependent",
|
|
10943
|
+
junction: "Junction / M:M",
|
|
10944
|
+
ambiguous: "Bridge",
|
|
10945
|
+
lookup: "Lookup / Reference",
|
|
10946
|
+
hub: "Hub",
|
|
10947
|
+
"self-referential": "Self-referential",
|
|
10948
|
+
unclassified: "Unclassified"
|
|
10949
|
+
};
|
|
10950
|
+
ROLE_ORDER = [
|
|
10951
|
+
"core",
|
|
10952
|
+
"dependent",
|
|
10953
|
+
"junction",
|
|
10954
|
+
"ambiguous",
|
|
10955
|
+
"lookup",
|
|
10956
|
+
"hub",
|
|
10957
|
+
"self-referential",
|
|
10958
|
+
"unclassified"
|
|
10959
|
+
];
|
|
10960
|
+
LOOKUP_NAME_SUFFIXES = ["_type", "_status", "_code", "_category"];
|
|
10615
10961
|
}
|
|
10616
10962
|
});
|
|
10617
10963
|
|
|
@@ -10681,25 +11027,41 @@ function drawCardinality(g, point, prevPoint, cardinality, color, useLabels) {
|
|
|
10681
11027
|
g.append("line").attr("x1", bx + px * spread).attr("y1", by + py * spread).attr("x2", bx - px * spread).attr("y2", by - py * spread).attr("stroke", color).attr("stroke-width", sw);
|
|
10682
11028
|
}
|
|
10683
11029
|
}
|
|
10684
|
-
function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem, exportDims, activeTagGroup) {
|
|
11030
|
+
function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem, exportDims, activeTagGroup, semanticColorsActive) {
|
|
10685
11031
|
d3Selection5.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
10686
|
-
const
|
|
10687
|
-
const
|
|
10688
|
-
if (width <= 0 || height <= 0) return;
|
|
11032
|
+
const useSemanticColors = parsed.tagGroups.length === 0 && layout.nodes.every((n) => !n.color);
|
|
11033
|
+
const legendReserveH = useSemanticColors ? LEGEND_HEIGHT + DIAGRAM_PADDING5 : 0;
|
|
10689
11034
|
const titleHeight = parsed.title ? 40 : 0;
|
|
10690
11035
|
const diagramW = layout.width;
|
|
10691
11036
|
const diagramH = layout.height;
|
|
10692
|
-
const
|
|
10693
|
-
const
|
|
10694
|
-
|
|
10695
|
-
|
|
10696
|
-
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
11037
|
+
const naturalW = diagramW + DIAGRAM_PADDING5 * 2;
|
|
11038
|
+
const naturalH = diagramH + titleHeight + legendReserveH + DIAGRAM_PADDING5 * 2;
|
|
11039
|
+
let viewW;
|
|
11040
|
+
let viewH;
|
|
11041
|
+
let scale;
|
|
11042
|
+
let offsetX;
|
|
11043
|
+
let offsetY;
|
|
11044
|
+
if (exportDims) {
|
|
11045
|
+
viewW = exportDims.width ?? naturalW;
|
|
11046
|
+
viewH = exportDims.height ?? naturalH;
|
|
11047
|
+
const availH = viewH - titleHeight - legendReserveH;
|
|
11048
|
+
const scaleX = (viewW - DIAGRAM_PADDING5 * 2) / diagramW;
|
|
11049
|
+
const scaleY = (availH - DIAGRAM_PADDING5 * 2) / diagramH;
|
|
11050
|
+
scale = Math.min(MAX_SCALE4, scaleX, scaleY);
|
|
11051
|
+
const scaledW = diagramW * scale;
|
|
11052
|
+
offsetX = (viewW - scaledW) / 2;
|
|
11053
|
+
offsetY = titleHeight + DIAGRAM_PADDING5;
|
|
11054
|
+
} else {
|
|
11055
|
+
viewW = naturalW;
|
|
11056
|
+
viewH = naturalH;
|
|
11057
|
+
scale = 1;
|
|
11058
|
+
offsetX = DIAGRAM_PADDING5;
|
|
11059
|
+
offsetY = titleHeight + DIAGRAM_PADDING5;
|
|
11060
|
+
}
|
|
11061
|
+
if (viewW <= 0 || viewH <= 0) return;
|
|
11062
|
+
const svg = d3Selection5.select(container).append("svg").attr("width", exportDims ? viewW : "100%").attr("height", exportDims ? viewH : "100%").attr("viewBox", `0 0 ${viewW} ${viewH}`).attr("preserveAspectRatio", "xMidYMid meet").style("font-family", FONT_FAMILY);
|
|
10701
11063
|
if (parsed.title) {
|
|
10702
|
-
const titleEl = svg.append("text").attr("class", "chart-title").attr("x",
|
|
11064
|
+
const titleEl = svg.append("text").attr("class", "chart-title").attr("x", viewW / 2).attr("y", 30).attr("text-anchor", "middle").attr("fill", palette.text).attr("font-size", "20px").attr("font-weight", "700").style("cursor", onClickItem && parsed.titleLineNumber ? "pointer" : "default").text(parsed.title);
|
|
10703
11065
|
if (parsed.titleLineNumber) {
|
|
10704
11066
|
titleEl.attr("data-line-number", parsed.titleLineNumber);
|
|
10705
11067
|
if (onClickItem) {
|
|
@@ -10713,6 +11075,8 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10713
11075
|
}
|
|
10714
11076
|
const contentG = svg.append("g").attr("transform", `translate(${offsetX}, ${offsetY}) scale(${scale})`);
|
|
10715
11077
|
const seriesColors2 = getSeriesColors(palette);
|
|
11078
|
+
const semanticRoles = useSemanticColors ? classifyEREntities(parsed.tables, parsed.relationships) : null;
|
|
11079
|
+
const semanticActive = semanticRoles !== null && (semanticColorsActive ?? true);
|
|
10716
11080
|
const useLabels = parsed.options.notation === "labels";
|
|
10717
11081
|
for (const edge of layout.edges) {
|
|
10718
11082
|
if (edge.points.length < 2) continue;
|
|
@@ -10752,7 +11116,8 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10752
11116
|
for (let ni = 0; ni < layout.nodes.length; ni++) {
|
|
10753
11117
|
const node = layout.nodes[ni];
|
|
10754
11118
|
const tagColor = resolveTagColor(node.metadata, parsed.tagGroups, activeTagGroup ?? null);
|
|
10755
|
-
const
|
|
11119
|
+
const semanticColor = semanticActive ? palette.colors[ROLE_COLORS[semanticRoles.get(node.id) ?? "unclassified"]] : semanticRoles ? palette.primary : void 0;
|
|
11120
|
+
const nodeColor2 = node.color ?? tagColor ?? semanticColor ?? seriesColors2[ni % seriesColors2.length];
|
|
10756
11121
|
const nodeG = contentG.append("g").attr("transform", `translate(${node.x}, ${node.y})`).attr("class", "er-table").attr("data-line-number", String(node.lineNumber)).attr("data-node-id", node.id);
|
|
10757
11122
|
if (activeTagGroup) {
|
|
10758
11123
|
const tagKey = activeTagGroup.toLowerCase();
|
|
@@ -10761,6 +11126,10 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10761
11126
|
nodeG.attr(`data-tag-${tagKey}`, tagValue.toLowerCase());
|
|
10762
11127
|
}
|
|
10763
11128
|
}
|
|
11129
|
+
if (semanticRoles) {
|
|
11130
|
+
const role = semanticRoles.get(node.id);
|
|
11131
|
+
if (role) nodeG.attr("data-er-role", role);
|
|
11132
|
+
}
|
|
10764
11133
|
if (onClickItem) {
|
|
10765
11134
|
nodeG.style("cursor", "pointer").on("click", () => {
|
|
10766
11135
|
onClickItem(node.lineNumber);
|
|
@@ -10801,7 +11170,7 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10801
11170
|
legendG.attr("data-legend-active", activeTagGroup.toLowerCase());
|
|
10802
11171
|
}
|
|
10803
11172
|
let legendX = DIAGRAM_PADDING5;
|
|
10804
|
-
let legendY =
|
|
11173
|
+
let legendY = viewH - DIAGRAM_PADDING5;
|
|
10805
11174
|
for (const group of parsed.tagGroups) {
|
|
10806
11175
|
const groupG = legendG.append("g").attr("data-legend-group", group.name.toLowerCase());
|
|
10807
11176
|
const labelText = groupG.append("text").attr("x", legendX).attr("y", legendY + LEGEND_PILL_H / 2).attr("dominant-baseline", "central").attr("fill", palette.textMuted).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-family", FONT_FAMILY).text(`${group.name}:`);
|
|
@@ -10820,6 +11189,62 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10820
11189
|
legendX += LEGEND_GROUP_GAP;
|
|
10821
11190
|
}
|
|
10822
11191
|
}
|
|
11192
|
+
if (semanticRoles) {
|
|
11193
|
+
const presentRoles = ROLE_ORDER.filter((role) => {
|
|
11194
|
+
for (const r of semanticRoles.values()) {
|
|
11195
|
+
if (r === role) return true;
|
|
11196
|
+
}
|
|
11197
|
+
return false;
|
|
11198
|
+
});
|
|
11199
|
+
if (presentRoles.length > 0) {
|
|
11200
|
+
const measureLabelW = (text, fontSize) => {
|
|
11201
|
+
const dummy = svg.append("text").attr("font-size", fontSize).attr("font-family", FONT_FAMILY).attr("visibility", "hidden").text(text);
|
|
11202
|
+
const measured = dummy.node()?.getComputedTextLength?.() ?? 0;
|
|
11203
|
+
dummy.remove();
|
|
11204
|
+
return measured > 0 ? measured : text.length * fontSize * 0.6;
|
|
11205
|
+
};
|
|
11206
|
+
const labelWidths = /* @__PURE__ */ new Map();
|
|
11207
|
+
for (const role of presentRoles) {
|
|
11208
|
+
labelWidths.set(role, measureLabelW(ROLE_LABELS[role], LEGEND_ENTRY_FONT_SIZE));
|
|
11209
|
+
}
|
|
11210
|
+
const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
|
|
11211
|
+
const groupName = "Role";
|
|
11212
|
+
const pillWidth = groupName.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD;
|
|
11213
|
+
const pillH = LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2;
|
|
11214
|
+
let totalWidth;
|
|
11215
|
+
let entriesWidth = 0;
|
|
11216
|
+
if (semanticActive) {
|
|
11217
|
+
for (const role of presentRoles) {
|
|
11218
|
+
entriesWidth += LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + labelWidths.get(role) + LEGEND_ENTRY_TRAIL;
|
|
11219
|
+
}
|
|
11220
|
+
totalWidth = LEGEND_CAPSULE_PAD * 2 + pillWidth + LEGEND_ENTRY_TRAIL + entriesWidth;
|
|
11221
|
+
} else {
|
|
11222
|
+
totalWidth = pillWidth;
|
|
11223
|
+
}
|
|
11224
|
+
const legendX = (viewW - totalWidth) / 2;
|
|
11225
|
+
const legendY = viewH - DIAGRAM_PADDING5 - LEGEND_HEIGHT;
|
|
11226
|
+
const semanticLegendG = svg.append("g").attr("class", "er-semantic-legend").attr("data-legend-group", "role").attr("transform", `translate(${legendX}, ${legendY})`).style("cursor", "pointer");
|
|
11227
|
+
if (semanticActive) {
|
|
11228
|
+
semanticLegendG.append("rect").attr("width", totalWidth).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
|
|
11229
|
+
semanticLegendG.append("rect").attr("x", LEGEND_CAPSULE_PAD).attr("y", LEGEND_CAPSULE_PAD).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", palette.bg);
|
|
11230
|
+
semanticLegendG.append("rect").attr("x", LEGEND_CAPSULE_PAD).attr("y", LEGEND_CAPSULE_PAD).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
|
|
11231
|
+
semanticLegendG.append("text").attr("x", LEGEND_CAPSULE_PAD + pillWidth / 2).attr("y", LEGEND_HEIGHT / 2 + LEGEND_PILL_FONT_SIZE / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-weight", "500").attr("fill", palette.text).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).text(groupName);
|
|
11232
|
+
let entryX = LEGEND_CAPSULE_PAD + pillWidth + LEGEND_ENTRY_TRAIL;
|
|
11233
|
+
for (const role of presentRoles) {
|
|
11234
|
+
const label = ROLE_LABELS[role];
|
|
11235
|
+
const roleColor = palette.colors[ROLE_COLORS[role]];
|
|
11236
|
+
const entryG = semanticLegendG.append("g").attr("data-legend-entry", role);
|
|
11237
|
+
entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", roleColor);
|
|
11238
|
+
const textX = entryX + LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP;
|
|
11239
|
+
entryG.append("text").attr("x", textX).attr("y", LEGEND_HEIGHT / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE).attr("fill", palette.textMuted).attr("font-family", FONT_FAMILY).text(label);
|
|
11240
|
+
entryX = textX + labelWidths.get(role) + LEGEND_ENTRY_TRAIL;
|
|
11241
|
+
}
|
|
11242
|
+
} else {
|
|
11243
|
+
semanticLegendG.append("rect").attr("width", pillWidth).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
|
|
11244
|
+
semanticLegendG.append("text").attr("x", pillWidth / 2).attr("y", LEGEND_HEIGHT / 2 + LEGEND_PILL_FONT_SIZE / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-weight", "500").attr("fill", palette.textMuted).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).text(groupName);
|
|
11245
|
+
}
|
|
11246
|
+
}
|
|
11247
|
+
}
|
|
10823
11248
|
}
|
|
10824
11249
|
function renderERDiagramForExport(content, theme, palette) {
|
|
10825
11250
|
const parsed = parseERDiagram(content, palette);
|
|
@@ -10869,6 +11294,7 @@ var init_renderer5 = __esm({
|
|
|
10869
11294
|
init_legend_constants();
|
|
10870
11295
|
init_parser3();
|
|
10871
11296
|
init_layout4();
|
|
11297
|
+
init_classify();
|
|
10872
11298
|
DIAGRAM_PADDING5 = 20;
|
|
10873
11299
|
MAX_SCALE4 = 3;
|
|
10874
11300
|
TABLE_FONT_SIZE = 13;
|
|
@@ -10996,9 +11422,10 @@ function layoutInitiativeStatus(parsed, collapseResult) {
|
|
|
10996
11422
|
const dagreEdge = g.edge(edge.source, edge.target, `e${i}`);
|
|
10997
11423
|
const dagrePoints = dagreEdge?.points ?? [];
|
|
10998
11424
|
const hasIntermediateRank = allNodeX.some((x) => x > src.x + 20 && x < tgt.x - 20);
|
|
10999
|
-
const step = Math.min((enterX - exitX) * 0.15, 20);
|
|
11425
|
+
const step = Math.max(0, Math.min((enterX - exitX) * 0.15, 20));
|
|
11000
11426
|
const isBackEdge = tgt.x < src.x - 5;
|
|
11001
|
-
const
|
|
11427
|
+
const isTopExit = !isBackEdge && tgt.x > src.x && !hasIntermediateRank && tgt.y < src.y - NODESEP;
|
|
11428
|
+
const isBottomExit = !isBackEdge && tgt.x > src.x && !hasIntermediateRank && tgt.y > src.y + NODESEP;
|
|
11002
11429
|
let points;
|
|
11003
11430
|
if (isBackEdge) {
|
|
11004
11431
|
const routeAbove = Math.min(src.y, tgt.y) > avgNodeY;
|
|
@@ -11008,31 +11435,44 @@ function layoutInitiativeStatus(parsed, collapseResult) {
|
|
|
11008
11435
|
const spreadDir = avgNodeX < rawMidX ? 1 : -1;
|
|
11009
11436
|
const unclamped = Math.abs(src.x - tgt.x) < NODE_WIDTH ? rawMidX + spreadDir * BACK_EDGE_MIN_SPREAD : rawMidX;
|
|
11010
11437
|
const midX = Math.min(src.x, Math.max(tgt.x, unclamped));
|
|
11438
|
+
const srcDepart = Math.max(midX + 1, src.x - TOP_EXIT_STEP);
|
|
11439
|
+
const tgtApproach = Math.min(midX - 1, tgt.x + TOP_EXIT_STEP);
|
|
11011
11440
|
if (routeAbove) {
|
|
11012
11441
|
const arcY = Math.min(src.y - srcHalfH, tgt.y - tgtHalfH) - BACK_EDGE_MARGIN;
|
|
11013
11442
|
points = [
|
|
11014
11443
|
{ x: src.x, y: src.y - srcHalfH },
|
|
11444
|
+
{ x: srcDepart, y: src.y - srcHalfH - TOP_EXIT_STEP },
|
|
11015
11445
|
{ x: midX, y: arcY },
|
|
11446
|
+
{ x: tgtApproach, y: tgt.y - tgtHalfH - TOP_EXIT_STEP },
|
|
11016
11447
|
{ x: tgt.x, y: tgt.y - tgtHalfH }
|
|
11017
11448
|
];
|
|
11018
11449
|
} else {
|
|
11019
11450
|
const arcY = Math.max(src.y + srcHalfH, tgt.y + tgtHalfH) + BACK_EDGE_MARGIN;
|
|
11020
11451
|
points = [
|
|
11021
11452
|
{ x: src.x, y: src.y + srcHalfH },
|
|
11453
|
+
{ x: srcDepart, y: src.y + srcHalfH + TOP_EXIT_STEP },
|
|
11022
11454
|
{ x: midX, y: arcY },
|
|
11455
|
+
{ x: tgtApproach, y: tgt.y + tgtHalfH + TOP_EXIT_STEP },
|
|
11023
11456
|
{ x: tgt.x, y: tgt.y + tgtHalfH }
|
|
11024
11457
|
];
|
|
11025
11458
|
}
|
|
11026
|
-
} else if (
|
|
11027
|
-
const exitY =
|
|
11028
|
-
const
|
|
11029
|
-
const spreadEntryY = tgt.y + yOffset;
|
|
11030
|
-
const midX = (spreadExitX + enterX) / 2;
|
|
11031
|
-
const midY = (exitY + spreadEntryY) / 2;
|
|
11459
|
+
} else if (isTopExit) {
|
|
11460
|
+
const exitY = src.y - src.height / 2;
|
|
11461
|
+
const p1x = Math.min(Math.max(src.x, src.x + yOffset + TOP_EXIT_STEP), (src.x + enterX) / 2 - 1);
|
|
11032
11462
|
points = [
|
|
11033
|
-
{ x:
|
|
11034
|
-
{ x:
|
|
11035
|
-
{ x: enterX, y:
|
|
11463
|
+
{ x: src.x, y: exitY },
|
|
11464
|
+
{ x: p1x, y: exitY - TOP_EXIT_STEP },
|
|
11465
|
+
{ x: enterX - step, y: tgt.y + yOffset },
|
|
11466
|
+
{ x: enterX, y: tgt.y }
|
|
11467
|
+
];
|
|
11468
|
+
} else if (isBottomExit) {
|
|
11469
|
+
const exitY = src.y + src.height / 2;
|
|
11470
|
+
const p1x = Math.min(Math.max(src.x, src.x + yOffset + TOP_EXIT_STEP), (src.x + enterX) / 2 - 1);
|
|
11471
|
+
points = [
|
|
11472
|
+
{ x: src.x, y: exitY },
|
|
11473
|
+
{ x: p1x, y: exitY + TOP_EXIT_STEP },
|
|
11474
|
+
{ x: enterX - step, y: tgt.y + yOffset },
|
|
11475
|
+
{ x: enterX, y: tgt.y }
|
|
11036
11476
|
];
|
|
11037
11477
|
} else if (tgt.x > src.x && !hasIntermediateRank) {
|
|
11038
11478
|
points = [
|
|
@@ -11129,7 +11569,7 @@ function layoutInitiativeStatus(parsed, collapseResult) {
|
|
|
11129
11569
|
totalHeight += 40;
|
|
11130
11570
|
return { nodes: layoutNodes, edges: layoutEdges, groups: layoutGroups, width: totalWidth, height: totalHeight };
|
|
11131
11571
|
}
|
|
11132
|
-
var import_dagre4, STATUS_PRIORITY, PHI, NODE_HEIGHT, NODE_WIDTH, GROUP_PADDING, NODESEP, RANKSEP, PARALLEL_SPACING, PARALLEL_EDGE_MARGIN, MAX_PARALLEL_EDGES, BACK_EDGE_MARGIN, BACK_EDGE_MIN_SPREAD, CHAR_WIDTH_RATIO, NODE_FONT_SIZE, NODE_TEXT_PADDING;
|
|
11572
|
+
var import_dagre4, STATUS_PRIORITY, PHI, NODE_HEIGHT, NODE_WIDTH, GROUP_PADDING, NODESEP, RANKSEP, PARALLEL_SPACING, PARALLEL_EDGE_MARGIN, MAX_PARALLEL_EDGES, BACK_EDGE_MARGIN, BACK_EDGE_MIN_SPREAD, TOP_EXIT_STEP, CHAR_WIDTH_RATIO, NODE_FONT_SIZE, NODE_TEXT_PADDING;
|
|
11133
11573
|
var init_layout5 = __esm({
|
|
11134
11574
|
"src/initiative-status/layout.ts"() {
|
|
11135
11575
|
"use strict";
|
|
@@ -11146,6 +11586,7 @@ var init_layout5 = __esm({
|
|
|
11146
11586
|
MAX_PARALLEL_EDGES = 5;
|
|
11147
11587
|
BACK_EDGE_MARGIN = 40;
|
|
11148
11588
|
BACK_EDGE_MIN_SPREAD = Math.round(NODE_WIDTH * 0.75);
|
|
11589
|
+
TOP_EXIT_STEP = 10;
|
|
11149
11590
|
CHAR_WIDTH_RATIO = 0.6;
|
|
11150
11591
|
NODE_FONT_SIZE = 13;
|
|
11151
11592
|
NODE_TEXT_PADDING = 12;
|
|
@@ -11392,7 +11833,6 @@ function renderInitiativeStatus(container, parsed, layout, palette, isDark, onCl
|
|
|
11392
11833
|
const scaleY = (availH - DIAGRAM_PADDING6 * 2) / diagramH;
|
|
11393
11834
|
const scale = Math.min(MAX_SCALE5, scaleX, scaleY);
|
|
11394
11835
|
const scaledW = diagramW * scale;
|
|
11395
|
-
const scaledH = diagramH * scale;
|
|
11396
11836
|
const offsetX = (width - scaledW) / 2;
|
|
11397
11837
|
const offsetY = titleHeight + DIAGRAM_PADDING6;
|
|
11398
11838
|
const svg = d3Selection6.select(container).append("svg").attr("width", width).attr("height", height).style("font-family", FONT_FAMILY);
|
|
@@ -11575,13 +12015,7 @@ function renderInitiativeStatusForExport(content, theme, palette) {
|
|
|
11575
12015
|
const titleOffset = parsed.title ? 40 : 0;
|
|
11576
12016
|
const exportWidth = layout.width + DIAGRAM_PADDING6 * 2;
|
|
11577
12017
|
const exportHeight = layout.height + DIAGRAM_PADDING6 * 2 + titleOffset;
|
|
11578
|
-
|
|
11579
|
-
container.style.width = `${exportWidth}px`;
|
|
11580
|
-
container.style.height = `${exportHeight}px`;
|
|
11581
|
-
container.style.position = "absolute";
|
|
11582
|
-
container.style.left = "-9999px";
|
|
11583
|
-
document.body.appendChild(container);
|
|
11584
|
-
try {
|
|
12018
|
+
return runInExportContainer(exportWidth, exportHeight, (container) => {
|
|
11585
12019
|
renderInitiativeStatus(
|
|
11586
12020
|
container,
|
|
11587
12021
|
parsed,
|
|
@@ -11591,17 +12025,8 @@ function renderInitiativeStatusForExport(content, theme, palette) {
|
|
|
11591
12025
|
void 0,
|
|
11592
12026
|
{ width: exportWidth, height: exportHeight }
|
|
11593
12027
|
);
|
|
11594
|
-
|
|
11595
|
-
|
|
11596
|
-
if (theme === "transparent") {
|
|
11597
|
-
svgEl.style.background = "none";
|
|
11598
|
-
}
|
|
11599
|
-
svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
11600
|
-
svgEl.style.fontFamily = FONT_FAMILY;
|
|
11601
|
-
return svgEl.outerHTML;
|
|
11602
|
-
} finally {
|
|
11603
|
-
document.body.removeChild(container);
|
|
11604
|
-
}
|
|
12028
|
+
return extractExportSvg(container, theme);
|
|
12029
|
+
});
|
|
11605
12030
|
}
|
|
11606
12031
|
var d3Selection6, d3Shape4, DIAGRAM_PADDING6, MAX_SCALE5, NODE_FONT_SIZE2, MIN_NODE_FONT_SIZE, EDGE_LABEL_FONT_SIZE4, EDGE_STROKE_WIDTH5, NODE_STROKE_WIDTH5, NODE_RX, ARROWHEAD_W2, ARROWHEAD_H2, CHAR_WIDTH_RATIO2, NODE_TEXT_PADDING2, SERVICE_RX, GROUP_EXTRA_PADDING, GROUP_LABEL_FONT_SIZE, COLLAPSE_BAR_HEIGHT3, lineGenerator4;
|
|
11607
12032
|
var init_renderer6 = __esm({
|
|
@@ -11610,6 +12035,7 @@ var init_renderer6 = __esm({
|
|
|
11610
12035
|
d3Selection6 = __toESM(require("d3-selection"), 1);
|
|
11611
12036
|
d3Shape4 = __toESM(require("d3-shape"), 1);
|
|
11612
12037
|
init_fonts();
|
|
12038
|
+
init_export_container();
|
|
11613
12039
|
init_color_utils();
|
|
11614
12040
|
init_parser7();
|
|
11615
12041
|
init_layout5();
|
|
@@ -11644,7 +12070,7 @@ __export(layout_exports6, {
|
|
|
11644
12070
|
layoutC4Deployment: () => layoutC4Deployment,
|
|
11645
12071
|
rollUpContextRelationships: () => rollUpContextRelationships
|
|
11646
12072
|
});
|
|
11647
|
-
function computeEdgePenalty(edgeList, nodePositions, degrees) {
|
|
12073
|
+
function computeEdgePenalty(edgeList, nodePositions, degrees, nodeGeometry) {
|
|
11648
12074
|
let penalty = 0;
|
|
11649
12075
|
for (const edge of edgeList) {
|
|
11650
12076
|
const sx = nodePositions.get(edge.source);
|
|
@@ -11654,6 +12080,32 @@ function computeEdgePenalty(edgeList, nodePositions, degrees) {
|
|
|
11654
12080
|
const weight = Math.min(degrees.get(edge.source) ?? 1, degrees.get(edge.target) ?? 1);
|
|
11655
12081
|
penalty += dist * weight;
|
|
11656
12082
|
}
|
|
12083
|
+
if (nodeGeometry) {
|
|
12084
|
+
for (const edge of edgeList) {
|
|
12085
|
+
const geomA = nodeGeometry.get(edge.source);
|
|
12086
|
+
const geomB = nodeGeometry.get(edge.target);
|
|
12087
|
+
if (!geomA || !geomB) continue;
|
|
12088
|
+
const ax = nodePositions.get(edge.source) ?? 0;
|
|
12089
|
+
const bx = nodePositions.get(edge.target) ?? 0;
|
|
12090
|
+
const ay = geomA.y;
|
|
12091
|
+
const by = geomB.y;
|
|
12092
|
+
if (ay === by) continue;
|
|
12093
|
+
const edgeMinX = Math.min(ax, bx);
|
|
12094
|
+
const edgeMaxX = Math.max(ax, bx);
|
|
12095
|
+
const edgeMinY = Math.min(ay, by);
|
|
12096
|
+
const edgeMaxY = Math.max(ay, by);
|
|
12097
|
+
for (const [name, geomC] of nodeGeometry) {
|
|
12098
|
+
if (name === edge.source || name === edge.target) continue;
|
|
12099
|
+
const cx = nodePositions.get(name) ?? 0;
|
|
12100
|
+
const cy = geomC.y;
|
|
12101
|
+
const hw = geomC.width / 2;
|
|
12102
|
+
const hh = geomC.height / 2;
|
|
12103
|
+
if (cx + hw > edgeMinX && cx - hw < edgeMaxX && cy + hh > edgeMinY && cy - hh < edgeMaxY) {
|
|
12104
|
+
penalty += EDGE_NODE_COLLISION_WEIGHT;
|
|
12105
|
+
}
|
|
12106
|
+
}
|
|
12107
|
+
}
|
|
12108
|
+
}
|
|
11657
12109
|
return penalty;
|
|
11658
12110
|
}
|
|
11659
12111
|
function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
@@ -11663,6 +12115,11 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11663
12115
|
degrees.set(edge.source, (degrees.get(edge.source) ?? 0) + 1);
|
|
11664
12116
|
degrees.set(edge.target, (degrees.get(edge.target) ?? 0) + 1);
|
|
11665
12117
|
}
|
|
12118
|
+
const nodeGeometry = /* @__PURE__ */ new Map();
|
|
12119
|
+
for (const name of g.nodes()) {
|
|
12120
|
+
const pos = g.node(name);
|
|
12121
|
+
if (pos) nodeGeometry.set(name, { y: pos.y, width: pos.width, height: pos.height });
|
|
12122
|
+
}
|
|
11666
12123
|
const rankMap = /* @__PURE__ */ new Map();
|
|
11667
12124
|
for (const name of g.nodes()) {
|
|
11668
12125
|
const pos = g.node(name);
|
|
@@ -11705,7 +12162,7 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11705
12162
|
const pos = g.node(name);
|
|
11706
12163
|
if (pos) basePositions.set(name, pos.x);
|
|
11707
12164
|
}
|
|
11708
|
-
const currentPenalty = computeEdgePenalty(edgeList, basePositions, degrees);
|
|
12165
|
+
const currentPenalty = computeEdgePenalty(edgeList, basePositions, degrees, nodeGeometry);
|
|
11709
12166
|
let bestPerm = [...partition];
|
|
11710
12167
|
let bestPenalty = currentPenalty;
|
|
11711
12168
|
if (partition.length <= 8) {
|
|
@@ -11715,7 +12172,7 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11715
12172
|
for (let i = 0; i < perm.length; i++) {
|
|
11716
12173
|
testPositions.set(perm[i], xSlots[i]);
|
|
11717
12174
|
}
|
|
11718
|
-
const penalty = computeEdgePenalty(edgeList, testPositions, degrees);
|
|
12175
|
+
const penalty = computeEdgePenalty(edgeList, testPositions, degrees, nodeGeometry);
|
|
11719
12176
|
if (penalty < bestPenalty) {
|
|
11720
12177
|
bestPenalty = penalty;
|
|
11721
12178
|
bestPerm = [...perm];
|
|
@@ -11733,13 +12190,13 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11733
12190
|
for (let k = 0; k < workingOrder.length; k++) {
|
|
11734
12191
|
testPositions.set(workingOrder[k], xSlots[k]);
|
|
11735
12192
|
}
|
|
11736
|
-
const before = computeEdgePenalty(edgeList, testPositions, degrees);
|
|
12193
|
+
const before = computeEdgePenalty(edgeList, testPositions, degrees, nodeGeometry);
|
|
11737
12194
|
[workingOrder[i], workingOrder[i + 1]] = [workingOrder[i + 1], workingOrder[i]];
|
|
11738
12195
|
const testPositions2 = new Map(basePositions);
|
|
11739
12196
|
for (let k = 0; k < workingOrder.length; k++) {
|
|
11740
12197
|
testPositions2.set(workingOrder[k], xSlots[k]);
|
|
11741
12198
|
}
|
|
11742
|
-
const after = computeEdgePenalty(edgeList, testPositions2, degrees);
|
|
12199
|
+
const after = computeEdgePenalty(edgeList, testPositions2, degrees, nodeGeometry);
|
|
11743
12200
|
if (after < before) {
|
|
11744
12201
|
improved = true;
|
|
11745
12202
|
if (after < bestPenalty) {
|
|
@@ -11846,8 +12303,6 @@ function collectAllRelationships(elements, ownerMap) {
|
|
|
11846
12303
|
function rollUpContextRelationships(parsed) {
|
|
11847
12304
|
const ownerMap = buildOwnershipMap(parsed.elements);
|
|
11848
12305
|
const allRels = collectAllRelationships(parsed.elements, ownerMap);
|
|
11849
|
-
for (const rel of parsed.relationships) {
|
|
11850
|
-
}
|
|
11851
12306
|
const topLevelNames = new Set(parsed.elements.map((e) => e.name));
|
|
11852
12307
|
const explicitKeys = /* @__PURE__ */ new Set();
|
|
11853
12308
|
const explicit = [];
|
|
@@ -13059,7 +13514,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
|
|
|
13059
13514
|
}
|
|
13060
13515
|
return { nodes, edges, legend: legendGroups, groupBoundaries, width: totalWidth, height: totalHeight };
|
|
13061
13516
|
}
|
|
13062
|
-
var import_dagre5, CHAR_WIDTH5, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, DESC_LINE_HEIGHT, DESC_CHAR_WIDTH, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_CHAR_WIDTH, MARGIN3, BOUNDARY_PAD, GROUP_BOUNDARY_PAD, LEGEND_HEIGHT4, LEGEND_PILL_FONT_SIZE2, LEGEND_PILL_FONT_W4, LEGEND_PILL_PAD4, LEGEND_DOT_R4, LEGEND_ENTRY_FONT_SIZE2, LEGEND_ENTRY_FONT_W4, LEGEND_ENTRY_DOT_GAP4, LEGEND_ENTRY_TRAIL4, LEGEND_CAPSULE_PAD4, META_EXCLUDE_KEYS;
|
|
13517
|
+
var import_dagre5, CHAR_WIDTH5, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, DESC_LINE_HEIGHT, DESC_CHAR_WIDTH, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_CHAR_WIDTH, MARGIN3, BOUNDARY_PAD, GROUP_BOUNDARY_PAD, LEGEND_HEIGHT4, LEGEND_PILL_FONT_SIZE2, LEGEND_PILL_FONT_W4, LEGEND_PILL_PAD4, LEGEND_DOT_R4, LEGEND_ENTRY_FONT_SIZE2, LEGEND_ENTRY_FONT_W4, LEGEND_ENTRY_DOT_GAP4, LEGEND_ENTRY_TRAIL4, LEGEND_CAPSULE_PAD4, EDGE_NODE_COLLISION_WEIGHT, META_EXCLUDE_KEYS;
|
|
13063
13518
|
var init_layout6 = __esm({
|
|
13064
13519
|
"src/c4/layout.ts"() {
|
|
13065
13520
|
"use strict";
|
|
@@ -13089,6 +13544,7 @@ var init_layout6 = __esm({
|
|
|
13089
13544
|
LEGEND_ENTRY_DOT_GAP4 = 4;
|
|
13090
13545
|
LEGEND_ENTRY_TRAIL4 = 8;
|
|
13091
13546
|
LEGEND_CAPSULE_PAD4 = 4;
|
|
13547
|
+
EDGE_NODE_COLLISION_WEIGHT = 5e3;
|
|
13092
13548
|
META_EXCLUDE_KEYS = /* @__PURE__ */ new Set(["description", "tech", "technology", "is a"]);
|
|
13093
13549
|
}
|
|
13094
13550
|
});
|
|
@@ -13176,7 +13632,6 @@ function renderC4Context(container, parsed, layout, palette, isDark, onClickItem
|
|
|
13176
13632
|
const scaleY = (availH - DIAGRAM_PADDING7 * 2) / diagramH;
|
|
13177
13633
|
const scale = Math.min(MAX_SCALE6, scaleX, scaleY);
|
|
13178
13634
|
const scaledW = diagramW * scale;
|
|
13179
|
-
const scaledH = diagramH * scale;
|
|
13180
13635
|
const offsetX = (width - scaledW) / 2;
|
|
13181
13636
|
const offsetY = titleHeight + DIAGRAM_PADDING7;
|
|
13182
13637
|
const svg = d3Selection7.select(container).append("svg").attr("width", width).attr("height", height).style("font-family", FONT_FAMILY);
|
|
@@ -13666,7 +14121,6 @@ function renderC4Containers(container, parsed, layout, palette, isDark, onClickI
|
|
|
13666
14121
|
const scaleY = (availH - DIAGRAM_PADDING7 * 2) / diagramH;
|
|
13667
14122
|
const scale = Math.min(MAX_SCALE6, scaleX, scaleY);
|
|
13668
14123
|
const scaledW = diagramW * scale;
|
|
13669
|
-
const scaledH = diagramH * scale;
|
|
13670
14124
|
const offsetX = (width - scaledW) / 2;
|
|
13671
14125
|
const offsetY = titleHeight + DIAGRAM_PADDING7;
|
|
13672
14126
|
const svg = d3Selection7.select(container).append("svg").attr("width", width).attr("height", height).style("font-family", FONT_FAMILY);
|
|
@@ -14279,7 +14733,6 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
|
|
|
14279
14733
|
const scaleY = (availH - DIAGRAM_PADDING8 * 2) / diagramH;
|
|
14280
14734
|
const scale = Math.min(MAX_SCALE7, scaleX, scaleY);
|
|
14281
14735
|
const scaledW = diagramW * scale;
|
|
14282
|
-
const scaledH = diagramH * scale;
|
|
14283
14736
|
const offsetX = (width - scaledW) / 2;
|
|
14284
14737
|
const offsetY = titleHeight + DIAGRAM_PADDING8;
|
|
14285
14738
|
const svg = d3Selection8.select(container).append("svg").attr("width", width).attr("height", height).style("font-family", FONT_FAMILY);
|
|
@@ -15273,6 +15726,7 @@ var init_compute = __esm({
|
|
|
15273
15726
|
// src/infra/layout.ts
|
|
15274
15727
|
var layout_exports8 = {};
|
|
15275
15728
|
__export(layout_exports8, {
|
|
15729
|
+
fixEdgeWaypoints: () => fixEdgeWaypoints,
|
|
15276
15730
|
layoutInfra: () => layoutInfra,
|
|
15277
15731
|
separateGroups: () => separateGroups
|
|
15278
15732
|
});
|
|
@@ -15456,6 +15910,8 @@ function formatUptime(fraction) {
|
|
|
15456
15910
|
return `${pct.toFixed(1)}%`;
|
|
15457
15911
|
}
|
|
15458
15912
|
function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
15913
|
+
const groupDeltas = /* @__PURE__ */ new Map();
|
|
15914
|
+
let converged = false;
|
|
15459
15915
|
for (let iter = 0; iter < maxIterations; iter++) {
|
|
15460
15916
|
let anyOverlap = false;
|
|
15461
15917
|
for (let i = 0; i < groups.length; i++) {
|
|
@@ -15473,6 +15929,9 @@ function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
|
15473
15929
|
const groupToShift = aCenter <= bCenter ? gb : ga;
|
|
15474
15930
|
if (isLR) groupToShift.y += shift;
|
|
15475
15931
|
else groupToShift.x += shift;
|
|
15932
|
+
const prev = groupDeltas.get(groupToShift.id) ?? { dx: 0, dy: 0 };
|
|
15933
|
+
if (isLR) groupDeltas.set(groupToShift.id, { dx: prev.dx, dy: prev.dy + shift });
|
|
15934
|
+
else groupDeltas.set(groupToShift.id, { dx: prev.dx + shift, dy: prev.dy });
|
|
15476
15935
|
for (const node of nodes) {
|
|
15477
15936
|
if (node.groupId === groupToShift.id) {
|
|
15478
15937
|
if (isLR) node.y += shift;
|
|
@@ -15481,19 +15940,48 @@ function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
|
15481
15940
|
}
|
|
15482
15941
|
}
|
|
15483
15942
|
}
|
|
15484
|
-
if (!anyOverlap)
|
|
15943
|
+
if (!anyOverlap) {
|
|
15944
|
+
converged = true;
|
|
15945
|
+
break;
|
|
15946
|
+
}
|
|
15947
|
+
}
|
|
15948
|
+
if (!converged && maxIterations > 0) {
|
|
15949
|
+
console.warn(`separateGroups: hit maxIterations (${maxIterations}) without fully resolving all group overlaps`);
|
|
15950
|
+
}
|
|
15951
|
+
return groupDeltas;
|
|
15952
|
+
}
|
|
15953
|
+
function fixEdgeWaypoints(edges, nodes, groupDeltas) {
|
|
15954
|
+
if (groupDeltas.size === 0) return;
|
|
15955
|
+
const nodeToGroup = /* @__PURE__ */ new Map();
|
|
15956
|
+
for (const node of nodes) nodeToGroup.set(node.id, node.groupId);
|
|
15957
|
+
for (const edge of edges) {
|
|
15958
|
+
const srcGroup = nodeToGroup.get(edge.sourceId) ?? null;
|
|
15959
|
+
const tgtGroup = nodeToGroup.get(edge.targetId) ?? null;
|
|
15960
|
+
const srcDelta = srcGroup ? groupDeltas.get(srcGroup) : void 0;
|
|
15961
|
+
const tgtDelta = tgtGroup ? groupDeltas.get(tgtGroup) : void 0;
|
|
15962
|
+
if (!srcDelta && !tgtDelta) continue;
|
|
15963
|
+
if (srcDelta && tgtDelta && srcGroup !== tgtGroup) {
|
|
15964
|
+
edge.points = [];
|
|
15965
|
+
continue;
|
|
15966
|
+
}
|
|
15967
|
+
const delta = srcDelta ?? tgtDelta;
|
|
15968
|
+
for (const pt of edge.points) {
|
|
15969
|
+
pt.x += delta.dx;
|
|
15970
|
+
pt.y += delta.dy;
|
|
15971
|
+
}
|
|
15485
15972
|
}
|
|
15486
15973
|
}
|
|
15487
15974
|
function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
15488
15975
|
if (computed.nodes.length === 0) {
|
|
15489
|
-
return { nodes: [], edges: [], groups: [], options: {}, width: 0, height: 0 };
|
|
15976
|
+
return { nodes: [], edges: [], groups: [], options: {}, direction: computed.direction, width: 0, height: 0 };
|
|
15490
15977
|
}
|
|
15978
|
+
const isLR = computed.direction !== "TB";
|
|
15491
15979
|
const g = new import_dagre7.default.graphlib.Graph();
|
|
15492
15980
|
g.setGraph({
|
|
15493
15981
|
rankdir: computed.direction === "TB" ? "TB" : "LR",
|
|
15494
|
-
nodesep:
|
|
15495
|
-
ranksep:
|
|
15496
|
-
edgesep:
|
|
15982
|
+
nodesep: isLR ? 70 : 60,
|
|
15983
|
+
ranksep: isLR ? 150 : 120,
|
|
15984
|
+
edgesep: 30
|
|
15497
15985
|
});
|
|
15498
15986
|
g.setDefaultEdgeLabel(() => ({}));
|
|
15499
15987
|
const groupedNodeIds = /* @__PURE__ */ new Set();
|
|
@@ -15501,7 +15989,6 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
15501
15989
|
if (node.groupId) groupedNodeIds.add(node.id);
|
|
15502
15990
|
}
|
|
15503
15991
|
const GROUP_INFLATE = GROUP_PADDING3 * 2 + GROUP_HEADER_HEIGHT;
|
|
15504
|
-
const isLR = computed.direction !== "TB";
|
|
15505
15992
|
const widthMap = /* @__PURE__ */ new Map();
|
|
15506
15993
|
const heightMap = /* @__PURE__ */ new Map();
|
|
15507
15994
|
for (const node of computed.nodes) {
|
|
@@ -15636,7 +16123,8 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
15636
16123
|
lineNumber: group.lineNumber
|
|
15637
16124
|
};
|
|
15638
16125
|
});
|
|
15639
|
-
separateGroups(layoutGroups, layoutNodes, isLR);
|
|
16126
|
+
const groupDeltas = separateGroups(layoutGroups, layoutNodes, isLR);
|
|
16127
|
+
fixEdgeWaypoints(layoutEdges, layoutNodes, groupDeltas);
|
|
15640
16128
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
15641
16129
|
for (const node of layoutNodes) {
|
|
15642
16130
|
const left = node.x - node.width / 2;
|
|
@@ -15694,6 +16182,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
15694
16182
|
edges: layoutEdges,
|
|
15695
16183
|
groups: layoutGroups,
|
|
15696
16184
|
options: computed.options,
|
|
16185
|
+
direction: computed.direction,
|
|
15697
16186
|
width: totalWidth,
|
|
15698
16187
|
height: totalHeight
|
|
15699
16188
|
};
|
|
@@ -15736,23 +16225,23 @@ var init_layout8 = __esm({
|
|
|
15736
16225
|
]);
|
|
15737
16226
|
DISPLAY_NAMES = {
|
|
15738
16227
|
"cache-hit": "cache hit",
|
|
15739
|
-
"firewall-block": "
|
|
16228
|
+
"firewall-block": "firewall block",
|
|
15740
16229
|
"ratelimit-rps": "rate limit RPS",
|
|
15741
16230
|
"latency-ms": "latency",
|
|
15742
16231
|
"uptime": "uptime",
|
|
15743
16232
|
"instances": "instances",
|
|
15744
16233
|
"max-rps": "max RPS",
|
|
15745
|
-
"cb-error-threshold": "CB error",
|
|
15746
|
-
"cb-latency-threshold-ms": "CB latency",
|
|
16234
|
+
"cb-error-threshold": "CB error threshold",
|
|
16235
|
+
"cb-latency-threshold-ms": "CB latency threshold",
|
|
15747
16236
|
"concurrency": "concurrency",
|
|
15748
16237
|
"duration-ms": "duration",
|
|
15749
16238
|
"cold-start-ms": "cold start",
|
|
15750
16239
|
"buffer": "buffer",
|
|
15751
|
-
"drain-rate": "drain",
|
|
16240
|
+
"drain-rate": "drain rate",
|
|
15752
16241
|
"retention-hours": "retention",
|
|
15753
16242
|
"partitions": "partitions"
|
|
15754
16243
|
};
|
|
15755
|
-
GROUP_GAP =
|
|
16244
|
+
GROUP_GAP = GROUP_PADDING3 * 2 + GROUP_HEADER_HEIGHT;
|
|
15756
16245
|
}
|
|
15757
16246
|
});
|
|
15758
16247
|
|
|
@@ -15825,6 +16314,236 @@ function resolveNodeSlo(node, diagramOptions) {
|
|
|
15825
16314
|
if (availThreshold == null && latencyP90 == null) return null;
|
|
15826
16315
|
return { availThreshold, latencyP90, warningMargin };
|
|
15827
16316
|
}
|
|
16317
|
+
function buildPathD(pts, direction) {
|
|
16318
|
+
const gen = d3Shape7.line().x((d) => d.x).y((d) => d.y);
|
|
16319
|
+
if (pts.length <= 2) {
|
|
16320
|
+
gen.curve(direction === "TB" ? d3Shape7.curveBumpY : d3Shape7.curveBumpX);
|
|
16321
|
+
} else {
|
|
16322
|
+
gen.curve(d3Shape7.curveCatmullRom.alpha(0.5));
|
|
16323
|
+
}
|
|
16324
|
+
return gen(pts) ?? "";
|
|
16325
|
+
}
|
|
16326
|
+
function computePortPts(edges, nodeMap, direction) {
|
|
16327
|
+
const srcPts = /* @__PURE__ */ new Map();
|
|
16328
|
+
const tgtPts = /* @__PURE__ */ new Map();
|
|
16329
|
+
const PAD = 0.1;
|
|
16330
|
+
const activeEdges = edges.filter((e) => e.points.length > 0);
|
|
16331
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
16332
|
+
for (const e of activeEdges) {
|
|
16333
|
+
if (!bySource.has(e.sourceId)) bySource.set(e.sourceId, []);
|
|
16334
|
+
bySource.get(e.sourceId).push(e);
|
|
16335
|
+
}
|
|
16336
|
+
for (const [sourceId, es] of bySource) {
|
|
16337
|
+
if (es.length < 2) continue;
|
|
16338
|
+
const source = nodeMap.get(sourceId);
|
|
16339
|
+
if (!source) continue;
|
|
16340
|
+
const sorted = es.map((e) => ({ e, t: nodeMap.get(e.targetId) })).filter((x) => x.t != null).sort((a, b) => direction === "LR" ? a.t.y - b.t.y : a.t.x - b.t.x);
|
|
16341
|
+
const n = sorted.length;
|
|
16342
|
+
for (let i = 0; i < n; i++) {
|
|
16343
|
+
const frac = n === 1 ? 0.5 : PAD + (1 - 2 * PAD) * i / (n - 1);
|
|
16344
|
+
const { e, t } = sorted[i];
|
|
16345
|
+
const isBackward = direction === "LR" ? t.x < source.x : t.y < source.y;
|
|
16346
|
+
if (direction === "LR") {
|
|
16347
|
+
srcPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16348
|
+
x: isBackward ? source.x - source.width / 2 : source.x + source.width / 2,
|
|
16349
|
+
y: source.y - source.height / 2 + frac * source.height
|
|
16350
|
+
});
|
|
16351
|
+
} else {
|
|
16352
|
+
srcPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16353
|
+
x: source.x - source.width / 2 + frac * source.width,
|
|
16354
|
+
y: isBackward ? source.y - source.height / 2 : source.y + source.height / 2
|
|
16355
|
+
});
|
|
16356
|
+
}
|
|
16357
|
+
}
|
|
16358
|
+
}
|
|
16359
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
16360
|
+
for (const e of activeEdges) {
|
|
16361
|
+
if (!byTarget.has(e.targetId)) byTarget.set(e.targetId, []);
|
|
16362
|
+
byTarget.get(e.targetId).push(e);
|
|
16363
|
+
}
|
|
16364
|
+
for (const [targetId, es] of byTarget) {
|
|
16365
|
+
if (es.length < 2) continue;
|
|
16366
|
+
const target = nodeMap.get(targetId);
|
|
16367
|
+
if (!target) continue;
|
|
16368
|
+
const sorted = es.map((e) => ({ e, s: nodeMap.get(e.sourceId) })).filter((x) => x.s != null).sort((a, b) => direction === "LR" ? a.s.y - b.s.y : a.s.x - b.s.x);
|
|
16369
|
+
const n = sorted.length;
|
|
16370
|
+
for (let i = 0; i < n; i++) {
|
|
16371
|
+
const frac = n === 1 ? 0.5 : PAD + (1 - 2 * PAD) * i / (n - 1);
|
|
16372
|
+
const { e, s } = sorted[i];
|
|
16373
|
+
const isBackward = direction === "LR" ? target.x < s.x : target.y < s.y;
|
|
16374
|
+
if (direction === "LR") {
|
|
16375
|
+
tgtPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16376
|
+
x: isBackward ? target.x + target.width / 2 : target.x - target.width / 2,
|
|
16377
|
+
y: target.y - target.height / 2 + frac * target.height
|
|
16378
|
+
});
|
|
16379
|
+
} else {
|
|
16380
|
+
tgtPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16381
|
+
x: target.x - target.width / 2 + frac * target.width,
|
|
16382
|
+
y: isBackward ? target.y + target.height / 2 : target.y - target.height / 2
|
|
16383
|
+
});
|
|
16384
|
+
}
|
|
16385
|
+
}
|
|
16386
|
+
}
|
|
16387
|
+
return { srcPts, tgtPts };
|
|
16388
|
+
}
|
|
16389
|
+
function findRoutingLane(blocking, targetY, margin) {
|
|
16390
|
+
const MERGE_SLOP = 4;
|
|
16391
|
+
const sorted = [...blocking].sort((a, b) => a.y + a.height / 2 - (b.y + b.height / 2));
|
|
16392
|
+
const merged = [];
|
|
16393
|
+
for (const r of sorted) {
|
|
16394
|
+
const lo = r.y - MERGE_SLOP;
|
|
16395
|
+
const hi = r.y + r.height + MERGE_SLOP;
|
|
16396
|
+
if (merged.length && lo <= merged[merged.length - 1][1]) {
|
|
16397
|
+
merged[merged.length - 1][1] = Math.max(merged[merged.length - 1][1], hi);
|
|
16398
|
+
} else {
|
|
16399
|
+
merged.push([lo, hi]);
|
|
16400
|
+
}
|
|
16401
|
+
}
|
|
16402
|
+
if (merged.length === 0) return targetY;
|
|
16403
|
+
const MIN_GAP = 10;
|
|
16404
|
+
const candidates = [
|
|
16405
|
+
merged[0][0] - margin,
|
|
16406
|
+
// above all blocking rects
|
|
16407
|
+
merged[merged.length - 1][1] + margin
|
|
16408
|
+
// below all blocking rects
|
|
16409
|
+
];
|
|
16410
|
+
for (let i = 0; i < merged.length - 1; i++) {
|
|
16411
|
+
const gapLo = merged[i][1];
|
|
16412
|
+
const gapHi = merged[i + 1][0];
|
|
16413
|
+
if (gapHi - gapLo >= MIN_GAP) {
|
|
16414
|
+
candidates.push((gapLo + gapHi) / 2);
|
|
16415
|
+
}
|
|
16416
|
+
}
|
|
16417
|
+
return candidates.reduce(
|
|
16418
|
+
(best, c) => Math.abs(c - targetY) < Math.abs(best - targetY) ? c : best,
|
|
16419
|
+
candidates[0]
|
|
16420
|
+
);
|
|
16421
|
+
}
|
|
16422
|
+
function segmentIntersectsRect(p1, p2, rect) {
|
|
16423
|
+
const { x: rx, y: ry, width: rw, height: rh } = rect;
|
|
16424
|
+
const rr = rx + rw;
|
|
16425
|
+
const rb = ry + rh;
|
|
16426
|
+
const inRect = (p) => p.x >= rx && p.x <= rr && p.y >= ry && p.y <= rb;
|
|
16427
|
+
if (inRect(p1) || inRect(p2)) return true;
|
|
16428
|
+
if (Math.max(p1.x, p2.x) < rx || Math.min(p1.x, p2.x) > rr) return false;
|
|
16429
|
+
if (Math.max(p1.y, p2.y) < ry || Math.min(p1.y, p2.y) > rb) return false;
|
|
16430
|
+
const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
|
|
16431
|
+
const crosses = (a, b) => {
|
|
16432
|
+
const d1 = cross(a, b, p1);
|
|
16433
|
+
const d2 = cross(a, b, p2);
|
|
16434
|
+
const d3 = cross(p1, p2, a);
|
|
16435
|
+
const d4 = cross(p1, p2, b);
|
|
16436
|
+
return (d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d3 > 0 && d4 < 0 || d3 < 0 && d4 > 0);
|
|
16437
|
+
};
|
|
16438
|
+
const tl = { x: rx, y: ry };
|
|
16439
|
+
const tr = { x: rr, y: ry };
|
|
16440
|
+
const br = { x: rr, y: rb };
|
|
16441
|
+
const bl = { x: rx, y: rb };
|
|
16442
|
+
return crosses(tl, tr) || crosses(tr, br) || crosses(br, bl) || crosses(bl, tl);
|
|
16443
|
+
}
|
|
16444
|
+
function curveIntersectsRect(sc, tc, rect, direction) {
|
|
16445
|
+
if (direction === "LR") {
|
|
16446
|
+
const midX = (sc.x + tc.x) / 2;
|
|
16447
|
+
const m1 = { x: midX, y: sc.y };
|
|
16448
|
+
const m2 = { x: midX, y: tc.y };
|
|
16449
|
+
return segmentIntersectsRect(sc, m1, rect) || segmentIntersectsRect(m1, m2, rect) || segmentIntersectsRect(m2, tc, rect);
|
|
16450
|
+
} else {
|
|
16451
|
+
const midY = (sc.y + tc.y) / 2;
|
|
16452
|
+
const m1 = { x: sc.x, y: midY };
|
|
16453
|
+
const m2 = { x: tc.x, y: midY };
|
|
16454
|
+
return segmentIntersectsRect(sc, m1, rect) || segmentIntersectsRect(m1, m2, rect) || segmentIntersectsRect(m2, tc, rect);
|
|
16455
|
+
}
|
|
16456
|
+
}
|
|
16457
|
+
function edgeWaypoints(source, target, groups, nodes, direction, margin = 30, srcExitPt, tgtEnterPt) {
|
|
16458
|
+
const sc = { x: source.x, y: source.y };
|
|
16459
|
+
const tc = { x: target.x, y: target.y };
|
|
16460
|
+
const isBackward = direction === "LR" ? tc.x < sc.x : tc.y < sc.y;
|
|
16461
|
+
if (isBackward) {
|
|
16462
|
+
if (direction === "LR") {
|
|
16463
|
+
const xBandObs = [];
|
|
16464
|
+
for (const g of groups) {
|
|
16465
|
+
if (g.x + g.width < tc.x - margin || g.x > sc.x + margin) continue;
|
|
16466
|
+
xBandObs.push({ x: g.x, y: g.y, width: g.width, height: g.height });
|
|
16467
|
+
}
|
|
16468
|
+
for (const n of nodes) {
|
|
16469
|
+
if (n.id === source.id || n.id === target.id) continue;
|
|
16470
|
+
const nLeft = n.x - n.width / 2;
|
|
16471
|
+
const nRight = n.x + n.width / 2;
|
|
16472
|
+
if (nRight < tc.x - margin || nLeft > sc.x + margin) continue;
|
|
16473
|
+
xBandObs.push({ x: nLeft, y: n.y - n.height / 2, width: n.width, height: n.height });
|
|
16474
|
+
}
|
|
16475
|
+
const midY = (sc.y + tc.y) / 2;
|
|
16476
|
+
const routeY2 = xBandObs.length > 0 ? findRoutingLane(xBandObs, midY, margin) : midY;
|
|
16477
|
+
const exitBorder = srcExitPt ?? nodeBorderPoint(source, { x: sc.x, y: routeY2 });
|
|
16478
|
+
const exitPt2 = { x: exitBorder.x, y: routeY2 };
|
|
16479
|
+
const enterPt2 = { x: tc.x, y: routeY2 };
|
|
16480
|
+
const tp2 = tgtEnterPt ?? nodeBorderPoint(target, enterPt2);
|
|
16481
|
+
return srcExitPt ? [srcExitPt, exitPt2, enterPt2, tp2] : [exitBorder, exitPt2, enterPt2, tp2];
|
|
16482
|
+
} else {
|
|
16483
|
+
const yBandObs = [];
|
|
16484
|
+
for (const g of groups) {
|
|
16485
|
+
if (g.y + g.height < tc.y - margin || g.y > sc.y + margin) continue;
|
|
16486
|
+
yBandObs.push({ x: g.x, y: g.y, width: g.width, height: g.height });
|
|
16487
|
+
}
|
|
16488
|
+
for (const n of nodes) {
|
|
16489
|
+
if (n.id === source.id || n.id === target.id) continue;
|
|
16490
|
+
const nTop = n.y - n.height / 2;
|
|
16491
|
+
const nBot = n.y + n.height / 2;
|
|
16492
|
+
if (nBot < tc.y - margin || nTop > sc.y + margin) continue;
|
|
16493
|
+
yBandObs.push({ x: n.x - n.width / 2, y: nTop, width: n.width, height: n.height });
|
|
16494
|
+
}
|
|
16495
|
+
const rotated = yBandObs.map((r) => ({ x: r.y, y: r.x, width: r.height, height: r.width }));
|
|
16496
|
+
const midX = (sc.x + tc.x) / 2;
|
|
16497
|
+
const routeX = rotated.length > 0 ? findRoutingLane(rotated, midX, margin) : midX;
|
|
16498
|
+
const exitPt2 = srcExitPt ?? { x: routeX, y: sc.y };
|
|
16499
|
+
const enterPt2 = { x: routeX, y: tc.y };
|
|
16500
|
+
return [
|
|
16501
|
+
srcExitPt ?? nodeBorderPoint(source, exitPt2),
|
|
16502
|
+
exitPt2,
|
|
16503
|
+
enterPt2,
|
|
16504
|
+
tgtEnterPt ?? nodeBorderPoint(target, enterPt2)
|
|
16505
|
+
];
|
|
16506
|
+
}
|
|
16507
|
+
}
|
|
16508
|
+
const blocking = [];
|
|
16509
|
+
const blockingGroupIds = /* @__PURE__ */ new Set();
|
|
16510
|
+
const pathSrc = srcExitPt ?? sc;
|
|
16511
|
+
const pathTgt = tgtEnterPt ?? tc;
|
|
16512
|
+
for (const g of groups) {
|
|
16513
|
+
if (g.id === source.groupId || g.id === target.groupId) continue;
|
|
16514
|
+
const gRect = { x: g.x, y: g.y, width: g.width, height: g.height };
|
|
16515
|
+
if (curveIntersectsRect(pathSrc, pathTgt, gRect, direction)) {
|
|
16516
|
+
blocking.push(gRect);
|
|
16517
|
+
blockingGroupIds.add(g.id);
|
|
16518
|
+
}
|
|
16519
|
+
}
|
|
16520
|
+
for (const n of nodes) {
|
|
16521
|
+
if (n.id === source.id || n.id === target.id) continue;
|
|
16522
|
+
if (n.groupId && (n.groupId === source.groupId || n.groupId === target.groupId)) continue;
|
|
16523
|
+
if (n.groupId && blockingGroupIds.has(n.groupId)) continue;
|
|
16524
|
+
const nodeRect = { x: n.x - n.width / 2, y: n.y - n.height / 2, width: n.width, height: n.height };
|
|
16525
|
+
if (curveIntersectsRect(pathSrc, pathTgt, nodeRect, direction)) {
|
|
16526
|
+
blocking.push(nodeRect);
|
|
16527
|
+
}
|
|
16528
|
+
}
|
|
16529
|
+
if (blocking.length === 0) {
|
|
16530
|
+
const sp = srcExitPt ?? nodeBorderPoint(source, tc);
|
|
16531
|
+
const tp2 = tgtEnterPt ?? nodeBorderPoint(target, sp);
|
|
16532
|
+
return [sp, tp2];
|
|
16533
|
+
}
|
|
16534
|
+
const obsLeft = Math.min(...blocking.map((o) => o.x));
|
|
16535
|
+
const obsRight = Math.max(...blocking.map((o) => o.x + o.width));
|
|
16536
|
+
const routeY = findRoutingLane(blocking, tc.y, margin);
|
|
16537
|
+
const exitX = direction === "LR" ? Math.max(sc.x, obsLeft - margin) : obsLeft - margin;
|
|
16538
|
+
const enterX = direction === "LR" ? Math.min(tc.x, obsRight + margin) : obsRight + margin;
|
|
16539
|
+
const exitPt = { x: exitX, y: routeY };
|
|
16540
|
+
const enterPt = { x: enterX, y: routeY };
|
|
16541
|
+
const tp = tgtEnterPt ?? nodeBorderPoint(target, enterPt);
|
|
16542
|
+
if (srcExitPt) {
|
|
16543
|
+
return [srcExitPt, exitPt, enterPt, tp];
|
|
16544
|
+
}
|
|
16545
|
+
return [nodeBorderPoint(source, exitPt), exitPt, enterPt, tp];
|
|
16546
|
+
}
|
|
15828
16547
|
function nodeBorderPoint(node, target) {
|
|
15829
16548
|
const hw = node.width / 2;
|
|
15830
16549
|
const hh = node.height / 2;
|
|
@@ -16108,33 +16827,29 @@ function renderGroups(svg, groups, palette, isDark) {
|
|
|
16108
16827
|
}
|
|
16109
16828
|
}
|
|
16110
16829
|
}
|
|
16111
|
-
function renderEdgePaths(svg, edges, nodes, palette, isDark, animate) {
|
|
16830
|
+
function renderEdgePaths(svg, edges, nodes, groups, palette, isDark, animate, direction) {
|
|
16112
16831
|
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
|
|
16113
16832
|
const maxRps = Math.max(...edges.map((e) => e.computedRps), 1);
|
|
16833
|
+
const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
|
|
16114
16834
|
for (const edge of edges) {
|
|
16115
16835
|
if (edge.points.length === 0) continue;
|
|
16116
16836
|
const targetNode = nodeMap.get(edge.targetId);
|
|
16117
16837
|
const sourceNode = nodeMap.get(edge.sourceId);
|
|
16118
16838
|
const color = edgeColor(edge, palette);
|
|
16119
16839
|
const strokeW = edgeWidth();
|
|
16120
|
-
|
|
16121
|
-
|
|
16122
|
-
|
|
16123
|
-
|
|
16124
|
-
|
|
16125
|
-
|
|
16126
|
-
|
|
16127
|
-
|
|
16128
|
-
|
|
16129
|
-
|
|
16130
|
-
|
|
16131
|
-
|
|
16132
|
-
|
|
16133
|
-
if (targetNode && pts.length > 0) {
|
|
16134
|
-
const bp = nodeBorderPoint(targetNode, pts[pts.length - 1]);
|
|
16135
|
-
pts = [...pts, bp];
|
|
16136
|
-
}
|
|
16137
|
-
const pathD = lineGenerator7(pts) ?? "";
|
|
16840
|
+
if (!sourceNode || !targetNode) continue;
|
|
16841
|
+
const key = `${edge.sourceId}:${edge.targetId}`;
|
|
16842
|
+
const pts = edgeWaypoints(
|
|
16843
|
+
sourceNode,
|
|
16844
|
+
targetNode,
|
|
16845
|
+
groups,
|
|
16846
|
+
nodes,
|
|
16847
|
+
direction,
|
|
16848
|
+
30,
|
|
16849
|
+
srcPts.get(key),
|
|
16850
|
+
tgtPts.get(key)
|
|
16851
|
+
);
|
|
16852
|
+
const pathD = buildPathD(pts, direction);
|
|
16138
16853
|
const edgeG = svg.append("g").attr("class", "infra-edge").attr("data-line-number", edge.lineNumber);
|
|
16139
16854
|
edgeG.append("path").attr("d", pathD).attr("fill", "none").attr("stroke", color).attr("stroke-width", strokeW);
|
|
16140
16855
|
if (animate && edge.computedRps > 0) {
|
|
@@ -16149,19 +16864,34 @@ function renderEdgePaths(svg, edges, nodes, palette, isDark, animate) {
|
|
|
16149
16864
|
}
|
|
16150
16865
|
}
|
|
16151
16866
|
}
|
|
16152
|
-
function renderEdgeLabels(svg, edges, palette, isDark, animate) {
|
|
16867
|
+
function renderEdgeLabels(svg, edges, nodes, groups, palette, isDark, animate, direction) {
|
|
16868
|
+
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
|
|
16869
|
+
const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
|
|
16153
16870
|
for (const edge of edges) {
|
|
16154
16871
|
if (edge.points.length === 0) continue;
|
|
16155
16872
|
if (!edge.label) continue;
|
|
16156
|
-
const
|
|
16157
|
-
const
|
|
16873
|
+
const sourceNode = nodeMap.get(edge.sourceId);
|
|
16874
|
+
const targetNode = nodeMap.get(edge.targetId);
|
|
16875
|
+
if (!sourceNode || !targetNode) continue;
|
|
16876
|
+
const key = `${edge.sourceId}:${edge.targetId}`;
|
|
16877
|
+
const wps = edgeWaypoints(
|
|
16878
|
+
sourceNode,
|
|
16879
|
+
targetNode,
|
|
16880
|
+
groups,
|
|
16881
|
+
nodes,
|
|
16882
|
+
direction,
|
|
16883
|
+
30,
|
|
16884
|
+
srcPts.get(key),
|
|
16885
|
+
tgtPts.get(key)
|
|
16886
|
+
);
|
|
16887
|
+
const midPt = wps[Math.floor(wps.length / 2)];
|
|
16158
16888
|
const labelText = edge.label;
|
|
16159
16889
|
const g = svg.append("g").attr("class", animate ? "infra-edge-label" : "");
|
|
16160
16890
|
const textWidth = labelText.length * 6.5 + 8;
|
|
16161
16891
|
g.append("rect").attr("x", midPt.x - textWidth / 2).attr("y", midPt.y - 8).attr("width", textWidth).attr("height", 16).attr("rx", 3).attr("fill", palette.bg).attr("opacity", 0.9);
|
|
16162
16892
|
g.append("text").attr("x", midPt.x).attr("y", midPt.y + 4).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).attr("font-size", EDGE_LABEL_FONT_SIZE7).attr("fill", palette.textMuted).text(labelText);
|
|
16163
16893
|
if (animate) {
|
|
16164
|
-
const pathD =
|
|
16894
|
+
const pathD = buildPathD(wps, direction);
|
|
16165
16895
|
g.insert("path", ":first-child").attr("d", pathD).attr("fill", "none").attr("stroke", "transparent").attr("stroke-width", 20);
|
|
16166
16896
|
}
|
|
16167
16897
|
}
|
|
@@ -16571,7 +17301,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
16571
17301
|
rootSvg.append("text").attr("class", "chart-title").attr("x", totalWidth / 2).attr("y", 28).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).attr("font-size", 18).attr("font-weight", "700").attr("fill", palette.text).attr("data-line-number", titleLineNumber != null ? titleLineNumber : "").text(title);
|
|
16572
17302
|
}
|
|
16573
17303
|
renderGroups(svg, layout.groups, palette, isDark);
|
|
16574
|
-
renderEdgePaths(svg, layout.edges, layout.nodes, palette, isDark, shouldAnimate);
|
|
17304
|
+
renderEdgePaths(svg, layout.edges, layout.nodes, layout.groups, palette, isDark, shouldAnimate, layout.direction);
|
|
16575
17305
|
const fanoutSourceIds = collectFanoutSourceIds(layout.edges);
|
|
16576
17306
|
const scaledGroupIds = new Set(
|
|
16577
17307
|
layout.groups.filter((g) => {
|
|
@@ -16583,7 +17313,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
16583
17313
|
if (shouldAnimate) {
|
|
16584
17314
|
renderRejectParticles(svg, layout.nodes);
|
|
16585
17315
|
}
|
|
16586
|
-
renderEdgeLabels(svg, layout.edges, palette, isDark, shouldAnimate);
|
|
17316
|
+
renderEdgeLabels(svg, layout.edges, layout.nodes, layout.groups, palette, isDark, shouldAnimate, layout.direction);
|
|
16587
17317
|
if (hasLegend) {
|
|
16588
17318
|
if (fixedLegend) {
|
|
16589
17319
|
const containerWidth = container.clientWidth || totalWidth;
|
|
@@ -16601,7 +17331,7 @@ function parseAndLayoutInfra(content) {
|
|
|
16601
17331
|
const layout = layoutInfra(computed);
|
|
16602
17332
|
return { parsed, computed, layout };
|
|
16603
17333
|
}
|
|
16604
|
-
var d3Selection9, d3Shape7, NODE_FONT_SIZE4, META_FONT_SIZE4, META_LINE_HEIGHT8, EDGE_LABEL_FONT_SIZE7, GROUP_LABEL_FONT_SIZE2, NODE_BORDER_RADIUS, EDGE_STROKE_WIDTH8, NODE_STROKE_WIDTH8, OVERLOAD_STROKE_WIDTH, ROLE_DOT_RADIUS, NODE_HEADER_HEIGHT2, NODE_SEPARATOR_GAP2, NODE_PAD_BOTTOM2, COLLAPSE_BAR_HEIGHT5, COLLAPSE_BAR_INSET2, LEGEND_FIXED_GAP3, COLOR_HEALTHY, COLOR_WARNING, COLOR_OVERLOADED, FLOW_SPEED_MIN, FLOW_SPEED_MAX, PARTICLE_R, PARTICLE_COUNT_MIN, PARTICLE_COUNT_MAX, NODE_PULSE_SPEED, NODE_PULSE_OVERLOAD, REJECT_PARTICLE_R, REJECT_DROP_DISTANCE, REJECT_DURATION_MIN, REJECT_DURATION_MAX, REJECT_COUNT_MIN, REJECT_COUNT_MAX,
|
|
17334
|
+
var d3Selection9, d3Shape7, NODE_FONT_SIZE4, META_FONT_SIZE4, META_LINE_HEIGHT8, EDGE_LABEL_FONT_SIZE7, GROUP_LABEL_FONT_SIZE2, NODE_BORDER_RADIUS, EDGE_STROKE_WIDTH8, NODE_STROKE_WIDTH8, OVERLOAD_STROKE_WIDTH, ROLE_DOT_RADIUS, NODE_HEADER_HEIGHT2, NODE_SEPARATOR_GAP2, NODE_PAD_BOTTOM2, COLLAPSE_BAR_HEIGHT5, COLLAPSE_BAR_INSET2, LEGEND_FIXED_GAP3, COLOR_HEALTHY, COLOR_WARNING, COLOR_OVERLOADED, FLOW_SPEED_MIN, FLOW_SPEED_MAX, PARTICLE_R, PARTICLE_COUNT_MIN, PARTICLE_COUNT_MAX, NODE_PULSE_SPEED, NODE_PULSE_OVERLOAD, REJECT_PARTICLE_R, REJECT_DROP_DISTANCE, REJECT_DURATION_MIN, REJECT_DURATION_MAX, REJECT_COUNT_MIN, REJECT_COUNT_MAX, PROP_DISPLAY, DESC_MAX_CHARS, RPS_FORMAT_KEYS, MS_FORMAT_KEYS, PCT_FORMAT_KEYS;
|
|
16605
17335
|
var init_renderer8 = __esm({
|
|
16606
17336
|
"src/infra/renderer.ts"() {
|
|
16607
17337
|
"use strict";
|
|
@@ -16647,7 +17377,6 @@ var init_renderer8 = __esm({
|
|
|
16647
17377
|
REJECT_DURATION_MAX = 3;
|
|
16648
17378
|
REJECT_COUNT_MIN = 1;
|
|
16649
17379
|
REJECT_COUNT_MAX = 3;
|
|
16650
|
-
lineGenerator7 = d3Shape7.line().x((d) => d.x).y((d) => d.y).curve(d3Shape7.curveBasis);
|
|
16651
17380
|
PROP_DISPLAY = {
|
|
16652
17381
|
"cache-hit": "cache hit",
|
|
16653
17382
|
"firewall-block": "firewall block",
|
|
@@ -16830,7 +17559,7 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
|
|
|
16830
17559
|
}
|
|
16831
17560
|
}
|
|
16832
17561
|
} else if (edge.points.length >= 2) {
|
|
16833
|
-
const pathD =
|
|
17562
|
+
const pathD = lineGenerator7(edge.points);
|
|
16834
17563
|
if (pathD) {
|
|
16835
17564
|
edgeG.append("path").attr("d", pathD).attr("fill", "none").attr("stroke", edgeColor2).attr("stroke-width", EDGE_STROKE_WIDTH9).attr("marker-end", `url(#${markerId})`).attr("class", "st-edge");
|
|
16836
17565
|
}
|
|
@@ -16894,7 +17623,7 @@ function renderStateForExport(content, theme, palette) {
|
|
|
16894
17623
|
document.body.removeChild(container);
|
|
16895
17624
|
}
|
|
16896
17625
|
}
|
|
16897
|
-
var d3Selection10, d3Shape8, DIAGRAM_PADDING9, MAX_SCALE8, NODE_FONT_SIZE5, EDGE_LABEL_FONT_SIZE8, GROUP_LABEL_FONT_SIZE3, EDGE_STROKE_WIDTH9, NODE_STROKE_WIDTH9, ARROWHEAD_W4, ARROWHEAD_H4, PSEUDOSTATE_RADIUS, STATE_CORNER_RADIUS, GROUP_EXTRA_PADDING2,
|
|
17626
|
+
var d3Selection10, d3Shape8, DIAGRAM_PADDING9, MAX_SCALE8, NODE_FONT_SIZE5, EDGE_LABEL_FONT_SIZE8, GROUP_LABEL_FONT_SIZE3, EDGE_STROKE_WIDTH9, NODE_STROKE_WIDTH9, ARROWHEAD_W4, ARROWHEAD_H4, PSEUDOSTATE_RADIUS, STATE_CORNER_RADIUS, GROUP_EXTRA_PADDING2, lineGenerator7;
|
|
16898
17627
|
var init_state_renderer = __esm({
|
|
16899
17628
|
"src/graph/state-renderer.ts"() {
|
|
16900
17629
|
"use strict";
|
|
@@ -16916,7 +17645,7 @@ var init_state_renderer = __esm({
|
|
|
16916
17645
|
PSEUDOSTATE_RADIUS = 10;
|
|
16917
17646
|
STATE_CORNER_RADIUS = 10;
|
|
16918
17647
|
GROUP_EXTRA_PADDING2 = 12;
|
|
16919
|
-
|
|
17648
|
+
lineGenerator7 = d3Shape8.line().x((d) => d.x).y((d) => d.y).curve(d3Shape8.curveBasis);
|
|
16920
17649
|
}
|
|
16921
17650
|
});
|
|
16922
17651
|
|
|
@@ -18078,7 +18807,6 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
18078
18807
|
if (secY === void 0) continue;
|
|
18079
18808
|
const isCollapsed = collapsedSections?.has(sec.lineNumber) ?? false;
|
|
18080
18809
|
const lineColor = palette.textMuted;
|
|
18081
|
-
const HIT_AREA_HEIGHT = 36;
|
|
18082
18810
|
const sectionG = svg.append("g").attr("data-section-toggle", "").attr("data-line-number", String(sec.lineNumber)).attr("data-section", "").attr("tabindex", "0").attr("role", "button").attr("aria-expanded", String(!isCollapsed));
|
|
18083
18811
|
const BAND_HEIGHT = 22;
|
|
18084
18812
|
const bandX = sectionLineX1 - 10;
|
|
@@ -19467,7 +20195,6 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
19467
20195
|
const positions = groupNodes.map((n) => yScale(n));
|
|
19468
20196
|
const minY = Math.min(...positions) - bandPad;
|
|
19469
20197
|
const maxY = Math.max(...positions) + bandPad;
|
|
19470
|
-
const bandColor = group.color ?? mutedColor;
|
|
19471
20198
|
g.append("rect").attr("class", "arc-group-band").attr("data-group", group.name).attr("data-line-number", String(group.lineNumber)).attr("x", baseX - bandHalfW).attr("y", minY).attr("width", bandHalfW * 2).attr("height", maxY - minY).attr("rx", 4).attr("fill", textColor).attr("fill-opacity", 0.06).style("cursor", "pointer").on("mouseenter", () => handleGroupEnter(group.name)).on("mouseleave", handleMouseLeave).on("click", () => {
|
|
19472
20199
|
if (onClickItem) onClickItem(group.lineNumber);
|
|
19473
20200
|
});
|
|
@@ -19511,7 +20238,6 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
19511
20238
|
const positions = groupNodes.map((n) => xScale(n));
|
|
19512
20239
|
const minX = Math.min(...positions) - bandPad;
|
|
19513
20240
|
const maxX = Math.max(...positions) + bandPad;
|
|
19514
|
-
const bandColor = group.color ?? mutedColor;
|
|
19515
20241
|
g.append("rect").attr("class", "arc-group-band").attr("data-group", group.name).attr("data-line-number", String(group.lineNumber)).attr("x", minX).attr("y", baseY - bandHalfH).attr("width", maxX - minX).attr("height", bandHalfH * 2).attr("rx", 4).attr("fill", textColor).attr("fill-opacity", 0.06).style("cursor", "pointer").on("mouseenter", () => handleGroupEnter(group.name)).on("mouseleave", handleMouseLeave).on("click", () => {
|
|
19516
20242
|
if (onClickItem) onClickItem(group.lineNumber);
|
|
19517
20243
|
});
|
|
@@ -19829,6 +20555,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19829
20555
|
const textColor = palette.text;
|
|
19830
20556
|
const mutedColor = palette.border;
|
|
19831
20557
|
const bgColor = palette.bg;
|
|
20558
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
19832
20559
|
const colors = getSeriesColors(palette);
|
|
19833
20560
|
const groupColorMap = /* @__PURE__ */ new Map();
|
|
19834
20561
|
timelineGroups.forEach((grp, i) => {
|
|
@@ -20090,7 +20817,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20090
20817
|
if (ev.endDate) {
|
|
20091
20818
|
const y2 = yScale(parseTimelineDate(ev.endDate));
|
|
20092
20819
|
const rectH = Math.max(y2 - y, 4);
|
|
20093
|
-
let fill2 = evColor;
|
|
20820
|
+
let fill2 = mix(evColor, bg, 30);
|
|
20094
20821
|
if (ev.uncertain) {
|
|
20095
20822
|
const gradientId = `uncertain-vg-${ev.lineNumber}`;
|
|
20096
20823
|
const defs = svg.select("defs").node() || svg.append("defs").node();
|
|
@@ -20098,13 +20825,13 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20098
20825
|
{ offset: "0%", opacity: 1 },
|
|
20099
20826
|
{ offset: "80%", opacity: 1 },
|
|
20100
20827
|
{ offset: "100%", opacity: 0 }
|
|
20101
|
-
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", laneColor).attr("stop-opacity", (d) => d.opacity);
|
|
20828
|
+
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(laneColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
|
|
20102
20829
|
fill2 = `url(#${gradientId})`;
|
|
20103
20830
|
}
|
|
20104
|
-
evG.append("rect").attr("x", laneCenter - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2);
|
|
20831
|
+
evG.append("rect").attr("x", laneCenter - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2).attr("stroke", evColor).attr("stroke-width", 2);
|
|
20105
20832
|
evG.append("text").attr("x", laneCenter + 14).attr("y", y + rectH / 2).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
|
|
20106
20833
|
} else {
|
|
20107
|
-
evG.append("circle").attr("cx", laneCenter).attr("cy", y).attr("r", 4).attr("fill", evColor).attr("stroke",
|
|
20834
|
+
evG.append("circle").attr("cx", laneCenter).attr("cy", y).attr("r", 4).attr("fill", mix(evColor, bg, 30)).attr("stroke", evColor).attr("stroke-width", 2);
|
|
20108
20835
|
evG.append("text").attr("x", laneCenter + 10).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
|
|
20109
20836
|
}
|
|
20110
20837
|
}
|
|
@@ -20197,7 +20924,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20197
20924
|
if (ev.endDate) {
|
|
20198
20925
|
const y2 = yScale(parseTimelineDate(ev.endDate));
|
|
20199
20926
|
const rectH = Math.max(y2 - y, 4);
|
|
20200
|
-
let fill2 = color;
|
|
20927
|
+
let fill2 = mix(color, bg, 30);
|
|
20201
20928
|
if (ev.uncertain) {
|
|
20202
20929
|
const gradientId = `uncertain-v-${ev.lineNumber}`;
|
|
20203
20930
|
const defs = svg.select("defs").node() || svg.append("defs").node();
|
|
@@ -20205,13 +20932,13 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20205
20932
|
{ offset: "0%", opacity: 1 },
|
|
20206
20933
|
{ offset: "80%", opacity: 1 },
|
|
20207
20934
|
{ offset: "100%", opacity: 0 }
|
|
20208
|
-
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", color).attr("stop-opacity", (d) => d.opacity);
|
|
20935
|
+
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
|
|
20209
20936
|
fill2 = `url(#${gradientId})`;
|
|
20210
20937
|
}
|
|
20211
|
-
evG.append("rect").attr("x", axisX - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2);
|
|
20938
|
+
evG.append("rect").attr("x", axisX - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2).attr("stroke", color).attr("stroke-width", 2);
|
|
20212
20939
|
evG.append("text").attr("x", axisX + 16).attr("y", y + rectH / 2).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
|
|
20213
20940
|
} else {
|
|
20214
|
-
evG.append("circle").attr("cx", axisX).attr("cy", y).attr("r", 4).attr("fill", color).attr("stroke",
|
|
20941
|
+
evG.append("circle").attr("cx", axisX).attr("cy", y).attr("r", 4).attr("fill", mix(color, bg, 30)).attr("stroke", color).attr("stroke-width", 2);
|
|
20215
20942
|
evG.append("text").attr("x", axisX + 16).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
|
|
20216
20943
|
}
|
|
20217
20944
|
evG.append("text").attr("x", axisX - 14).attr(
|
|
@@ -20362,7 +21089,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20362
21089
|
const rectW = Math.max(x2 - x, 4);
|
|
20363
21090
|
const estLabelWidth = ev.label.length * 7 + 16;
|
|
20364
21091
|
const labelFitsInside = rectW >= estLabelWidth;
|
|
20365
|
-
let fill2 = evColor;
|
|
21092
|
+
let fill2 = mix(evColor, bg, 30);
|
|
20366
21093
|
if (ev.uncertain) {
|
|
20367
21094
|
const gradientId = `uncertain-${ev.lineNumber}`;
|
|
20368
21095
|
const defs = svg.select("defs").node() || svg.append("defs").node();
|
|
@@ -20370,12 +21097,12 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20370
21097
|
{ offset: "0%", opacity: 1 },
|
|
20371
21098
|
{ offset: "80%", opacity: 1 },
|
|
20372
21099
|
{ offset: "100%", opacity: 0 }
|
|
20373
|
-
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", evColor).attr("stop-opacity", (d) => d.opacity);
|
|
21100
|
+
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(evColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
|
|
20374
21101
|
fill2 = `url(#${gradientId})`;
|
|
20375
21102
|
}
|
|
20376
|
-
evG.append("rect").attr("x", x).attr("y", y - BAR_H / 2).attr("width", rectW).attr("height", BAR_H).attr("rx", 4).attr("fill", fill2);
|
|
21103
|
+
evG.append("rect").attr("x", x).attr("y", y - BAR_H / 2).attr("width", rectW).attr("height", BAR_H).attr("rx", 4).attr("fill", fill2).attr("stroke", evColor).attr("stroke-width", 2);
|
|
20377
21104
|
if (labelFitsInside) {
|
|
20378
|
-
evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill",
|
|
21105
|
+
evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", textColor).attr("font-size", "14px").attr("font-weight", "700").text(ev.label);
|
|
20379
21106
|
} else {
|
|
20380
21107
|
const wouldFlipLeft = x + rectW > innerWidth * 0.6;
|
|
20381
21108
|
const labelFitsLeft = x - 6 - estLabelWidth > 0;
|
|
@@ -20387,7 +21114,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20387
21114
|
const wouldFlipLeft = x > innerWidth * 0.6;
|
|
20388
21115
|
const labelFitsLeft = x - 10 - estLabelWidth > 0;
|
|
20389
21116
|
const flipLeft = wouldFlipLeft && labelFitsLeft;
|
|
20390
|
-
evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", evColor).attr("stroke",
|
|
21117
|
+
evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", mix(evColor, bg, 30)).attr("stroke", evColor).attr("stroke-width", 2);
|
|
20391
21118
|
evG.append("text").attr("x", flipLeft ? x - 10 : x + 10).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "12px").text(ev.label);
|
|
20392
21119
|
}
|
|
20393
21120
|
});
|
|
@@ -20500,7 +21227,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20500
21227
|
const rectW = Math.max(x2 - x, 4);
|
|
20501
21228
|
const estLabelWidth = ev.label.length * 7 + 16;
|
|
20502
21229
|
const labelFitsInside = rectW >= estLabelWidth;
|
|
20503
|
-
let fill2 = color;
|
|
21230
|
+
let fill2 = mix(color, bg, 30);
|
|
20504
21231
|
if (ev.uncertain) {
|
|
20505
21232
|
const gradientId = `uncertain-ts-${ev.lineNumber}`;
|
|
20506
21233
|
const defs = svg.select("defs").node() || svg.append("defs").node();
|
|
@@ -20508,12 +21235,12 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20508
21235
|
{ offset: "0%", opacity: 1 },
|
|
20509
21236
|
{ offset: "80%", opacity: 1 },
|
|
20510
21237
|
{ offset: "100%", opacity: 0 }
|
|
20511
|
-
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", color).attr("stop-opacity", (d) => d.opacity);
|
|
21238
|
+
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
|
|
20512
21239
|
fill2 = `url(#${gradientId})`;
|
|
20513
21240
|
}
|
|
20514
|
-
evG.append("rect").attr("x", x).attr("y", y - BAR_H / 2).attr("width", rectW).attr("height", BAR_H).attr("rx", 4).attr("fill", fill2);
|
|
21241
|
+
evG.append("rect").attr("x", x).attr("y", y - BAR_H / 2).attr("width", rectW).attr("height", BAR_H).attr("rx", 4).attr("fill", fill2).attr("stroke", color).attr("stroke-width", 2);
|
|
20515
21242
|
if (labelFitsInside) {
|
|
20516
|
-
evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill",
|
|
21243
|
+
evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", textColor).attr("font-size", "14px").attr("font-weight", "700").text(ev.label);
|
|
20517
21244
|
} else {
|
|
20518
21245
|
const wouldFlipLeft = x + rectW > innerWidth * 0.6;
|
|
20519
21246
|
const labelFitsLeft = x - 6 - estLabelWidth > 0;
|
|
@@ -20525,7 +21252,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20525
21252
|
const wouldFlipLeft = x > innerWidth * 0.6;
|
|
20526
21253
|
const labelFitsLeft = x - 10 - estLabelWidth > 0;
|
|
20527
21254
|
const flipLeft = wouldFlipLeft && labelFitsLeft;
|
|
20528
|
-
evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", color).attr("stroke",
|
|
21255
|
+
evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", mix(color, bg, 30)).attr("stroke", color).attr("stroke-width", 2);
|
|
20529
21256
|
evG.append("text").attr("x", flipLeft ? x - 10 : x + 10).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "12px").text(ev.label);
|
|
20530
21257
|
}
|
|
20531
21258
|
});
|
|
@@ -20680,8 +21407,8 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20680
21407
|
} else {
|
|
20681
21408
|
color = ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor;
|
|
20682
21409
|
}
|
|
20683
|
-
el.selectAll("rect").attr("fill", color);
|
|
20684
|
-
el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", color);
|
|
21410
|
+
el.selectAll("rect").attr("fill", mix(color, bg, 30)).attr("stroke", color);
|
|
21411
|
+
el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", mix(color, bg, 30)).attr("stroke", color);
|
|
20685
21412
|
});
|
|
20686
21413
|
};
|
|
20687
21414
|
var drawSwimlaneIcon = drawSwimlaneIcon2, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
|
|
@@ -21146,7 +21873,6 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
21146
21873
|
const init2 = initD3Chart(container, palette, exportDims);
|
|
21147
21874
|
if (!init2) return;
|
|
21148
21875
|
const { svg, width, height, textColor } = init2;
|
|
21149
|
-
const mutedColor = palette.textMuted;
|
|
21150
21876
|
const borderColor = palette.border;
|
|
21151
21877
|
const defaultColors = [
|
|
21152
21878
|
palette.colors.blue,
|
|
@@ -21170,13 +21896,17 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
21170
21896
|
const f = r.length === 3 ? r[0] + r[0] + r[1] + r[1] + r[2] + r[2] : r;
|
|
21171
21897
|
return [parseInt(f.substring(0, 2), 16), parseInt(f.substring(2, 4), 16), parseInt(f.substring(4, 6), 16)];
|
|
21172
21898
|
};
|
|
21173
|
-
const [ar, ag, ab] = parse(a), [br,
|
|
21899
|
+
const [ar, ag, ab] = parse(a), [br, bg2, bb] = parse(b), t = pct / 100;
|
|
21174
21900
|
const c = (x, y) => Math.round(x * t + y * (1 - t)).toString(16).padStart(2, "0");
|
|
21175
|
-
return `#${c(ar, br)}${c(ag,
|
|
21901
|
+
return `#${c(ar, br)}${c(ag, bg2)}${c(ab, bb)}`;
|
|
21176
21902
|
};
|
|
21177
|
-
const
|
|
21903
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
21904
|
+
const getQuadrantColor = (label, defaultIdx) => {
|
|
21178
21905
|
return label?.color ?? defaultColors[defaultIdx % defaultColors.length];
|
|
21179
21906
|
};
|
|
21907
|
+
const getQuadrantFill = (label, defaultIdx) => {
|
|
21908
|
+
return mixHex(getQuadrantColor(label, defaultIdx), bg, 30);
|
|
21909
|
+
};
|
|
21180
21910
|
const quadrantDefs = [
|
|
21181
21911
|
{
|
|
21182
21912
|
position: "top-left",
|
|
@@ -21227,12 +21957,11 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
21227
21957
|
// purple
|
|
21228
21958
|
}
|
|
21229
21959
|
];
|
|
21230
|
-
const quadrantRects = chartG.selectAll("rect.quadrant").data(quadrantDefs).enter().append("rect").attr("class", "quadrant").attr("x", (d) => d.x).attr("y", (d) => d.y).attr("width", (d) => d.w).attr("height", (d) => d.h).attr("fill", (d) => getQuadrantFill(d.label, d.colorIdx)).attr("stroke",
|
|
21231
|
-
const contrastColor = "#ffffff";
|
|
21960
|
+
const quadrantRects = chartG.selectAll("rect.quadrant").data(quadrantDefs).enter().append("rect").attr("class", "quadrant").attr("x", (d) => d.x).attr("y", (d) => d.y).attr("width", (d) => d.w).attr("height", (d) => d.h).attr("fill", (d) => getQuadrantFill(d.label, d.colorIdx)).attr("stroke", (d) => getQuadrantColor(d.label, d.colorIdx)).attr("stroke-width", 2);
|
|
21232
21961
|
const shadowColor = "rgba(0,0,0,0.4)";
|
|
21233
21962
|
const getQuadrantLabelColor = (d) => {
|
|
21234
|
-
const
|
|
21235
|
-
return mixHex("#000000",
|
|
21963
|
+
const color = getQuadrantColor(d.label, d.colorIdx);
|
|
21964
|
+
return mixHex("#000000", color, 40);
|
|
21236
21965
|
};
|
|
21237
21966
|
const LABEL_MAX_FONT = 48;
|
|
21238
21967
|
const LABEL_MIN_FONT = 14;
|
|
@@ -21373,7 +22102,7 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
21373
22102
|
const pointColor = quadDef?.label?.color ?? defaultColors[quadDef?.colorIdx ?? 0];
|
|
21374
22103
|
const pointG = pointsG.append("g").attr("class", "point-group").attr("data-line-number", String(point.lineNumber));
|
|
21375
22104
|
pointG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", 6).attr("fill", "#ffffff").attr("stroke", pointColor).attr("stroke-width", 2);
|
|
21376
|
-
pointG.append("text").attr("x", cx).attr("y", cy - 10).attr("text-anchor", "middle").attr("fill",
|
|
22105
|
+
pointG.append("text").attr("x", cx).attr("y", cy - 10).attr("text-anchor", "middle").attr("fill", textColor).attr("font-size", "12px").attr("font-weight", "700").style("text-shadow", `0 1px 2px ${shadowColor}`).text(point.label);
|
|
21377
22106
|
const tipHtml = `<strong>${point.label}</strong><br>x: ${point.x.toFixed(2)}, y: ${point.y.toFixed(2)}`;
|
|
21378
22107
|
pointG.style("cursor", onClickItem ? "pointer" : "default").on("mouseenter", (event) => {
|
|
21379
22108
|
showTooltip(tooltip, tipHtml, event);
|
|
@@ -21874,6 +22603,7 @@ __export(index_exports, {
|
|
|
21874
22603
|
contrastText: () => contrastText,
|
|
21875
22604
|
decodeDiagramUrl: () => decodeDiagramUrl,
|
|
21876
22605
|
encodeDiagramUrl: () => encodeDiagramUrl,
|
|
22606
|
+
extractDiagramSymbols: () => extractDiagramSymbols,
|
|
21877
22607
|
formatDateLabel: () => formatDateLabel,
|
|
21878
22608
|
formatDgmoError: () => formatDgmoError,
|
|
21879
22609
|
getAvailablePalettes: () => getAvailablePalettes,
|
|
@@ -21937,6 +22667,7 @@ __export(index_exports, {
|
|
|
21937
22667
|
parseState: () => parseState,
|
|
21938
22668
|
parseTimelineDate: () => parseTimelineDate,
|
|
21939
22669
|
parseVisualization: () => parseVisualization,
|
|
22670
|
+
registerExtractor: () => registerExtractor,
|
|
21940
22671
|
registerPalette: () => registerPalette,
|
|
21941
22672
|
render: () => render,
|
|
21942
22673
|
renderArcDiagram: () => renderArcDiagram,
|
|
@@ -22790,6 +23521,34 @@ function decodeDiagramUrl(hash) {
|
|
|
22790
23521
|
}
|
|
22791
23522
|
}
|
|
22792
23523
|
|
|
23524
|
+
// src/completion.ts
|
|
23525
|
+
init_parser3();
|
|
23526
|
+
init_flowchart_parser();
|
|
23527
|
+
init_parser9();
|
|
23528
|
+
init_parser2();
|
|
23529
|
+
var registry = /* @__PURE__ */ new Map();
|
|
23530
|
+
function registerExtractor(kind, fn) {
|
|
23531
|
+
registry.set(kind, fn);
|
|
23532
|
+
}
|
|
23533
|
+
function extractDiagramSymbols(docText) {
|
|
23534
|
+
let chartType = null;
|
|
23535
|
+
for (const line10 of docText.split("\n")) {
|
|
23536
|
+
const m = line10.match(/^\s*chart\s*:\s*(.+)/i);
|
|
23537
|
+
if (m) {
|
|
23538
|
+
chartType = m[1].trim().toLowerCase();
|
|
23539
|
+
break;
|
|
23540
|
+
}
|
|
23541
|
+
}
|
|
23542
|
+
if (!chartType) return null;
|
|
23543
|
+
const fn = registry.get(chartType);
|
|
23544
|
+
if (!fn) return null;
|
|
23545
|
+
return fn(docText);
|
|
23546
|
+
}
|
|
23547
|
+
registerExtractor("er", extractSymbols3);
|
|
23548
|
+
registerExtractor("flowchart", extractSymbols);
|
|
23549
|
+
registerExtractor("infra", extractSymbols4);
|
|
23550
|
+
registerExtractor("class", extractSymbols2);
|
|
23551
|
+
|
|
22793
23552
|
// src/index.ts
|
|
22794
23553
|
init_branding();
|
|
22795
23554
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -22822,6 +23581,7 @@ init_branding();
|
|
|
22822
23581
|
contrastText,
|
|
22823
23582
|
decodeDiagramUrl,
|
|
22824
23583
|
encodeDiagramUrl,
|
|
23584
|
+
extractDiagramSymbols,
|
|
22825
23585
|
formatDateLabel,
|
|
22826
23586
|
formatDgmoError,
|
|
22827
23587
|
getAvailablePalettes,
|
|
@@ -22885,6 +23645,7 @@ init_branding();
|
|
|
22885
23645
|
parseState,
|
|
22886
23646
|
parseTimelineDate,
|
|
22887
23647
|
parseVisualization,
|
|
23648
|
+
registerExtractor,
|
|
22888
23649
|
registerPalette,
|
|
22889
23650
|
render,
|
|
22890
23651
|
renderArcDiagram,
|