@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.js
CHANGED
|
@@ -1787,12 +1787,12 @@ var SYNC_LABELED_RE, ASYNC_LABELED_RE, RETURN_SYNC_LABELED_RE, RETURN_ASYNC_LABE
|
|
|
1787
1787
|
var init_arrows = __esm({
|
|
1788
1788
|
"src/utils/arrows.ts"() {
|
|
1789
1789
|
"use strict";
|
|
1790
|
-
SYNC_LABELED_RE = /^(
|
|
1791
|
-
ASYNC_LABELED_RE = /^(
|
|
1792
|
-
RETURN_SYNC_LABELED_RE = /^(
|
|
1793
|
-
RETURN_ASYNC_LABELED_RE = /^(
|
|
1794
|
-
BIDI_SYNC_RE = /^(
|
|
1795
|
-
BIDI_ASYNC_RE = /^(
|
|
1790
|
+
SYNC_LABELED_RE = /^(.+?)\s+-(.+)->\s+(.+)$/;
|
|
1791
|
+
ASYNC_LABELED_RE = /^(.+?)\s+~(.+)~>\s+(.+)$/;
|
|
1792
|
+
RETURN_SYNC_LABELED_RE = /^(.+?)\s+<-(.+)-\s+(.+)$/;
|
|
1793
|
+
RETURN_ASYNC_LABELED_RE = /^(.+?)\s+<~(.+)~\s+(.+)$/;
|
|
1794
|
+
BIDI_SYNC_RE = /^(.+?)\s+<-(.+)->\s+(.+)$/;
|
|
1795
|
+
BIDI_ASYNC_RE = /^(.+?)\s+<~(.+)~>\s+(.+)$/;
|
|
1796
1796
|
ARROW_CHARS = ["->", "~>"];
|
|
1797
1797
|
}
|
|
1798
1798
|
});
|
|
@@ -2201,7 +2201,7 @@ function parseSequenceDgmo(content) {
|
|
|
2201
2201
|
continue;
|
|
2202
2202
|
}
|
|
2203
2203
|
const bidiPlainMatch = arrowCore.match(
|
|
2204
|
-
/^(
|
|
2204
|
+
/^(.+?)\s*(?:<->|<~>)\s*(.+)/
|
|
2205
2205
|
);
|
|
2206
2206
|
if (bidiPlainMatch) {
|
|
2207
2207
|
pushError(
|
|
@@ -2210,8 +2210,8 @@ function parseSequenceDgmo(content) {
|
|
|
2210
2210
|
);
|
|
2211
2211
|
continue;
|
|
2212
2212
|
}
|
|
2213
|
-
const bareReturnSync = arrowCore.match(/^(
|
|
2214
|
-
const bareReturnAsync = arrowCore.match(/^(
|
|
2213
|
+
const bareReturnSync = arrowCore.match(/^(.+?)\s+<-\s+(.+)$/);
|
|
2214
|
+
const bareReturnAsync = arrowCore.match(/^(.+?)\s+<~\s+(.+)$/);
|
|
2215
2215
|
const bareReturn = bareReturnSync || bareReturnAsync;
|
|
2216
2216
|
if (bareReturn) {
|
|
2217
2217
|
const to = bareReturn[1];
|
|
@@ -2222,8 +2222,8 @@ function parseSequenceDgmo(content) {
|
|
|
2222
2222
|
);
|
|
2223
2223
|
continue;
|
|
2224
2224
|
}
|
|
2225
|
-
const bareCallSync = arrowCore.match(/^(
|
|
2226
|
-
const bareCallAsync = arrowCore.match(/^(
|
|
2225
|
+
const bareCallSync = arrowCore.match(/^(.+?)\s*->\s*(.+)$/);
|
|
2226
|
+
const bareCallAsync = arrowCore.match(/^(.+?)\s*~>\s*(.+)$/);
|
|
2227
2227
|
const bareCall = bareCallSync || bareCallAsync;
|
|
2228
2228
|
if (bareCall) {
|
|
2229
2229
|
contentStarted = true;
|
|
@@ -2475,21 +2475,22 @@ var init_parser = __esm({
|
|
|
2475
2475
|
"networking",
|
|
2476
2476
|
"frontend"
|
|
2477
2477
|
]);
|
|
2478
|
-
IS_A_PATTERN = /^(
|
|
2479
|
-
POSITION_ONLY_PATTERN = /^(
|
|
2478
|
+
IS_A_PATTERN = /^([^:]+?)\s+is\s+an?\s+(\w+)(?:\s+(.+))?$/i;
|
|
2479
|
+
POSITION_ONLY_PATTERN = /^([^:]+?)\s+position\s+(-?\d+)$/i;
|
|
2480
2480
|
COLORED_PARTICIPANT_PATTERN = /^(\S+?)\(([^)]+)\)\s*$/;
|
|
2481
2481
|
GROUP_HEADING_PATTERN = /^\[(.+?)(?:\(([^)]+)\))?\]\s*$/;
|
|
2482
2482
|
LEGACY_GROUP_PATTERN = /^##\s+(.+?)(?:\(([^)]+)\))?\s*$/;
|
|
2483
2483
|
SECTION_PATTERN = /^==\s+(.+?)(?:\s*==)?\s*$/;
|
|
2484
2484
|
ARROW_PATTERN = /\S+\s*(?:<-\S+-|<~\S+~|-\S+->|~\S+~>|->|~>|<-|<~)\s*\S+/;
|
|
2485
|
-
NOTE_SINGLE = /^note(?:\s+(right|left)\s+of\s+(
|
|
2486
|
-
NOTE_MULTI = /^note(?:\s+(right|left)\s+of\s+(
|
|
2485
|
+
NOTE_SINGLE = /^note(?:\s+(right|left)\s+of\s+(.+?))?\s*:\s*(.+)$/i;
|
|
2486
|
+
NOTE_MULTI = /^note(?:\s+(right|left)\s+of\s+(.+?))?\s*:?\s*$/i;
|
|
2487
2487
|
}
|
|
2488
2488
|
});
|
|
2489
2489
|
|
|
2490
2490
|
// src/graph/flowchart-parser.ts
|
|
2491
2491
|
var flowchart_parser_exports = {};
|
|
2492
2492
|
__export(flowchart_parser_exports, {
|
|
2493
|
+
extractSymbols: () => extractSymbols,
|
|
2493
2494
|
looksLikeFlowchart: () => looksLikeFlowchart,
|
|
2494
2495
|
parseFlowchart: () => parseFlowchart
|
|
2495
2496
|
});
|
|
@@ -2533,7 +2534,6 @@ function parseNodeRef(text, palette) {
|
|
|
2533
2534
|
}
|
|
2534
2535
|
function splitArrows(line10) {
|
|
2535
2536
|
const segments = [];
|
|
2536
|
-
const arrowRe = /(?:^|\s)-([^>\s(][^(>]*?)?\s*(?:\(([^)]+)\))?\s*->|(?:^|\s)->/g;
|
|
2537
2537
|
let lastIndex = 0;
|
|
2538
2538
|
const arrowPositions = [];
|
|
2539
2539
|
let searchFrom = 0;
|
|
@@ -2774,7 +2774,20 @@ function looksLikeFlowchart(content) {
|
|
|
2774
2774
|
/->[ \t]*[\[(<\/]/.test(content);
|
|
2775
2775
|
return shapeNearArrow;
|
|
2776
2776
|
}
|
|
2777
|
-
|
|
2777
|
+
function extractSymbols(docText) {
|
|
2778
|
+
const entities = [];
|
|
2779
|
+
let inMetadata = true;
|
|
2780
|
+
for (const rawLine of docText.split("\n")) {
|
|
2781
|
+
const line10 = rawLine.trim();
|
|
2782
|
+
if (inMetadata && /^[a-z-]+\s*:/i.test(line10)) continue;
|
|
2783
|
+
inMetadata = false;
|
|
2784
|
+
if (line10.length === 0 || /^\s/.test(rawLine)) continue;
|
|
2785
|
+
const m = NODE_ID_RE.exec(line10);
|
|
2786
|
+
if (m && !entities.includes(m[1])) entities.push(m[1]);
|
|
2787
|
+
}
|
|
2788
|
+
return { kind: "flowchart", entities, keywords: [] };
|
|
2789
|
+
}
|
|
2790
|
+
var LEGACY_GROUP_RE, NODE_ID_RE;
|
|
2778
2791
|
var init_flowchart_parser = __esm({
|
|
2779
2792
|
"src/graph/flowchart-parser.ts"() {
|
|
2780
2793
|
"use strict";
|
|
@@ -2782,6 +2795,7 @@ var init_flowchart_parser = __esm({
|
|
|
2782
2795
|
init_diagnostics();
|
|
2783
2796
|
init_parsing();
|
|
2784
2797
|
LEGACY_GROUP_RE = /^##\s+/;
|
|
2798
|
+
NODE_ID_RE = /^([a-zA-Z_][\w-]*)[\s([</{]/;
|
|
2785
2799
|
}
|
|
2786
2800
|
});
|
|
2787
2801
|
|
|
@@ -3057,6 +3071,7 @@ var init_state_parser = __esm({
|
|
|
3057
3071
|
// src/class/parser.ts
|
|
3058
3072
|
var parser_exports2 = {};
|
|
3059
3073
|
__export(parser_exports2, {
|
|
3074
|
+
extractSymbols: () => extractSymbols2,
|
|
3060
3075
|
looksLikeClassDiagram: () => looksLikeClassDiagram,
|
|
3061
3076
|
parseClassDiagram: () => parseClassDiagram
|
|
3062
3077
|
});
|
|
@@ -3304,6 +3319,23 @@ function looksLikeClassDiagram(content) {
|
|
|
3304
3319
|
if (hasRelationship && hasClassDecl && hasIndentedMember) return true;
|
|
3305
3320
|
return false;
|
|
3306
3321
|
}
|
|
3322
|
+
function extractSymbols2(docText) {
|
|
3323
|
+
const entities = [];
|
|
3324
|
+
let inMetadata = true;
|
|
3325
|
+
for (const rawLine of docText.split("\n")) {
|
|
3326
|
+
const line10 = rawLine.trim();
|
|
3327
|
+
if (inMetadata && /^[a-z-]+\s*:/i.test(line10)) continue;
|
|
3328
|
+
inMetadata = false;
|
|
3329
|
+
if (line10.length === 0 || /^\s/.test(rawLine)) continue;
|
|
3330
|
+
const m = CLASS_DECL_RE.exec(line10);
|
|
3331
|
+
if (m && !entities.includes(m[1])) entities.push(m[1]);
|
|
3332
|
+
}
|
|
3333
|
+
return {
|
|
3334
|
+
kind: "class",
|
|
3335
|
+
entities,
|
|
3336
|
+
keywords: ["extends", "implements", "abstract", "interface", "enum"]
|
|
3337
|
+
};
|
|
3338
|
+
}
|
|
3307
3339
|
var CLASS_DECL_RE, REL_ARROW_RE, VISIBILITY_RE, STATIC_SUFFIX_RE, METHOD_RE, FIELD_RE, ARROW_TO_TYPE;
|
|
3308
3340
|
var init_parser2 = __esm({
|
|
3309
3341
|
"src/class/parser.ts"() {
|
|
@@ -3331,6 +3363,7 @@ var init_parser2 = __esm({
|
|
|
3331
3363
|
// src/er/parser.ts
|
|
3332
3364
|
var parser_exports3 = {};
|
|
3333
3365
|
__export(parser_exports3, {
|
|
3366
|
+
extractSymbols: () => extractSymbols3,
|
|
3334
3367
|
looksLikeERDiagram: () => looksLikeERDiagram,
|
|
3335
3368
|
parseERDiagram: () => parseERDiagram
|
|
3336
3369
|
});
|
|
@@ -3633,6 +3666,25 @@ function looksLikeERDiagram(content) {
|
|
|
3633
3666
|
if (hasRelationship && hasTableDecl) return true;
|
|
3634
3667
|
return false;
|
|
3635
3668
|
}
|
|
3669
|
+
function extractSymbols3(docText) {
|
|
3670
|
+
const entities = [];
|
|
3671
|
+
let inMetadata = true;
|
|
3672
|
+
for (const rawLine of docText.split("\n")) {
|
|
3673
|
+
const line10 = rawLine.trim();
|
|
3674
|
+
if (inMetadata && /^chart\s*:/i.test(line10)) continue;
|
|
3675
|
+
if (inMetadata && /^[a-z-]+\s*:/i.test(line10)) continue;
|
|
3676
|
+
inMetadata = false;
|
|
3677
|
+
if (line10.length === 0) continue;
|
|
3678
|
+
if (/^\s/.test(rawLine)) continue;
|
|
3679
|
+
const m = TABLE_DECL_RE.exec(line10);
|
|
3680
|
+
if (m) entities.push(m[1]);
|
|
3681
|
+
}
|
|
3682
|
+
return {
|
|
3683
|
+
kind: "er",
|
|
3684
|
+
entities,
|
|
3685
|
+
keywords: ["pk", "fk", "unique", "nullable", "1", "*", "?"]
|
|
3686
|
+
};
|
|
3687
|
+
}
|
|
3636
3688
|
var TABLE_DECL_RE, COLUMN_RE, INDENT_REL_RE, CONSTRAINT_MAP, REL_SYMBOLIC_RE, REL_KEYWORD_RE, KEYWORD_TO_SYMBOL;
|
|
3637
3689
|
var init_parser3 = __esm({
|
|
3638
3690
|
"src/er/parser.ts"() {
|
|
@@ -4115,10 +4167,12 @@ function buildExtendedChartOption(parsed, palette, isDark) {
|
|
|
4115
4167
|
);
|
|
4116
4168
|
}
|
|
4117
4169
|
if (parsed.type === "chord") {
|
|
4170
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
4118
4171
|
return buildChordOption(
|
|
4119
4172
|
parsed,
|
|
4120
4173
|
textColor,
|
|
4121
4174
|
colors,
|
|
4175
|
+
bg,
|
|
4122
4176
|
titleConfig,
|
|
4123
4177
|
tooltipTheme
|
|
4124
4178
|
);
|
|
@@ -4136,6 +4190,7 @@ function buildExtendedChartOption(parsed, palette, isDark) {
|
|
|
4136
4190
|
);
|
|
4137
4191
|
}
|
|
4138
4192
|
if (parsed.type === "scatter") {
|
|
4193
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
4139
4194
|
return buildScatterOption(
|
|
4140
4195
|
parsed,
|
|
4141
4196
|
palette,
|
|
@@ -4143,15 +4198,18 @@ function buildExtendedChartOption(parsed, palette, isDark) {
|
|
|
4143
4198
|
axisLineColor,
|
|
4144
4199
|
gridOpacity,
|
|
4145
4200
|
colors,
|
|
4201
|
+
bg,
|
|
4146
4202
|
titleConfig,
|
|
4147
4203
|
tooltipTheme
|
|
4148
4204
|
);
|
|
4149
4205
|
}
|
|
4150
4206
|
if (parsed.type === "funnel") {
|
|
4207
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
4151
4208
|
return buildFunnelOption(
|
|
4152
4209
|
parsed,
|
|
4153
4210
|
textColor,
|
|
4154
4211
|
colors,
|
|
4212
|
+
bg,
|
|
4155
4213
|
titleConfig,
|
|
4156
4214
|
tooltipTheme
|
|
4157
4215
|
);
|
|
@@ -4159,6 +4217,7 @@ function buildExtendedChartOption(parsed, palette, isDark) {
|
|
|
4159
4217
|
return buildHeatmapOption(
|
|
4160
4218
|
parsed,
|
|
4161
4219
|
palette,
|
|
4220
|
+
isDark,
|
|
4162
4221
|
textColor,
|
|
4163
4222
|
axisLineColor,
|
|
4164
4223
|
titleConfig,
|
|
@@ -4215,7 +4274,7 @@ function buildSankeyOption(parsed, textColor, colors, titleConfig, tooltipTheme)
|
|
|
4215
4274
|
]
|
|
4216
4275
|
};
|
|
4217
4276
|
}
|
|
4218
|
-
function buildChordOption(parsed, textColor, colors, titleConfig, tooltipTheme) {
|
|
4277
|
+
function buildChordOption(parsed, textColor, colors, bg, titleConfig, tooltipTheme) {
|
|
4219
4278
|
const nodeSet = /* @__PURE__ */ new Set();
|
|
4220
4279
|
if (parsed.links) {
|
|
4221
4280
|
for (const link of parsed.links) {
|
|
@@ -4235,12 +4294,13 @@ function buildChordOption(parsed, textColor, colors, titleConfig, tooltipTheme)
|
|
|
4235
4294
|
}
|
|
4236
4295
|
}
|
|
4237
4296
|
}
|
|
4238
|
-
const categories = nodeNames.map((name, index) =>
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4297
|
+
const categories = nodeNames.map((name, index) => {
|
|
4298
|
+
const stroke2 = colors[index % colors.length];
|
|
4299
|
+
return {
|
|
4300
|
+
name,
|
|
4301
|
+
itemStyle: { color: mix(stroke2, bg, 30), borderColor: stroke2, borderWidth: CHART_BORDER_WIDTH }
|
|
4302
|
+
};
|
|
4303
|
+
});
|
|
4244
4304
|
return {
|
|
4245
4305
|
...CHART_BASE,
|
|
4246
4306
|
title: titleConfig,
|
|
@@ -4408,7 +4468,7 @@ function buildFunctionOption(parsed, palette, textColor, axisLineColor, gridOpac
|
|
|
4408
4468
|
series
|
|
4409
4469
|
};
|
|
4410
4470
|
}
|
|
4411
|
-
function buildScatterOption(parsed, palette, textColor, axisLineColor, gridOpacity, colors, titleConfig, tooltipTheme) {
|
|
4471
|
+
function buildScatterOption(parsed, palette, textColor, axisLineColor, gridOpacity, colors, bg, titleConfig, tooltipTheme) {
|
|
4412
4472
|
const points = parsed.scatterPoints ?? [];
|
|
4413
4473
|
const defaultSize = 15;
|
|
4414
4474
|
const hasCategories = points.some((p) => p.category !== void 0);
|
|
@@ -4440,27 +4500,30 @@ function buildScatterOption(parsed, palette, textColor, axisLineColor, gridOpaci
|
|
|
4440
4500
|
const data = categoryPoints.map((p) => ({
|
|
4441
4501
|
name: p.name,
|
|
4442
4502
|
value: hasSize ? [p.x, p.y, p.size ?? 0] : [p.x, p.y],
|
|
4443
|
-
...p.color && {
|
|
4503
|
+
...p.color && {
|
|
4504
|
+
itemStyle: { color: mix(p.color, bg, 30), borderColor: p.color, borderWidth: CHART_BORDER_WIDTH }
|
|
4505
|
+
}
|
|
4444
4506
|
}));
|
|
4445
4507
|
return {
|
|
4446
4508
|
name: category,
|
|
4447
4509
|
type: "scatter",
|
|
4448
4510
|
data,
|
|
4449
4511
|
...hasSize ? { symbolSize: (val) => val[2] } : { symbolSize: defaultSize },
|
|
4450
|
-
itemStyle: { color: catColor },
|
|
4512
|
+
itemStyle: { color: mix(catColor, bg, 30), borderColor: catColor, borderWidth: CHART_BORDER_WIDTH },
|
|
4451
4513
|
label: labelConfig,
|
|
4452
4514
|
emphasis: emphasisConfig
|
|
4453
4515
|
};
|
|
4454
4516
|
});
|
|
4455
4517
|
} else {
|
|
4456
|
-
const data = points.map((p, index) =>
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4518
|
+
const data = points.map((p, index) => {
|
|
4519
|
+
const stroke2 = p.color ?? colors[index % colors.length];
|
|
4520
|
+
return {
|
|
4521
|
+
name: p.name,
|
|
4522
|
+
value: hasSize ? [p.x, p.y, p.size ?? 0] : [p.x, p.y],
|
|
4523
|
+
...hasSize ? { symbolSize: p.size ?? defaultSize } : { symbolSize: defaultSize },
|
|
4524
|
+
itemStyle: { color: mix(stroke2, bg, 30), borderColor: stroke2, borderWidth: CHART_BORDER_WIDTH }
|
|
4525
|
+
};
|
|
4526
|
+
});
|
|
4464
4527
|
series = [
|
|
4465
4528
|
{
|
|
4466
4529
|
type: "scatter",
|
|
@@ -4563,7 +4626,8 @@ function buildScatterOption(parsed, palette, textColor, axisLineColor, gridOpaci
|
|
|
4563
4626
|
series
|
|
4564
4627
|
};
|
|
4565
4628
|
}
|
|
4566
|
-
function buildHeatmapOption(parsed, palette, textColor, axisLineColor, titleConfig, tooltipTheme) {
|
|
4629
|
+
function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, titleConfig, tooltipTheme) {
|
|
4630
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
4567
4631
|
const heatmapRows = parsed.heatmapRows ?? [];
|
|
4568
4632
|
const columns = parsed.columns ?? [];
|
|
4569
4633
|
const rowLabels = heatmapRows.map((r) => r.label);
|
|
@@ -4634,10 +4698,10 @@ function buildHeatmapOption(parsed, palette, textColor, axisLineColor, titleConf
|
|
|
4634
4698
|
top: "center",
|
|
4635
4699
|
inRange: {
|
|
4636
4700
|
color: [
|
|
4637
|
-
palette.primary,
|
|
4638
|
-
palette.colors.cyan,
|
|
4639
|
-
palette.colors.yellow,
|
|
4640
|
-
palette.colors.orange
|
|
4701
|
+
mix(palette.primary, bg, 30),
|
|
4702
|
+
mix(palette.colors.cyan, bg, 30),
|
|
4703
|
+
mix(palette.colors.yellow, bg, 30),
|
|
4704
|
+
mix(palette.colors.orange, bg, 30)
|
|
4641
4705
|
]
|
|
4642
4706
|
},
|
|
4643
4707
|
textStyle: {
|
|
@@ -4648,9 +4712,13 @@ function buildHeatmapOption(parsed, palette, textColor, axisLineColor, titleConf
|
|
|
4648
4712
|
{
|
|
4649
4713
|
type: "heatmap",
|
|
4650
4714
|
data,
|
|
4715
|
+
itemStyle: {
|
|
4716
|
+
borderWidth: 2,
|
|
4717
|
+
borderColor: bg
|
|
4718
|
+
},
|
|
4651
4719
|
label: {
|
|
4652
4720
|
show: true,
|
|
4653
|
-
color:
|
|
4721
|
+
color: textColor,
|
|
4654
4722
|
fontSize: 14,
|
|
4655
4723
|
fontWeight: "bold"
|
|
4656
4724
|
},
|
|
@@ -4665,17 +4733,21 @@ function buildHeatmapOption(parsed, palette, textColor, axisLineColor, titleConf
|
|
|
4665
4733
|
]
|
|
4666
4734
|
};
|
|
4667
4735
|
}
|
|
4668
|
-
function buildFunnelOption(parsed, textColor, colors, titleConfig, tooltipTheme) {
|
|
4736
|
+
function buildFunnelOption(parsed, textColor, colors, bg, titleConfig, tooltipTheme) {
|
|
4669
4737
|
const sorted = [...parsed.data].sort((a, b) => b.value - a.value);
|
|
4670
4738
|
const topValue = sorted.length > 0 ? sorted[0].value : 1;
|
|
4671
|
-
const data = sorted.map((d) =>
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4739
|
+
const data = sorted.map((d) => {
|
|
4740
|
+
const stroke2 = d.color ?? colors[parsed.data.indexOf(d) % colors.length];
|
|
4741
|
+
return {
|
|
4742
|
+
name: d.label,
|
|
4743
|
+
value: d.value,
|
|
4744
|
+
itemStyle: {
|
|
4745
|
+
color: mix(stroke2, bg, 30),
|
|
4746
|
+
borderColor: stroke2,
|
|
4747
|
+
borderWidth: CHART_BORDER_WIDTH
|
|
4748
|
+
}
|
|
4749
|
+
};
|
|
4750
|
+
});
|
|
4679
4751
|
const prevValueMap = /* @__PURE__ */ new Map();
|
|
4680
4752
|
for (let i = 0; i < sorted.length; i++) {
|
|
4681
4753
|
prevValueMap.set(
|
|
@@ -4821,23 +4893,24 @@ function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacit
|
|
|
4821
4893
|
function buildSimpleChartOption(parsed, palette, isDark, chartWidth) {
|
|
4822
4894
|
if (parsed.error) return {};
|
|
4823
4895
|
const { textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme } = buildChartCommons(parsed, palette, isDark);
|
|
4896
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
4824
4897
|
switch (parsed.type) {
|
|
4825
4898
|
case "bar":
|
|
4826
|
-
return buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth);
|
|
4899
|
+
return buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, tooltipTheme, chartWidth);
|
|
4827
4900
|
case "bar-stacked":
|
|
4828
|
-
return buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth);
|
|
4901
|
+
return buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, tooltipTheme, chartWidth);
|
|
4829
4902
|
case "line":
|
|
4830
4903
|
return parsed.seriesNames ? buildMultiLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) : buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
|
|
4831
4904
|
case "area":
|
|
4832
4905
|
return buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
|
|
4833
4906
|
case "pie":
|
|
4834
|
-
return buildPieOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), titleConfig, tooltipTheme, false);
|
|
4907
|
+
return buildPieOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), bg, titleConfig, tooltipTheme, false);
|
|
4835
4908
|
case "doughnut":
|
|
4836
|
-
return buildPieOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), titleConfig, tooltipTheme, true);
|
|
4909
|
+
return buildPieOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), bg, titleConfig, tooltipTheme, true);
|
|
4837
4910
|
case "radar":
|
|
4838
|
-
return buildRadarOption(parsed, palette, textColor, gridOpacity,
|
|
4911
|
+
return buildRadarOption(parsed, palette, isDark, textColor, gridOpacity, titleConfig, tooltipTheme);
|
|
4839
4912
|
case "polar-area":
|
|
4840
|
-
return buildPolarAreaOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), titleConfig, tooltipTheme);
|
|
4913
|
+
return buildPolarAreaOption(parsed, textColor, getSegmentColors(palette, parsed.data.length), bg, titleConfig, tooltipTheme);
|
|
4841
4914
|
}
|
|
4842
4915
|
}
|
|
4843
4916
|
function makeChartGrid(options) {
|
|
@@ -4849,14 +4922,17 @@ function makeChartGrid(options) {
|
|
|
4849
4922
|
containLabel: true
|
|
4850
4923
|
};
|
|
4851
4924
|
}
|
|
4852
|
-
function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
|
|
4925
|
+
function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, tooltipTheme, chartWidth) {
|
|
4853
4926
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
4854
4927
|
const isHorizontal = parsed.orientation === "horizontal";
|
|
4855
4928
|
const labels = parsed.data.map((d) => d.label);
|
|
4856
|
-
const data = parsed.data.map((d, i) =>
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4929
|
+
const data = parsed.data.map((d, i) => {
|
|
4930
|
+
const stroke2 = d.color ?? colors[i % colors.length];
|
|
4931
|
+
return {
|
|
4932
|
+
value: d.value,
|
|
4933
|
+
itemStyle: { color: mix(stroke2, bg, 30), borderColor: stroke2, borderWidth: CHART_BORDER_WIDTH }
|
|
4934
|
+
};
|
|
4935
|
+
});
|
|
4860
4936
|
const hCatGap = isHorizontal && yLabel ? Math.max(40, Math.max(...labels.map((l) => l.length)) * 8 + 16) : void 0;
|
|
4861
4937
|
const categoryAxis = makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? yLabel : xLabel, labels, hCatGap, !isHorizontal ? chartWidth : void 0);
|
|
4862
4938
|
const valueAxis = makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, isHorizontal ? xLabel : yLabel);
|
|
@@ -5037,12 +5113,15 @@ function segmentLabelFormatter(mode) {
|
|
|
5037
5113
|
return "{b} \u2014 {c} ({d}%)";
|
|
5038
5114
|
}
|
|
5039
5115
|
}
|
|
5040
|
-
function buildPieOption(parsed, textColor, colors, titleConfig, tooltipTheme, isDoughnut) {
|
|
5041
|
-
const data = parsed.data.map((d, i) =>
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5116
|
+
function buildPieOption(parsed, textColor, colors, bg, titleConfig, tooltipTheme, isDoughnut) {
|
|
5117
|
+
const data = parsed.data.map((d, i) => {
|
|
5118
|
+
const stroke2 = d.color ?? colors[i % colors.length];
|
|
5119
|
+
return {
|
|
5120
|
+
name: d.label,
|
|
5121
|
+
value: d.value,
|
|
5122
|
+
itemStyle: { color: mix(stroke2, bg, 30), borderColor: stroke2, borderWidth: CHART_BORDER_WIDTH }
|
|
5123
|
+
};
|
|
5124
|
+
});
|
|
5046
5125
|
return {
|
|
5047
5126
|
...CHART_BASE,
|
|
5048
5127
|
title: titleConfig,
|
|
@@ -5067,7 +5146,8 @@ function buildPieOption(parsed, textColor, colors, titleConfig, tooltipTheme, is
|
|
|
5067
5146
|
]
|
|
5068
5147
|
};
|
|
5069
5148
|
}
|
|
5070
|
-
function buildRadarOption(parsed, palette, textColor, gridOpacity,
|
|
5149
|
+
function buildRadarOption(parsed, palette, isDark, textColor, gridOpacity, titleConfig, tooltipTheme) {
|
|
5150
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
5071
5151
|
const radarColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
|
|
5072
5152
|
const values = parsed.data.map((d) => d.value);
|
|
5073
5153
|
const maxValue = Math.max(...values) * 1.15;
|
|
@@ -5104,7 +5184,7 @@ function buildRadarOption(parsed, palette, textColor, gridOpacity, colors, title
|
|
|
5104
5184
|
{
|
|
5105
5185
|
value: values,
|
|
5106
5186
|
name: parsed.series ?? "Value",
|
|
5107
|
-
areaStyle: { color: radarColor,
|
|
5187
|
+
areaStyle: { color: mix(radarColor, bg, 30) },
|
|
5108
5188
|
lineStyle: { color: radarColor },
|
|
5109
5189
|
itemStyle: { color: radarColor },
|
|
5110
5190
|
symbol: "circle",
|
|
@@ -5123,12 +5203,15 @@ function buildRadarOption(parsed, palette, textColor, gridOpacity, colors, title
|
|
|
5123
5203
|
]
|
|
5124
5204
|
};
|
|
5125
5205
|
}
|
|
5126
|
-
function buildPolarAreaOption(parsed, textColor, colors, titleConfig, tooltipTheme) {
|
|
5127
|
-
const data = parsed.data.map((d, i) =>
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5206
|
+
function buildPolarAreaOption(parsed, textColor, colors, bg, titleConfig, tooltipTheme) {
|
|
5207
|
+
const data = parsed.data.map((d, i) => {
|
|
5208
|
+
const stroke2 = d.color ?? colors[i % colors.length];
|
|
5209
|
+
return {
|
|
5210
|
+
name: d.label,
|
|
5211
|
+
value: d.value,
|
|
5212
|
+
itemStyle: { color: mix(stroke2, bg, 30), borderColor: stroke2, borderWidth: CHART_BORDER_WIDTH }
|
|
5213
|
+
};
|
|
5214
|
+
});
|
|
5132
5215
|
return {
|
|
5133
5216
|
...CHART_BASE,
|
|
5134
5217
|
title: titleConfig,
|
|
@@ -5154,7 +5237,7 @@ function buildPolarAreaOption(parsed, textColor, colors, titleConfig, tooltipThe
|
|
|
5154
5237
|
]
|
|
5155
5238
|
};
|
|
5156
5239
|
}
|
|
5157
|
-
function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
|
|
5240
|
+
function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, tooltipTheme, chartWidth) {
|
|
5158
5241
|
const { xLabel, yLabel } = resolveAxisLabels(parsed);
|
|
5159
5242
|
const isHorizontal = parsed.orientation === "horizontal";
|
|
5160
5243
|
const seriesNames = parsed.seriesNames ?? [];
|
|
@@ -5169,12 +5252,12 @@ function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor,
|
|
|
5169
5252
|
type: "bar",
|
|
5170
5253
|
stack: "total",
|
|
5171
5254
|
data,
|
|
5172
|
-
itemStyle: { color },
|
|
5255
|
+
itemStyle: { color: mix(color, bg, 30), borderColor: color, borderWidth: CHART_BORDER_WIDTH },
|
|
5173
5256
|
label: {
|
|
5174
5257
|
show: true,
|
|
5175
5258
|
position: "inside",
|
|
5176
5259
|
formatter: "{c}",
|
|
5177
|
-
color:
|
|
5260
|
+
color: textColor,
|
|
5178
5261
|
fontSize: 14,
|
|
5179
5262
|
fontWeight: "bold",
|
|
5180
5263
|
fontFamily: FONT_FAMILY
|
|
@@ -5246,19 +5329,21 @@ async function renderExtendedChartForExport(content, theme, palette, options) {
|
|
|
5246
5329
|
chart.dispose();
|
|
5247
5330
|
}
|
|
5248
5331
|
}
|
|
5249
|
-
var EMPHASIS_SELF, CHART_BASE, ECHART_EXPORT_WIDTH, ECHART_EXPORT_HEIGHT, STANDARD_CHART_TYPES;
|
|
5332
|
+
var EMPHASIS_SELF, CHART_BASE, CHART_BORDER_WIDTH, ECHART_EXPORT_WIDTH, ECHART_EXPORT_HEIGHT, STANDARD_CHART_TYPES;
|
|
5250
5333
|
var init_echarts = __esm({
|
|
5251
5334
|
"src/echarts.ts"() {
|
|
5252
5335
|
"use strict";
|
|
5253
5336
|
init_fonts();
|
|
5254
5337
|
init_branding();
|
|
5255
5338
|
init_palettes();
|
|
5339
|
+
init_color_utils();
|
|
5256
5340
|
init_chart();
|
|
5257
5341
|
init_diagnostics();
|
|
5258
5342
|
init_colors();
|
|
5259
5343
|
init_parsing();
|
|
5260
5344
|
EMPHASIS_SELF = { focus: "self", blurScope: "global" };
|
|
5261
5345
|
CHART_BASE = { backgroundColor: "transparent", animation: false };
|
|
5346
|
+
CHART_BORDER_WIDTH = 2;
|
|
5262
5347
|
ECHART_EXPORT_WIDTH = 1200;
|
|
5263
5348
|
ECHART_EXPORT_HEIGHT = 800;
|
|
5264
5349
|
STANDARD_CHART_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -6973,6 +7058,7 @@ var init_types2 = __esm({
|
|
|
6973
7058
|
// src/infra/parser.ts
|
|
6974
7059
|
var parser_exports9 = {};
|
|
6975
7060
|
__export(parser_exports9, {
|
|
7061
|
+
extractSymbols: () => extractSymbols4,
|
|
6976
7062
|
parseInfra: () => parseInfra
|
|
6977
7063
|
});
|
|
6978
7064
|
function nodeId2(name) {
|
|
@@ -7015,7 +7101,6 @@ function parseInfra(content) {
|
|
|
7015
7101
|
error: null
|
|
7016
7102
|
};
|
|
7017
7103
|
const nodeMap = /* @__PURE__ */ new Map();
|
|
7018
|
-
const edgeNodeId = "edge";
|
|
7019
7104
|
const setError = (line10, message) => {
|
|
7020
7105
|
const diag = makeDgmoError(line10, message);
|
|
7021
7106
|
result.diagnostics.push(diag);
|
|
@@ -7381,6 +7466,38 @@ function parseInfra(content) {
|
|
|
7381
7466
|
}
|
|
7382
7467
|
return result;
|
|
7383
7468
|
}
|
|
7469
|
+
function extractSymbols4(docText) {
|
|
7470
|
+
const entities = [];
|
|
7471
|
+
let inMetadata = true;
|
|
7472
|
+
let inTagGroup = false;
|
|
7473
|
+
for (const rawLine of docText.split("\n")) {
|
|
7474
|
+
const line10 = rawLine.trim();
|
|
7475
|
+
if (line10.length === 0) continue;
|
|
7476
|
+
const indented = /^\s/.test(rawLine);
|
|
7477
|
+
if (inMetadata) {
|
|
7478
|
+
if (!indented && !/^[a-z-]+\s*:/i.test(line10)) inMetadata = false;
|
|
7479
|
+
else continue;
|
|
7480
|
+
}
|
|
7481
|
+
if (!indented) {
|
|
7482
|
+
if (/^tag\s*:/i.test(line10)) {
|
|
7483
|
+
inTagGroup = true;
|
|
7484
|
+
continue;
|
|
7485
|
+
}
|
|
7486
|
+
inTagGroup = false;
|
|
7487
|
+
if (/^\[/.test(line10)) continue;
|
|
7488
|
+
const m = COMPONENT_RE.exec(line10);
|
|
7489
|
+
if (m && !entities.includes(m[1])) entities.push(m[1]);
|
|
7490
|
+
} else {
|
|
7491
|
+
if (inTagGroup) continue;
|
|
7492
|
+
if (/^->/.test(line10)) continue;
|
|
7493
|
+
if (/^-[^>]+-?>/.test(line10)) continue;
|
|
7494
|
+
if (/^\w[\w-]*\s*:/.test(line10)) continue;
|
|
7495
|
+
const m = COMPONENT_RE.exec(line10);
|
|
7496
|
+
if (m && !entities.includes(m[1])) entities.push(m[1]);
|
|
7497
|
+
}
|
|
7498
|
+
}
|
|
7499
|
+
return { kind: "infra", entities, keywords: [] };
|
|
7500
|
+
}
|
|
7384
7501
|
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;
|
|
7385
7502
|
var init_parser9 = __esm({
|
|
7386
7503
|
"src/infra/parser.ts"() {
|
|
@@ -8244,7 +8361,6 @@ function layoutOrg(parsed, hiddenCounts, activeTagGroup, hiddenAttributes, expan
|
|
|
8244
8361
|
const visibleGroups = activeTagGroup != null ? legendGroups.filter((g) => g.name.toLowerCase() === activeTagGroup.toLowerCase()) : legendGroups;
|
|
8245
8362
|
const allExpanded = expandAllLegend && activeTagGroup == null;
|
|
8246
8363
|
const effectiveW = (g) => activeTagGroup != null || allExpanded ? g.width : g.minifiedWidth;
|
|
8247
|
-
const effectiveH = (g) => activeTagGroup != null || allExpanded ? g.height : g.minifiedHeight;
|
|
8248
8364
|
if (visibleGroups.length > 0) {
|
|
8249
8365
|
if (legendPosition === "bottom") {
|
|
8250
8366
|
const totalGroupsWidth = visibleGroups.reduce((s, g) => s + effectiveW(g), 0) + (visibleGroups.length - 1) * LEGEND_GROUP_GAP2;
|
|
@@ -8397,6 +8513,35 @@ var init_collapse = __esm({
|
|
|
8397
8513
|
}
|
|
8398
8514
|
});
|
|
8399
8515
|
|
|
8516
|
+
// src/utils/export-container.ts
|
|
8517
|
+
function runInExportContainer(width, height, fn) {
|
|
8518
|
+
const container = document.createElement("div");
|
|
8519
|
+
container.style.width = `${width}px`;
|
|
8520
|
+
container.style.height = `${height}px`;
|
|
8521
|
+
container.style.position = "absolute";
|
|
8522
|
+
container.style.left = "-9999px";
|
|
8523
|
+
document.body.appendChild(container);
|
|
8524
|
+
try {
|
|
8525
|
+
return fn(container);
|
|
8526
|
+
} finally {
|
|
8527
|
+
document.body.removeChild(container);
|
|
8528
|
+
}
|
|
8529
|
+
}
|
|
8530
|
+
function extractExportSvg(container, theme) {
|
|
8531
|
+
const svgEl = container.querySelector("svg");
|
|
8532
|
+
if (!svgEl) return "";
|
|
8533
|
+
if (theme === "transparent") svgEl.style.background = "none";
|
|
8534
|
+
svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
8535
|
+
svgEl.style.fontFamily = FONT_FAMILY;
|
|
8536
|
+
return svgEl.outerHTML;
|
|
8537
|
+
}
|
|
8538
|
+
var init_export_container = __esm({
|
|
8539
|
+
"src/utils/export-container.ts"() {
|
|
8540
|
+
"use strict";
|
|
8541
|
+
init_fonts();
|
|
8542
|
+
}
|
|
8543
|
+
});
|
|
8544
|
+
|
|
8400
8545
|
// src/org/renderer.ts
|
|
8401
8546
|
var renderer_exports = {};
|
|
8402
8547
|
__export(renderer_exports, {
|
|
@@ -8652,37 +8797,23 @@ function renderOrgForExport(content, theme, palette) {
|
|
|
8652
8797
|
const exportHidden = hideOption ? new Set(hideOption.split(",").map((s) => s.trim().toLowerCase())) : void 0;
|
|
8653
8798
|
const layout = layoutOrg(parsed, void 0, void 0, exportHidden);
|
|
8654
8799
|
const isDark = theme === "dark";
|
|
8655
|
-
const container = document.createElement("div");
|
|
8656
8800
|
const titleOffset = parsed.title ? TITLE_HEIGHT : 0;
|
|
8657
8801
|
const exportWidth = layout.width + DIAGRAM_PADDING * 2;
|
|
8658
8802
|
const exportHeight = layout.height + DIAGRAM_PADDING * 2 + titleOffset;
|
|
8659
|
-
container
|
|
8660
|
-
container.style.height = `${exportHeight}px`;
|
|
8661
|
-
container.style.position = "absolute";
|
|
8662
|
-
container.style.left = "-9999px";
|
|
8663
|
-
document.body.appendChild(container);
|
|
8664
|
-
try {
|
|
8803
|
+
return runInExportContainer(exportWidth, exportHeight, (container) => {
|
|
8665
8804
|
renderOrg(container, parsed, layout, palette, isDark, void 0, {
|
|
8666
8805
|
width: exportWidth,
|
|
8667
8806
|
height: exportHeight
|
|
8668
8807
|
});
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
if (theme === "transparent") {
|
|
8672
|
-
svgEl.style.background = "none";
|
|
8673
|
-
}
|
|
8674
|
-
svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
8675
|
-
svgEl.style.fontFamily = FONT_FAMILY;
|
|
8676
|
-
return svgEl.outerHTML;
|
|
8677
|
-
} finally {
|
|
8678
|
-
document.body.removeChild(container);
|
|
8679
|
-
}
|
|
8808
|
+
return extractExportSvg(container, theme);
|
|
8809
|
+
});
|
|
8680
8810
|
}
|
|
8681
8811
|
var 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;
|
|
8682
8812
|
var init_renderer = __esm({
|
|
8683
8813
|
"src/org/renderer.ts"() {
|
|
8684
8814
|
"use strict";
|
|
8685
8815
|
init_fonts();
|
|
8816
|
+
init_export_container();
|
|
8686
8817
|
init_color_utils();
|
|
8687
8818
|
init_parser4();
|
|
8688
8819
|
init_layout();
|
|
@@ -10270,7 +10401,6 @@ function renderClassDiagram(container, parsed, layout, palette, isDark, onClickI
|
|
|
10270
10401
|
const scaleY = (availH - DIAGRAM_PADDING4 * 2) / diagramH;
|
|
10271
10402
|
const scale = Math.min(MAX_SCALE3, scaleX, scaleY);
|
|
10272
10403
|
const scaledW = diagramW * scale;
|
|
10273
|
-
const scaledH = diagramH * scale;
|
|
10274
10404
|
const offsetX = (width - scaledW) / 2;
|
|
10275
10405
|
const offsetY = titleHeight + DIAGRAM_PADDING4;
|
|
10276
10406
|
const svg = d3Selection4.select(container).append("svg").attr("width", width).attr("height", height).style("font-family", FONT_FAMILY);
|
|
@@ -10401,15 +10531,9 @@ function renderClassDiagramForExport(content, theme, palette) {
|
|
|
10401
10531
|
if (parsed.error || parsed.classes.length === 0) return "";
|
|
10402
10532
|
const layout = layoutClassDiagram(parsed);
|
|
10403
10533
|
const isDark = theme === "dark";
|
|
10404
|
-
const container = document.createElement("div");
|
|
10405
10534
|
const exportWidth = layout.width + DIAGRAM_PADDING4 * 2;
|
|
10406
10535
|
const exportHeight = layout.height + DIAGRAM_PADDING4 * 2 + (parsed.title ? 40 : 0);
|
|
10407
|
-
container
|
|
10408
|
-
container.style.height = `${exportHeight}px`;
|
|
10409
|
-
container.style.position = "absolute";
|
|
10410
|
-
container.style.left = "-9999px";
|
|
10411
|
-
document.body.appendChild(container);
|
|
10412
|
-
try {
|
|
10536
|
+
return runInExportContainer(exportWidth, exportHeight, (container) => {
|
|
10413
10537
|
renderClassDiagram(
|
|
10414
10538
|
container,
|
|
10415
10539
|
parsed,
|
|
@@ -10419,23 +10543,15 @@ function renderClassDiagramForExport(content, theme, palette) {
|
|
|
10419
10543
|
void 0,
|
|
10420
10544
|
{ width: exportWidth, height: exportHeight }
|
|
10421
10545
|
);
|
|
10422
|
-
|
|
10423
|
-
|
|
10424
|
-
if (theme === "transparent") {
|
|
10425
|
-
svgEl.style.background = "none";
|
|
10426
|
-
}
|
|
10427
|
-
svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
10428
|
-
svgEl.style.fontFamily = FONT_FAMILY;
|
|
10429
|
-
return svgEl.outerHTML;
|
|
10430
|
-
} finally {
|
|
10431
|
-
document.body.removeChild(container);
|
|
10432
|
-
}
|
|
10546
|
+
return extractExportSvg(container, theme);
|
|
10547
|
+
});
|
|
10433
10548
|
}
|
|
10434
10549
|
var 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;
|
|
10435
10550
|
var init_renderer4 = __esm({
|
|
10436
10551
|
"src/class/renderer.ts"() {
|
|
10437
10552
|
"use strict";
|
|
10438
10553
|
init_fonts();
|
|
10554
|
+
init_export_container();
|
|
10439
10555
|
init_color_utils();
|
|
10440
10556
|
init_parser2();
|
|
10441
10557
|
init_layout3();
|
|
@@ -10476,110 +10592,211 @@ function computeNodeDimensions2(table) {
|
|
|
10476
10592
|
const height = headerHeight + columnsHeight + (columnsHeight === 0 ? 4 : 0);
|
|
10477
10593
|
return { width, height, headerHeight, columnsHeight };
|
|
10478
10594
|
}
|
|
10595
|
+
function findConnectedComponents(tableIds, relationships) {
|
|
10596
|
+
const adj = /* @__PURE__ */ new Map();
|
|
10597
|
+
for (const id of tableIds) adj.set(id, /* @__PURE__ */ new Set());
|
|
10598
|
+
for (const rel of relationships) {
|
|
10599
|
+
adj.get(rel.source)?.add(rel.target);
|
|
10600
|
+
adj.get(rel.target)?.add(rel.source);
|
|
10601
|
+
}
|
|
10602
|
+
const visited = /* @__PURE__ */ new Set();
|
|
10603
|
+
const components = [];
|
|
10604
|
+
for (const id of tableIds) {
|
|
10605
|
+
if (visited.has(id)) continue;
|
|
10606
|
+
const comp = [];
|
|
10607
|
+
const queue = [id];
|
|
10608
|
+
while (queue.length > 0) {
|
|
10609
|
+
const cur = queue.shift();
|
|
10610
|
+
if (visited.has(cur)) continue;
|
|
10611
|
+
visited.add(cur);
|
|
10612
|
+
comp.push(cur);
|
|
10613
|
+
for (const nb of adj.get(cur) ?? []) {
|
|
10614
|
+
if (!visited.has(nb)) queue.push(nb);
|
|
10615
|
+
}
|
|
10616
|
+
}
|
|
10617
|
+
components.push(comp);
|
|
10618
|
+
}
|
|
10619
|
+
return components;
|
|
10620
|
+
}
|
|
10621
|
+
function layoutComponent(tables, rels, dimMap) {
|
|
10622
|
+
const nodePositions = /* @__PURE__ */ new Map();
|
|
10623
|
+
const edgePoints = /* @__PURE__ */ new Map();
|
|
10624
|
+
if (tables.length === 1) {
|
|
10625
|
+
const dims = dimMap.get(tables[0].id);
|
|
10626
|
+
nodePositions.set(tables[0].id, { x: dims.width / 2, y: dims.height / 2, ...dims });
|
|
10627
|
+
return { nodePositions, edgePoints, width: dims.width, height: dims.height };
|
|
10628
|
+
}
|
|
10629
|
+
const g = new dagre3.graphlib.Graph({ multigraph: true });
|
|
10630
|
+
g.setGraph({ rankdir: "LR", nodesep: 40, ranksep: 80, edgesep: 20 });
|
|
10631
|
+
g.setDefaultEdgeLabel(() => ({}));
|
|
10632
|
+
for (const table of tables) {
|
|
10633
|
+
const dims = dimMap.get(table.id);
|
|
10634
|
+
g.setNode(table.id, { width: dims.width, height: dims.height });
|
|
10635
|
+
}
|
|
10636
|
+
for (const rel of rels) {
|
|
10637
|
+
g.setEdge(rel.source, rel.target, { label: rel.label ?? "" }, String(rel.lineNumber));
|
|
10638
|
+
}
|
|
10639
|
+
dagre3.layout(g);
|
|
10640
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
10641
|
+
for (const table of tables) {
|
|
10642
|
+
const pos = g.node(table.id);
|
|
10643
|
+
const dims = dimMap.get(table.id);
|
|
10644
|
+
minX = Math.min(minX, pos.x - dims.width / 2);
|
|
10645
|
+
minY = Math.min(minY, pos.y - dims.height / 2);
|
|
10646
|
+
maxX = Math.max(maxX, pos.x + dims.width / 2);
|
|
10647
|
+
maxY = Math.max(maxY, pos.y + dims.height / 2);
|
|
10648
|
+
}
|
|
10649
|
+
for (const rel of rels) {
|
|
10650
|
+
const ed = g.edge(rel.source, rel.target, String(rel.lineNumber));
|
|
10651
|
+
for (const pt of ed?.points ?? []) {
|
|
10652
|
+
minX = Math.min(minX, pt.x);
|
|
10653
|
+
minY = Math.min(minY, pt.y);
|
|
10654
|
+
maxX = Math.max(maxX, pt.x);
|
|
10655
|
+
maxY = Math.max(maxY, pt.y);
|
|
10656
|
+
}
|
|
10657
|
+
if (rel.label && (ed?.points ?? []).length > 0) {
|
|
10658
|
+
const pts = ed.points;
|
|
10659
|
+
const mid = pts[Math.floor(pts.length / 2)];
|
|
10660
|
+
const hw = (rel.label.length * 7 + 8) / 2;
|
|
10661
|
+
minX = Math.min(minX, mid.x - hw);
|
|
10662
|
+
maxX = Math.max(maxX, mid.x + hw);
|
|
10663
|
+
}
|
|
10664
|
+
}
|
|
10665
|
+
for (const table of tables) {
|
|
10666
|
+
const pos = g.node(table.id);
|
|
10667
|
+
const dims = dimMap.get(table.id);
|
|
10668
|
+
nodePositions.set(table.id, {
|
|
10669
|
+
x: pos.x - minX,
|
|
10670
|
+
y: pos.y - minY,
|
|
10671
|
+
...dims
|
|
10672
|
+
});
|
|
10673
|
+
}
|
|
10674
|
+
for (const rel of rels) {
|
|
10675
|
+
const ed = g.edge(rel.source, rel.target, String(rel.lineNumber));
|
|
10676
|
+
edgePoints.set(
|
|
10677
|
+
rel.lineNumber,
|
|
10678
|
+
(ed?.points ?? []).map((pt) => ({ x: pt.x - minX, y: pt.y - minY }))
|
|
10679
|
+
);
|
|
10680
|
+
}
|
|
10681
|
+
return {
|
|
10682
|
+
nodePositions,
|
|
10683
|
+
edgePoints,
|
|
10684
|
+
width: Math.max(0, maxX - minX),
|
|
10685
|
+
height: Math.max(0, maxY - minY)
|
|
10686
|
+
};
|
|
10687
|
+
}
|
|
10688
|
+
function packComponents(items) {
|
|
10689
|
+
if (items.length === 0) return [];
|
|
10690
|
+
const sorted = [...items].sort((a, b) => {
|
|
10691
|
+
const aConnected = a.compIds.length > 1 ? 1 : 0;
|
|
10692
|
+
const bConnected = b.compIds.length > 1 ? 1 : 0;
|
|
10693
|
+
if (aConnected !== bConnected) return bConnected - aConnected;
|
|
10694
|
+
return b.compLayout.height - a.compLayout.height;
|
|
10695
|
+
});
|
|
10696
|
+
const totalArea = items.reduce(
|
|
10697
|
+
(s, c) => s + (c.compLayout.width || MIN_WIDTH2) * (c.compLayout.height || HEADER_BASE2),
|
|
10698
|
+
0
|
|
10699
|
+
);
|
|
10700
|
+
const targetW = Math.max(
|
|
10701
|
+
Math.sqrt(totalArea) * 1.5,
|
|
10702
|
+
sorted[0].compLayout.width
|
|
10703
|
+
// at least as wide as the widest component
|
|
10704
|
+
);
|
|
10705
|
+
const placements = [];
|
|
10706
|
+
let curX = 0;
|
|
10707
|
+
let curY = 0;
|
|
10708
|
+
let rowH = 0;
|
|
10709
|
+
for (const item of sorted) {
|
|
10710
|
+
const w = item.compLayout.width || MIN_WIDTH2;
|
|
10711
|
+
const h = item.compLayout.height || HEADER_BASE2;
|
|
10712
|
+
if (curX > 0 && curX + w > targetW) {
|
|
10713
|
+
curY += rowH + COMP_GAP;
|
|
10714
|
+
curX = 0;
|
|
10715
|
+
rowH = 0;
|
|
10716
|
+
}
|
|
10717
|
+
placements.push({ compIds: item.compIds, compLayout: item.compLayout, offsetX: curX, offsetY: curY });
|
|
10718
|
+
curX += w + COMP_GAP;
|
|
10719
|
+
rowH = Math.max(rowH, h);
|
|
10720
|
+
}
|
|
10721
|
+
return placements;
|
|
10722
|
+
}
|
|
10479
10723
|
function layoutERDiagram(parsed) {
|
|
10480
10724
|
if (parsed.tables.length === 0) {
|
|
10481
10725
|
return { nodes: [], edges: [], width: 0, height: 0 };
|
|
10482
10726
|
}
|
|
10483
|
-
const g = new dagre3.graphlib.Graph();
|
|
10484
|
-
g.setGraph({
|
|
10485
|
-
rankdir: "TB",
|
|
10486
|
-
nodesep: 60,
|
|
10487
|
-
ranksep: 80,
|
|
10488
|
-
edgesep: 20
|
|
10489
|
-
});
|
|
10490
|
-
g.setDefaultEdgeLabel(() => ({}));
|
|
10491
10727
|
const dimMap = /* @__PURE__ */ new Map();
|
|
10492
10728
|
for (const table of parsed.tables) {
|
|
10493
|
-
|
|
10494
|
-
dimMap.set(table.id, dims);
|
|
10495
|
-
g.setNode(table.id, {
|
|
10496
|
-
label: table.name,
|
|
10497
|
-
width: dims.width,
|
|
10498
|
-
height: dims.height
|
|
10499
|
-
});
|
|
10729
|
+
dimMap.set(table.id, computeNodeDimensions2(table));
|
|
10500
10730
|
}
|
|
10501
|
-
|
|
10502
|
-
|
|
10731
|
+
const compIdSets = findConnectedComponents(
|
|
10732
|
+
parsed.tables.map((t) => t.id),
|
|
10733
|
+
parsed.relationships
|
|
10734
|
+
);
|
|
10735
|
+
const tableById = new Map(parsed.tables.map((t) => [t.id, t]));
|
|
10736
|
+
const componentItems = compIdSets.map((ids) => {
|
|
10737
|
+
const tables = ids.map((id) => tableById.get(id));
|
|
10738
|
+
const rels = parsed.relationships.filter((r) => ids.includes(r.source));
|
|
10739
|
+
return { compIds: ids, compLayout: layoutComponent(tables, rels, dimMap) };
|
|
10740
|
+
});
|
|
10741
|
+
const packed = packComponents(componentItems);
|
|
10742
|
+
const placementByTableId = /* @__PURE__ */ new Map();
|
|
10743
|
+
for (const p of packed) {
|
|
10744
|
+
for (const id of p.compIds) placementByTableId.set(id, p);
|
|
10745
|
+
}
|
|
10746
|
+
const placementByRelLine = /* @__PURE__ */ new Map();
|
|
10747
|
+
for (const p of packed) {
|
|
10748
|
+
for (const lineNum of p.compLayout.edgePoints.keys()) {
|
|
10749
|
+
placementByRelLine.set(lineNum, p);
|
|
10750
|
+
}
|
|
10503
10751
|
}
|
|
10504
|
-
dagre3.layout(g);
|
|
10505
10752
|
const layoutNodes = parsed.tables.map((table) => {
|
|
10506
|
-
const
|
|
10507
|
-
const
|
|
10753
|
+
const p = placementByTableId.get(table.id);
|
|
10754
|
+
const pos = p.compLayout.nodePositions.get(table.id);
|
|
10508
10755
|
return {
|
|
10509
10756
|
...table,
|
|
10510
|
-
x: pos.x,
|
|
10511
|
-
y: pos.y,
|
|
10512
|
-
width:
|
|
10513
|
-
height:
|
|
10514
|
-
headerHeight:
|
|
10515
|
-
columnsHeight:
|
|
10757
|
+
x: pos.x + p.offsetX + HALF_MARGIN,
|
|
10758
|
+
y: pos.y + p.offsetY + HALF_MARGIN,
|
|
10759
|
+
width: pos.width,
|
|
10760
|
+
height: pos.height,
|
|
10761
|
+
headerHeight: pos.headerHeight,
|
|
10762
|
+
columnsHeight: pos.columnsHeight
|
|
10516
10763
|
};
|
|
10517
10764
|
});
|
|
10518
10765
|
const layoutEdges = parsed.relationships.map((rel) => {
|
|
10519
|
-
const
|
|
10766
|
+
const p = placementByRelLine.get(rel.lineNumber);
|
|
10767
|
+
const pts = p?.compLayout.edgePoints.get(rel.lineNumber) ?? [];
|
|
10520
10768
|
return {
|
|
10521
10769
|
source: rel.source,
|
|
10522
10770
|
target: rel.target,
|
|
10523
10771
|
cardinality: rel.cardinality,
|
|
10524
|
-
points:
|
|
10772
|
+
points: pts.map((pt) => ({
|
|
10773
|
+
x: pt.x + (p?.offsetX ?? 0) + HALF_MARGIN,
|
|
10774
|
+
y: pt.y + (p?.offsetY ?? 0) + HALF_MARGIN
|
|
10775
|
+
})),
|
|
10525
10776
|
label: rel.label,
|
|
10526
10777
|
lineNumber: rel.lineNumber
|
|
10527
10778
|
};
|
|
10528
10779
|
});
|
|
10529
|
-
let minX = Infinity;
|
|
10530
|
-
let minY = Infinity;
|
|
10531
10780
|
let maxX = 0;
|
|
10532
10781
|
let maxY = 0;
|
|
10533
10782
|
for (const node of layoutNodes) {
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
const top = node.y - node.height / 2;
|
|
10537
|
-
const bottom = node.y + node.height / 2;
|
|
10538
|
-
if (left < minX) minX = left;
|
|
10539
|
-
if (right > maxX) maxX = right;
|
|
10540
|
-
if (top < minY) minY = top;
|
|
10541
|
-
if (bottom > maxY) maxY = bottom;
|
|
10783
|
+
maxX = Math.max(maxX, node.x + node.width / 2);
|
|
10784
|
+
maxY = Math.max(maxY, node.y + node.height / 2);
|
|
10542
10785
|
}
|
|
10543
10786
|
for (const edge of layoutEdges) {
|
|
10544
10787
|
for (const pt of edge.points) {
|
|
10545
|
-
|
|
10546
|
-
|
|
10547
|
-
if (pt.y < minY) minY = pt.y;
|
|
10548
|
-
if (pt.y > maxY) maxY = pt.y;
|
|
10549
|
-
}
|
|
10550
|
-
if (edge.label && edge.points.length > 0) {
|
|
10551
|
-
const midPt = edge.points[Math.floor(edge.points.length / 2)];
|
|
10552
|
-
const labelHalfW = (edge.label.length * 7 + 8) / 2;
|
|
10553
|
-
if (midPt.x + labelHalfW > maxX) maxX = midPt.x + labelHalfW;
|
|
10554
|
-
if (midPt.x - labelHalfW < minX) minX = midPt.x - labelHalfW;
|
|
10788
|
+
maxX = Math.max(maxX, pt.x);
|
|
10789
|
+
maxY = Math.max(maxY, pt.y);
|
|
10555
10790
|
}
|
|
10556
10791
|
}
|
|
10557
|
-
const EDGE_MARGIN2 = 60;
|
|
10558
|
-
const HALF_MARGIN = EDGE_MARGIN2 / 2;
|
|
10559
|
-
const shiftX = -minX + HALF_MARGIN;
|
|
10560
|
-
const shiftY = -minY + HALF_MARGIN;
|
|
10561
|
-
for (const node of layoutNodes) {
|
|
10562
|
-
node.x += shiftX;
|
|
10563
|
-
node.y += shiftY;
|
|
10564
|
-
}
|
|
10565
|
-
for (const edge of layoutEdges) {
|
|
10566
|
-
for (const pt of edge.points) {
|
|
10567
|
-
pt.x += shiftX;
|
|
10568
|
-
pt.y += shiftY;
|
|
10569
|
-
}
|
|
10570
|
-
}
|
|
10571
|
-
maxX += shiftX;
|
|
10572
|
-
maxY += shiftY;
|
|
10573
|
-
const totalWidth = maxX + HALF_MARGIN;
|
|
10574
|
-
const totalHeight = maxY + HALF_MARGIN;
|
|
10575
10792
|
return {
|
|
10576
10793
|
nodes: layoutNodes,
|
|
10577
10794
|
edges: layoutEdges,
|
|
10578
|
-
width:
|
|
10579
|
-
height:
|
|
10795
|
+
width: maxX + HALF_MARGIN,
|
|
10796
|
+
height: maxY + HALF_MARGIN
|
|
10580
10797
|
};
|
|
10581
10798
|
}
|
|
10582
|
-
var MIN_WIDTH2, CHAR_WIDTH4, PADDING_X2, HEADER_BASE2, MEMBER_LINE_HEIGHT3, COMPARTMENT_PADDING_Y3, SEPARATOR_HEIGHT2;
|
|
10799
|
+
var MIN_WIDTH2, CHAR_WIDTH4, PADDING_X2, HEADER_BASE2, MEMBER_LINE_HEIGHT3, COMPARTMENT_PADDING_Y3, SEPARATOR_HEIGHT2, HALF_MARGIN, COMP_GAP;
|
|
10583
10800
|
var init_layout4 = __esm({
|
|
10584
10801
|
"src/er/layout.ts"() {
|
|
10585
10802
|
"use strict";
|
|
@@ -10590,6 +10807,135 @@ var init_layout4 = __esm({
|
|
|
10590
10807
|
MEMBER_LINE_HEIGHT3 = 18;
|
|
10591
10808
|
COMPARTMENT_PADDING_Y3 = 8;
|
|
10592
10809
|
SEPARATOR_HEIGHT2 = 1;
|
|
10810
|
+
HALF_MARGIN = 30;
|
|
10811
|
+
COMP_GAP = 60;
|
|
10812
|
+
}
|
|
10813
|
+
});
|
|
10814
|
+
|
|
10815
|
+
// src/er/classify.ts
|
|
10816
|
+
function classifyEREntities(tables, relationships) {
|
|
10817
|
+
const result = /* @__PURE__ */ new Map();
|
|
10818
|
+
if (tables.length === 0) return result;
|
|
10819
|
+
const indegreeMap = {};
|
|
10820
|
+
for (const t of tables) indegreeMap[t.id] = 0;
|
|
10821
|
+
for (const rel of relationships) {
|
|
10822
|
+
if (rel.source === rel.target) continue;
|
|
10823
|
+
if (rel.cardinality.from === "1" && rel.cardinality.to !== "1") {
|
|
10824
|
+
indegreeMap[rel.source] = (indegreeMap[rel.source] ?? 0) + 1;
|
|
10825
|
+
}
|
|
10826
|
+
if (rel.cardinality.to === "1" && rel.cardinality.from !== "1") {
|
|
10827
|
+
indegreeMap[rel.target] = (indegreeMap[rel.target] ?? 0) + 1;
|
|
10828
|
+
}
|
|
10829
|
+
}
|
|
10830
|
+
const tableStarNeighbors = /* @__PURE__ */ new Map();
|
|
10831
|
+
for (const rel of relationships) {
|
|
10832
|
+
if (rel.source === rel.target) continue;
|
|
10833
|
+
if (rel.cardinality.from === "*") {
|
|
10834
|
+
if (!tableStarNeighbors.has(rel.source)) tableStarNeighbors.set(rel.source, /* @__PURE__ */ new Set());
|
|
10835
|
+
tableStarNeighbors.get(rel.source).add(rel.target);
|
|
10836
|
+
}
|
|
10837
|
+
if (rel.cardinality.to === "*") {
|
|
10838
|
+
if (!tableStarNeighbors.has(rel.target)) tableStarNeighbors.set(rel.target, /* @__PURE__ */ new Set());
|
|
10839
|
+
tableStarNeighbors.get(rel.target).add(rel.source);
|
|
10840
|
+
}
|
|
10841
|
+
}
|
|
10842
|
+
const mmParticipants = /* @__PURE__ */ new Set();
|
|
10843
|
+
for (const [id, neighbors] of tableStarNeighbors) {
|
|
10844
|
+
if (neighbors.size >= 2) mmParticipants.add(id);
|
|
10845
|
+
}
|
|
10846
|
+
const indegreeValues = Object.values(indegreeMap);
|
|
10847
|
+
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
10848
|
+
const variance = indegreeValues.reduce((a, b) => a + (b - mean) ** 2, 0) / indegreeValues.length;
|
|
10849
|
+
const stddev = Math.sqrt(variance);
|
|
10850
|
+
const sorted = [...indegreeValues].sort((a, b) => a - b);
|
|
10851
|
+
const median = sorted.length % 2 === 0 ? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2 : sorted[Math.floor(sorted.length / 2)];
|
|
10852
|
+
for (const table of tables) {
|
|
10853
|
+
const id = table.id;
|
|
10854
|
+
const cols = table.columns;
|
|
10855
|
+
const fkCols = cols.filter((c) => c.constraints.includes("fk"));
|
|
10856
|
+
const pkFkCols = cols.filter(
|
|
10857
|
+
(c) => c.constraints.includes("pk") && c.constraints.includes("fk")
|
|
10858
|
+
);
|
|
10859
|
+
const fkCount = fkCols.length;
|
|
10860
|
+
const fkRatio = cols.length === 0 ? 0 : fkCount / cols.length;
|
|
10861
|
+
const indegree = indegreeMap[id] ?? 0;
|
|
10862
|
+
const nameLower = table.name.toLowerCase();
|
|
10863
|
+
const externalRels = relationships.filter(
|
|
10864
|
+
(r) => (r.source === id || r.target === id) && r.source !== r.target
|
|
10865
|
+
);
|
|
10866
|
+
const hasSelfRef = relationships.some((r) => r.source === id && r.target === id);
|
|
10867
|
+
const externalTargets = /* @__PURE__ */ new Set();
|
|
10868
|
+
for (const rel of externalRels) {
|
|
10869
|
+
externalTargets.add(rel.source === id ? rel.target : rel.source);
|
|
10870
|
+
}
|
|
10871
|
+
if (hasSelfRef && externalRels.length === 0) {
|
|
10872
|
+
result.set(id, "self-referential");
|
|
10873
|
+
continue;
|
|
10874
|
+
}
|
|
10875
|
+
const isInheritancePattern = pkFkCols.length >= 2 && externalTargets.size === 1;
|
|
10876
|
+
const junctionByRatio = fkRatio >= 0.6 && !isInheritancePattern;
|
|
10877
|
+
const junctionByCompositePk = pkFkCols.length >= 2 && externalTargets.size >= 2;
|
|
10878
|
+
const junctionByMm = mmParticipants.has(id);
|
|
10879
|
+
if (junctionByRatio || junctionByCompositePk || junctionByMm) {
|
|
10880
|
+
result.set(id, "junction");
|
|
10881
|
+
continue;
|
|
10882
|
+
}
|
|
10883
|
+
if (fkRatio >= 0.4 && fkRatio < 0.6 && pkFkCols.length < 2 && !mmParticipants.has(id)) {
|
|
10884
|
+
result.set(id, "ambiguous");
|
|
10885
|
+
continue;
|
|
10886
|
+
}
|
|
10887
|
+
const nameMatchesLookup = LOOKUP_NAME_SUFFIXES.some((s) => nameLower.endsWith(s));
|
|
10888
|
+
if (nameMatchesLookup && cols.length <= 6 && fkCount <= 1 && indegree > median) {
|
|
10889
|
+
result.set(id, "lookup");
|
|
10890
|
+
continue;
|
|
10891
|
+
}
|
|
10892
|
+
if (tables.length >= 6 && indegree > 0 && indegree > mean + 1.5 * stddev && indegree >= 2 * mean) {
|
|
10893
|
+
result.set(id, "hub");
|
|
10894
|
+
continue;
|
|
10895
|
+
}
|
|
10896
|
+
if (fkCount > 0) {
|
|
10897
|
+
result.set(id, "dependent");
|
|
10898
|
+
continue;
|
|
10899
|
+
}
|
|
10900
|
+
result.set(id, "core");
|
|
10901
|
+
}
|
|
10902
|
+
return result;
|
|
10903
|
+
}
|
|
10904
|
+
var ROLE_COLORS, ROLE_LABELS, ROLE_ORDER, LOOKUP_NAME_SUFFIXES;
|
|
10905
|
+
var init_classify = __esm({
|
|
10906
|
+
"src/er/classify.ts"() {
|
|
10907
|
+
"use strict";
|
|
10908
|
+
ROLE_COLORS = {
|
|
10909
|
+
core: "green",
|
|
10910
|
+
dependent: "blue",
|
|
10911
|
+
junction: "red",
|
|
10912
|
+
ambiguous: "purple",
|
|
10913
|
+
lookup: "yellow",
|
|
10914
|
+
hub: "orange",
|
|
10915
|
+
"self-referential": "teal",
|
|
10916
|
+
unclassified: "gray"
|
|
10917
|
+
};
|
|
10918
|
+
ROLE_LABELS = {
|
|
10919
|
+
core: "Core entity",
|
|
10920
|
+
dependent: "Dependent",
|
|
10921
|
+
junction: "Junction / M:M",
|
|
10922
|
+
ambiguous: "Bridge",
|
|
10923
|
+
lookup: "Lookup / Reference",
|
|
10924
|
+
hub: "Hub",
|
|
10925
|
+
"self-referential": "Self-referential",
|
|
10926
|
+
unclassified: "Unclassified"
|
|
10927
|
+
};
|
|
10928
|
+
ROLE_ORDER = [
|
|
10929
|
+
"core",
|
|
10930
|
+
"dependent",
|
|
10931
|
+
"junction",
|
|
10932
|
+
"ambiguous",
|
|
10933
|
+
"lookup",
|
|
10934
|
+
"hub",
|
|
10935
|
+
"self-referential",
|
|
10936
|
+
"unclassified"
|
|
10937
|
+
];
|
|
10938
|
+
LOOKUP_NAME_SUFFIXES = ["_type", "_status", "_code", "_category"];
|
|
10593
10939
|
}
|
|
10594
10940
|
});
|
|
10595
10941
|
|
|
@@ -10661,25 +11007,41 @@ function drawCardinality(g, point, prevPoint, cardinality, color, useLabels) {
|
|
|
10661
11007
|
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);
|
|
10662
11008
|
}
|
|
10663
11009
|
}
|
|
10664
|
-
function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem, exportDims, activeTagGroup) {
|
|
11010
|
+
function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem, exportDims, activeTagGroup, semanticColorsActive) {
|
|
10665
11011
|
d3Selection5.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
10666
|
-
const
|
|
10667
|
-
const
|
|
10668
|
-
if (width <= 0 || height <= 0) return;
|
|
11012
|
+
const useSemanticColors = parsed.tagGroups.length === 0 && layout.nodes.every((n) => !n.color);
|
|
11013
|
+
const legendReserveH = useSemanticColors ? LEGEND_HEIGHT + DIAGRAM_PADDING5 : 0;
|
|
10669
11014
|
const titleHeight = parsed.title ? 40 : 0;
|
|
10670
11015
|
const diagramW = layout.width;
|
|
10671
11016
|
const diagramH = layout.height;
|
|
10672
|
-
const
|
|
10673
|
-
const
|
|
10674
|
-
|
|
10675
|
-
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
10680
|
-
|
|
11017
|
+
const naturalW = diagramW + DIAGRAM_PADDING5 * 2;
|
|
11018
|
+
const naturalH = diagramH + titleHeight + legendReserveH + DIAGRAM_PADDING5 * 2;
|
|
11019
|
+
let viewW;
|
|
11020
|
+
let viewH;
|
|
11021
|
+
let scale;
|
|
11022
|
+
let offsetX;
|
|
11023
|
+
let offsetY;
|
|
11024
|
+
if (exportDims) {
|
|
11025
|
+
viewW = exportDims.width ?? naturalW;
|
|
11026
|
+
viewH = exportDims.height ?? naturalH;
|
|
11027
|
+
const availH = viewH - titleHeight - legendReserveH;
|
|
11028
|
+
const scaleX = (viewW - DIAGRAM_PADDING5 * 2) / diagramW;
|
|
11029
|
+
const scaleY = (availH - DIAGRAM_PADDING5 * 2) / diagramH;
|
|
11030
|
+
scale = Math.min(MAX_SCALE4, scaleX, scaleY);
|
|
11031
|
+
const scaledW = diagramW * scale;
|
|
11032
|
+
offsetX = (viewW - scaledW) / 2;
|
|
11033
|
+
offsetY = titleHeight + DIAGRAM_PADDING5;
|
|
11034
|
+
} else {
|
|
11035
|
+
viewW = naturalW;
|
|
11036
|
+
viewH = naturalH;
|
|
11037
|
+
scale = 1;
|
|
11038
|
+
offsetX = DIAGRAM_PADDING5;
|
|
11039
|
+
offsetY = titleHeight + DIAGRAM_PADDING5;
|
|
11040
|
+
}
|
|
11041
|
+
if (viewW <= 0 || viewH <= 0) return;
|
|
11042
|
+
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);
|
|
10681
11043
|
if (parsed.title) {
|
|
10682
|
-
const titleEl = svg.append("text").attr("class", "chart-title").attr("x",
|
|
11044
|
+
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);
|
|
10683
11045
|
if (parsed.titleLineNumber) {
|
|
10684
11046
|
titleEl.attr("data-line-number", parsed.titleLineNumber);
|
|
10685
11047
|
if (onClickItem) {
|
|
@@ -10693,6 +11055,8 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10693
11055
|
}
|
|
10694
11056
|
const contentG = svg.append("g").attr("transform", `translate(${offsetX}, ${offsetY}) scale(${scale})`);
|
|
10695
11057
|
const seriesColors2 = getSeriesColors(palette);
|
|
11058
|
+
const semanticRoles = useSemanticColors ? classifyEREntities(parsed.tables, parsed.relationships) : null;
|
|
11059
|
+
const semanticActive = semanticRoles !== null && (semanticColorsActive ?? true);
|
|
10696
11060
|
const useLabels = parsed.options.notation === "labels";
|
|
10697
11061
|
for (const edge of layout.edges) {
|
|
10698
11062
|
if (edge.points.length < 2) continue;
|
|
@@ -10732,7 +11096,8 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10732
11096
|
for (let ni = 0; ni < layout.nodes.length; ni++) {
|
|
10733
11097
|
const node = layout.nodes[ni];
|
|
10734
11098
|
const tagColor = resolveTagColor(node.metadata, parsed.tagGroups, activeTagGroup ?? null);
|
|
10735
|
-
const
|
|
11099
|
+
const semanticColor = semanticActive ? palette.colors[ROLE_COLORS[semanticRoles.get(node.id) ?? "unclassified"]] : semanticRoles ? palette.primary : void 0;
|
|
11100
|
+
const nodeColor2 = node.color ?? tagColor ?? semanticColor ?? seriesColors2[ni % seriesColors2.length];
|
|
10736
11101
|
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);
|
|
10737
11102
|
if (activeTagGroup) {
|
|
10738
11103
|
const tagKey = activeTagGroup.toLowerCase();
|
|
@@ -10741,6 +11106,10 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10741
11106
|
nodeG.attr(`data-tag-${tagKey}`, tagValue.toLowerCase());
|
|
10742
11107
|
}
|
|
10743
11108
|
}
|
|
11109
|
+
if (semanticRoles) {
|
|
11110
|
+
const role = semanticRoles.get(node.id);
|
|
11111
|
+
if (role) nodeG.attr("data-er-role", role);
|
|
11112
|
+
}
|
|
10744
11113
|
if (onClickItem) {
|
|
10745
11114
|
nodeG.style("cursor", "pointer").on("click", () => {
|
|
10746
11115
|
onClickItem(node.lineNumber);
|
|
@@ -10781,7 +11150,7 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10781
11150
|
legendG.attr("data-legend-active", activeTagGroup.toLowerCase());
|
|
10782
11151
|
}
|
|
10783
11152
|
let legendX = DIAGRAM_PADDING5;
|
|
10784
|
-
let legendY =
|
|
11153
|
+
let legendY = viewH - DIAGRAM_PADDING5;
|
|
10785
11154
|
for (const group of parsed.tagGroups) {
|
|
10786
11155
|
const groupG = legendG.append("g").attr("data-legend-group", group.name.toLowerCase());
|
|
10787
11156
|
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}:`);
|
|
@@ -10800,6 +11169,62 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10800
11169
|
legendX += LEGEND_GROUP_GAP;
|
|
10801
11170
|
}
|
|
10802
11171
|
}
|
|
11172
|
+
if (semanticRoles) {
|
|
11173
|
+
const presentRoles = ROLE_ORDER.filter((role) => {
|
|
11174
|
+
for (const r of semanticRoles.values()) {
|
|
11175
|
+
if (r === role) return true;
|
|
11176
|
+
}
|
|
11177
|
+
return false;
|
|
11178
|
+
});
|
|
11179
|
+
if (presentRoles.length > 0) {
|
|
11180
|
+
const measureLabelW = (text, fontSize) => {
|
|
11181
|
+
const dummy = svg.append("text").attr("font-size", fontSize).attr("font-family", FONT_FAMILY).attr("visibility", "hidden").text(text);
|
|
11182
|
+
const measured = dummy.node()?.getComputedTextLength?.() ?? 0;
|
|
11183
|
+
dummy.remove();
|
|
11184
|
+
return measured > 0 ? measured : text.length * fontSize * 0.6;
|
|
11185
|
+
};
|
|
11186
|
+
const labelWidths = /* @__PURE__ */ new Map();
|
|
11187
|
+
for (const role of presentRoles) {
|
|
11188
|
+
labelWidths.set(role, measureLabelW(ROLE_LABELS[role], LEGEND_ENTRY_FONT_SIZE));
|
|
11189
|
+
}
|
|
11190
|
+
const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
|
|
11191
|
+
const groupName = "Role";
|
|
11192
|
+
const pillWidth = groupName.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD;
|
|
11193
|
+
const pillH = LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2;
|
|
11194
|
+
let totalWidth;
|
|
11195
|
+
let entriesWidth = 0;
|
|
11196
|
+
if (semanticActive) {
|
|
11197
|
+
for (const role of presentRoles) {
|
|
11198
|
+
entriesWidth += LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + labelWidths.get(role) + LEGEND_ENTRY_TRAIL;
|
|
11199
|
+
}
|
|
11200
|
+
totalWidth = LEGEND_CAPSULE_PAD * 2 + pillWidth + LEGEND_ENTRY_TRAIL + entriesWidth;
|
|
11201
|
+
} else {
|
|
11202
|
+
totalWidth = pillWidth;
|
|
11203
|
+
}
|
|
11204
|
+
const legendX = (viewW - totalWidth) / 2;
|
|
11205
|
+
const legendY = viewH - DIAGRAM_PADDING5 - LEGEND_HEIGHT;
|
|
11206
|
+
const semanticLegendG = svg.append("g").attr("class", "er-semantic-legend").attr("data-legend-group", "role").attr("transform", `translate(${legendX}, ${legendY})`).style("cursor", "pointer");
|
|
11207
|
+
if (semanticActive) {
|
|
11208
|
+
semanticLegendG.append("rect").attr("width", totalWidth).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
|
|
11209
|
+
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);
|
|
11210
|
+
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);
|
|
11211
|
+
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);
|
|
11212
|
+
let entryX = LEGEND_CAPSULE_PAD + pillWidth + LEGEND_ENTRY_TRAIL;
|
|
11213
|
+
for (const role of presentRoles) {
|
|
11214
|
+
const label = ROLE_LABELS[role];
|
|
11215
|
+
const roleColor = palette.colors[ROLE_COLORS[role]];
|
|
11216
|
+
const entryG = semanticLegendG.append("g").attr("data-legend-entry", role);
|
|
11217
|
+
entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", roleColor);
|
|
11218
|
+
const textX = entryX + LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP;
|
|
11219
|
+
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);
|
|
11220
|
+
entryX = textX + labelWidths.get(role) + LEGEND_ENTRY_TRAIL;
|
|
11221
|
+
}
|
|
11222
|
+
} else {
|
|
11223
|
+
semanticLegendG.append("rect").attr("width", pillWidth).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
|
|
11224
|
+
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);
|
|
11225
|
+
}
|
|
11226
|
+
}
|
|
11227
|
+
}
|
|
10803
11228
|
}
|
|
10804
11229
|
function renderERDiagramForExport(content, theme, palette) {
|
|
10805
11230
|
const parsed = parseERDiagram(content, palette);
|
|
@@ -10847,6 +11272,7 @@ var init_renderer5 = __esm({
|
|
|
10847
11272
|
init_legend_constants();
|
|
10848
11273
|
init_parser3();
|
|
10849
11274
|
init_layout4();
|
|
11275
|
+
init_classify();
|
|
10850
11276
|
DIAGRAM_PADDING5 = 20;
|
|
10851
11277
|
MAX_SCALE4 = 3;
|
|
10852
11278
|
TABLE_FONT_SIZE = 13;
|
|
@@ -10975,9 +11401,10 @@ function layoutInitiativeStatus(parsed, collapseResult) {
|
|
|
10975
11401
|
const dagreEdge = g.edge(edge.source, edge.target, `e${i}`);
|
|
10976
11402
|
const dagrePoints = dagreEdge?.points ?? [];
|
|
10977
11403
|
const hasIntermediateRank = allNodeX.some((x) => x > src.x + 20 && x < tgt.x - 20);
|
|
10978
|
-
const step = Math.min((enterX - exitX) * 0.15, 20);
|
|
11404
|
+
const step = Math.max(0, Math.min((enterX - exitX) * 0.15, 20));
|
|
10979
11405
|
const isBackEdge = tgt.x < src.x - 5;
|
|
10980
|
-
const
|
|
11406
|
+
const isTopExit = !isBackEdge && tgt.x > src.x && !hasIntermediateRank && tgt.y < src.y - NODESEP;
|
|
11407
|
+
const isBottomExit = !isBackEdge && tgt.x > src.x && !hasIntermediateRank && tgt.y > src.y + NODESEP;
|
|
10981
11408
|
let points;
|
|
10982
11409
|
if (isBackEdge) {
|
|
10983
11410
|
const routeAbove = Math.min(src.y, tgt.y) > avgNodeY;
|
|
@@ -10987,31 +11414,44 @@ function layoutInitiativeStatus(parsed, collapseResult) {
|
|
|
10987
11414
|
const spreadDir = avgNodeX < rawMidX ? 1 : -1;
|
|
10988
11415
|
const unclamped = Math.abs(src.x - tgt.x) < NODE_WIDTH ? rawMidX + spreadDir * BACK_EDGE_MIN_SPREAD : rawMidX;
|
|
10989
11416
|
const midX = Math.min(src.x, Math.max(tgt.x, unclamped));
|
|
11417
|
+
const srcDepart = Math.max(midX + 1, src.x - TOP_EXIT_STEP);
|
|
11418
|
+
const tgtApproach = Math.min(midX - 1, tgt.x + TOP_EXIT_STEP);
|
|
10990
11419
|
if (routeAbove) {
|
|
10991
11420
|
const arcY = Math.min(src.y - srcHalfH, tgt.y - tgtHalfH) - BACK_EDGE_MARGIN;
|
|
10992
11421
|
points = [
|
|
10993
11422
|
{ x: src.x, y: src.y - srcHalfH },
|
|
11423
|
+
{ x: srcDepart, y: src.y - srcHalfH - TOP_EXIT_STEP },
|
|
10994
11424
|
{ x: midX, y: arcY },
|
|
11425
|
+
{ x: tgtApproach, y: tgt.y - tgtHalfH - TOP_EXIT_STEP },
|
|
10995
11426
|
{ x: tgt.x, y: tgt.y - tgtHalfH }
|
|
10996
11427
|
];
|
|
10997
11428
|
} else {
|
|
10998
11429
|
const arcY = Math.max(src.y + srcHalfH, tgt.y + tgtHalfH) + BACK_EDGE_MARGIN;
|
|
10999
11430
|
points = [
|
|
11000
11431
|
{ x: src.x, y: src.y + srcHalfH },
|
|
11432
|
+
{ x: srcDepart, y: src.y + srcHalfH + TOP_EXIT_STEP },
|
|
11001
11433
|
{ x: midX, y: arcY },
|
|
11434
|
+
{ x: tgtApproach, y: tgt.y + tgtHalfH + TOP_EXIT_STEP },
|
|
11002
11435
|
{ x: tgt.x, y: tgt.y + tgtHalfH }
|
|
11003
11436
|
];
|
|
11004
11437
|
}
|
|
11005
|
-
} else if (
|
|
11006
|
-
const exitY =
|
|
11007
|
-
const
|
|
11008
|
-
const spreadEntryY = tgt.y + yOffset;
|
|
11009
|
-
const midX = (spreadExitX + enterX) / 2;
|
|
11010
|
-
const midY = (exitY + spreadEntryY) / 2;
|
|
11438
|
+
} else if (isTopExit) {
|
|
11439
|
+
const exitY = src.y - src.height / 2;
|
|
11440
|
+
const p1x = Math.min(Math.max(src.x, src.x + yOffset + TOP_EXIT_STEP), (src.x + enterX) / 2 - 1);
|
|
11011
11441
|
points = [
|
|
11012
|
-
{ x:
|
|
11013
|
-
{ x:
|
|
11014
|
-
{ x: enterX, y:
|
|
11442
|
+
{ x: src.x, y: exitY },
|
|
11443
|
+
{ x: p1x, y: exitY - TOP_EXIT_STEP },
|
|
11444
|
+
{ x: enterX - step, y: tgt.y + yOffset },
|
|
11445
|
+
{ x: enterX, y: tgt.y }
|
|
11446
|
+
];
|
|
11447
|
+
} else if (isBottomExit) {
|
|
11448
|
+
const exitY = src.y + src.height / 2;
|
|
11449
|
+
const p1x = Math.min(Math.max(src.x, src.x + yOffset + TOP_EXIT_STEP), (src.x + enterX) / 2 - 1);
|
|
11450
|
+
points = [
|
|
11451
|
+
{ x: src.x, y: exitY },
|
|
11452
|
+
{ x: p1x, y: exitY + TOP_EXIT_STEP },
|
|
11453
|
+
{ x: enterX - step, y: tgt.y + yOffset },
|
|
11454
|
+
{ x: enterX, y: tgt.y }
|
|
11015
11455
|
];
|
|
11016
11456
|
} else if (tgt.x > src.x && !hasIntermediateRank) {
|
|
11017
11457
|
points = [
|
|
@@ -11108,7 +11548,7 @@ function layoutInitiativeStatus(parsed, collapseResult) {
|
|
|
11108
11548
|
totalHeight += 40;
|
|
11109
11549
|
return { nodes: layoutNodes, edges: layoutEdges, groups: layoutGroups, width: totalWidth, height: totalHeight };
|
|
11110
11550
|
}
|
|
11111
|
-
var 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;
|
|
11551
|
+
var 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;
|
|
11112
11552
|
var init_layout5 = __esm({
|
|
11113
11553
|
"src/initiative-status/layout.ts"() {
|
|
11114
11554
|
"use strict";
|
|
@@ -11124,6 +11564,7 @@ var init_layout5 = __esm({
|
|
|
11124
11564
|
MAX_PARALLEL_EDGES = 5;
|
|
11125
11565
|
BACK_EDGE_MARGIN = 40;
|
|
11126
11566
|
BACK_EDGE_MIN_SPREAD = Math.round(NODE_WIDTH * 0.75);
|
|
11567
|
+
TOP_EXIT_STEP = 10;
|
|
11127
11568
|
CHAR_WIDTH_RATIO = 0.6;
|
|
11128
11569
|
NODE_FONT_SIZE = 13;
|
|
11129
11570
|
NODE_TEXT_PADDING = 12;
|
|
@@ -11372,7 +11813,6 @@ function renderInitiativeStatus(container, parsed, layout, palette, isDark, onCl
|
|
|
11372
11813
|
const scaleY = (availH - DIAGRAM_PADDING6 * 2) / diagramH;
|
|
11373
11814
|
const scale = Math.min(MAX_SCALE5, scaleX, scaleY);
|
|
11374
11815
|
const scaledW = diagramW * scale;
|
|
11375
|
-
const scaledH = diagramH * scale;
|
|
11376
11816
|
const offsetX = (width - scaledW) / 2;
|
|
11377
11817
|
const offsetY = titleHeight + DIAGRAM_PADDING6;
|
|
11378
11818
|
const svg = d3Selection6.select(container).append("svg").attr("width", width).attr("height", height).style("font-family", FONT_FAMILY);
|
|
@@ -11555,13 +11995,7 @@ function renderInitiativeStatusForExport(content, theme, palette) {
|
|
|
11555
11995
|
const titleOffset = parsed.title ? 40 : 0;
|
|
11556
11996
|
const exportWidth = layout.width + DIAGRAM_PADDING6 * 2;
|
|
11557
11997
|
const exportHeight = layout.height + DIAGRAM_PADDING6 * 2 + titleOffset;
|
|
11558
|
-
|
|
11559
|
-
container.style.width = `${exportWidth}px`;
|
|
11560
|
-
container.style.height = `${exportHeight}px`;
|
|
11561
|
-
container.style.position = "absolute";
|
|
11562
|
-
container.style.left = "-9999px";
|
|
11563
|
-
document.body.appendChild(container);
|
|
11564
|
-
try {
|
|
11998
|
+
return runInExportContainer(exportWidth, exportHeight, (container) => {
|
|
11565
11999
|
renderInitiativeStatus(
|
|
11566
12000
|
container,
|
|
11567
12001
|
parsed,
|
|
@@ -11571,23 +12005,15 @@ function renderInitiativeStatusForExport(content, theme, palette) {
|
|
|
11571
12005
|
void 0,
|
|
11572
12006
|
{ width: exportWidth, height: exportHeight }
|
|
11573
12007
|
);
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
if (theme === "transparent") {
|
|
11577
|
-
svgEl.style.background = "none";
|
|
11578
|
-
}
|
|
11579
|
-
svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
11580
|
-
svgEl.style.fontFamily = FONT_FAMILY;
|
|
11581
|
-
return svgEl.outerHTML;
|
|
11582
|
-
} finally {
|
|
11583
|
-
document.body.removeChild(container);
|
|
11584
|
-
}
|
|
12008
|
+
return extractExportSvg(container, theme);
|
|
12009
|
+
});
|
|
11585
12010
|
}
|
|
11586
12011
|
var 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;
|
|
11587
12012
|
var init_renderer6 = __esm({
|
|
11588
12013
|
"src/initiative-status/renderer.ts"() {
|
|
11589
12014
|
"use strict";
|
|
11590
12015
|
init_fonts();
|
|
12016
|
+
init_export_container();
|
|
11591
12017
|
init_color_utils();
|
|
11592
12018
|
init_parser7();
|
|
11593
12019
|
init_layout5();
|
|
@@ -11623,7 +12049,7 @@ __export(layout_exports6, {
|
|
|
11623
12049
|
rollUpContextRelationships: () => rollUpContextRelationships
|
|
11624
12050
|
});
|
|
11625
12051
|
import dagre5 from "@dagrejs/dagre";
|
|
11626
|
-
function computeEdgePenalty(edgeList, nodePositions, degrees) {
|
|
12052
|
+
function computeEdgePenalty(edgeList, nodePositions, degrees, nodeGeometry) {
|
|
11627
12053
|
let penalty = 0;
|
|
11628
12054
|
for (const edge of edgeList) {
|
|
11629
12055
|
const sx = nodePositions.get(edge.source);
|
|
@@ -11633,6 +12059,32 @@ function computeEdgePenalty(edgeList, nodePositions, degrees) {
|
|
|
11633
12059
|
const weight = Math.min(degrees.get(edge.source) ?? 1, degrees.get(edge.target) ?? 1);
|
|
11634
12060
|
penalty += dist * weight;
|
|
11635
12061
|
}
|
|
12062
|
+
if (nodeGeometry) {
|
|
12063
|
+
for (const edge of edgeList) {
|
|
12064
|
+
const geomA = nodeGeometry.get(edge.source);
|
|
12065
|
+
const geomB = nodeGeometry.get(edge.target);
|
|
12066
|
+
if (!geomA || !geomB) continue;
|
|
12067
|
+
const ax = nodePositions.get(edge.source) ?? 0;
|
|
12068
|
+
const bx = nodePositions.get(edge.target) ?? 0;
|
|
12069
|
+
const ay = geomA.y;
|
|
12070
|
+
const by = geomB.y;
|
|
12071
|
+
if (ay === by) continue;
|
|
12072
|
+
const edgeMinX = Math.min(ax, bx);
|
|
12073
|
+
const edgeMaxX = Math.max(ax, bx);
|
|
12074
|
+
const edgeMinY = Math.min(ay, by);
|
|
12075
|
+
const edgeMaxY = Math.max(ay, by);
|
|
12076
|
+
for (const [name, geomC] of nodeGeometry) {
|
|
12077
|
+
if (name === edge.source || name === edge.target) continue;
|
|
12078
|
+
const cx = nodePositions.get(name) ?? 0;
|
|
12079
|
+
const cy = geomC.y;
|
|
12080
|
+
const hw = geomC.width / 2;
|
|
12081
|
+
const hh = geomC.height / 2;
|
|
12082
|
+
if (cx + hw > edgeMinX && cx - hw < edgeMaxX && cy + hh > edgeMinY && cy - hh < edgeMaxY) {
|
|
12083
|
+
penalty += EDGE_NODE_COLLISION_WEIGHT;
|
|
12084
|
+
}
|
|
12085
|
+
}
|
|
12086
|
+
}
|
|
12087
|
+
}
|
|
11636
12088
|
return penalty;
|
|
11637
12089
|
}
|
|
11638
12090
|
function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
@@ -11642,6 +12094,11 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11642
12094
|
degrees.set(edge.source, (degrees.get(edge.source) ?? 0) + 1);
|
|
11643
12095
|
degrees.set(edge.target, (degrees.get(edge.target) ?? 0) + 1);
|
|
11644
12096
|
}
|
|
12097
|
+
const nodeGeometry = /* @__PURE__ */ new Map();
|
|
12098
|
+
for (const name of g.nodes()) {
|
|
12099
|
+
const pos = g.node(name);
|
|
12100
|
+
if (pos) nodeGeometry.set(name, { y: pos.y, width: pos.width, height: pos.height });
|
|
12101
|
+
}
|
|
11645
12102
|
const rankMap = /* @__PURE__ */ new Map();
|
|
11646
12103
|
for (const name of g.nodes()) {
|
|
11647
12104
|
const pos = g.node(name);
|
|
@@ -11684,7 +12141,7 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11684
12141
|
const pos = g.node(name);
|
|
11685
12142
|
if (pos) basePositions.set(name, pos.x);
|
|
11686
12143
|
}
|
|
11687
|
-
const currentPenalty = computeEdgePenalty(edgeList, basePositions, degrees);
|
|
12144
|
+
const currentPenalty = computeEdgePenalty(edgeList, basePositions, degrees, nodeGeometry);
|
|
11688
12145
|
let bestPerm = [...partition];
|
|
11689
12146
|
let bestPenalty = currentPenalty;
|
|
11690
12147
|
if (partition.length <= 8) {
|
|
@@ -11694,7 +12151,7 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11694
12151
|
for (let i = 0; i < perm.length; i++) {
|
|
11695
12152
|
testPositions.set(perm[i], xSlots[i]);
|
|
11696
12153
|
}
|
|
11697
|
-
const penalty = computeEdgePenalty(edgeList, testPositions, degrees);
|
|
12154
|
+
const penalty = computeEdgePenalty(edgeList, testPositions, degrees, nodeGeometry);
|
|
11698
12155
|
if (penalty < bestPenalty) {
|
|
11699
12156
|
bestPenalty = penalty;
|
|
11700
12157
|
bestPerm = [...perm];
|
|
@@ -11712,13 +12169,13 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11712
12169
|
for (let k = 0; k < workingOrder.length; k++) {
|
|
11713
12170
|
testPositions.set(workingOrder[k], xSlots[k]);
|
|
11714
12171
|
}
|
|
11715
|
-
const before = computeEdgePenalty(edgeList, testPositions, degrees);
|
|
12172
|
+
const before = computeEdgePenalty(edgeList, testPositions, degrees, nodeGeometry);
|
|
11716
12173
|
[workingOrder[i], workingOrder[i + 1]] = [workingOrder[i + 1], workingOrder[i]];
|
|
11717
12174
|
const testPositions2 = new Map(basePositions);
|
|
11718
12175
|
for (let k = 0; k < workingOrder.length; k++) {
|
|
11719
12176
|
testPositions2.set(workingOrder[k], xSlots[k]);
|
|
11720
12177
|
}
|
|
11721
|
-
const after = computeEdgePenalty(edgeList, testPositions2, degrees);
|
|
12178
|
+
const after = computeEdgePenalty(edgeList, testPositions2, degrees, nodeGeometry);
|
|
11722
12179
|
if (after < before) {
|
|
11723
12180
|
improved = true;
|
|
11724
12181
|
if (after < bestPenalty) {
|
|
@@ -11825,8 +12282,6 @@ function collectAllRelationships(elements, ownerMap) {
|
|
|
11825
12282
|
function rollUpContextRelationships(parsed) {
|
|
11826
12283
|
const ownerMap = buildOwnershipMap(parsed.elements);
|
|
11827
12284
|
const allRels = collectAllRelationships(parsed.elements, ownerMap);
|
|
11828
|
-
for (const rel of parsed.relationships) {
|
|
11829
|
-
}
|
|
11830
12285
|
const topLevelNames = new Set(parsed.elements.map((e) => e.name));
|
|
11831
12286
|
const explicitKeys = /* @__PURE__ */ new Set();
|
|
11832
12287
|
const explicit = [];
|
|
@@ -13038,7 +13493,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
|
|
|
13038
13493
|
}
|
|
13039
13494
|
return { nodes, edges, legend: legendGroups, groupBoundaries, width: totalWidth, height: totalHeight };
|
|
13040
13495
|
}
|
|
13041
|
-
var 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;
|
|
13496
|
+
var 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;
|
|
13042
13497
|
var init_layout6 = __esm({
|
|
13043
13498
|
"src/c4/layout.ts"() {
|
|
13044
13499
|
"use strict";
|
|
@@ -13067,6 +13522,7 @@ var init_layout6 = __esm({
|
|
|
13067
13522
|
LEGEND_ENTRY_DOT_GAP4 = 4;
|
|
13068
13523
|
LEGEND_ENTRY_TRAIL4 = 8;
|
|
13069
13524
|
LEGEND_CAPSULE_PAD4 = 4;
|
|
13525
|
+
EDGE_NODE_COLLISION_WEIGHT = 5e3;
|
|
13070
13526
|
META_EXCLUDE_KEYS = /* @__PURE__ */ new Set(["description", "tech", "technology", "is a"]);
|
|
13071
13527
|
}
|
|
13072
13528
|
});
|
|
@@ -13156,7 +13612,6 @@ function renderC4Context(container, parsed, layout, palette, isDark, onClickItem
|
|
|
13156
13612
|
const scaleY = (availH - DIAGRAM_PADDING7 * 2) / diagramH;
|
|
13157
13613
|
const scale = Math.min(MAX_SCALE6, scaleX, scaleY);
|
|
13158
13614
|
const scaledW = diagramW * scale;
|
|
13159
|
-
const scaledH = diagramH * scale;
|
|
13160
13615
|
const offsetX = (width - scaledW) / 2;
|
|
13161
13616
|
const offsetY = titleHeight + DIAGRAM_PADDING7;
|
|
13162
13617
|
const svg = d3Selection7.select(container).append("svg").attr("width", width).attr("height", height).style("font-family", FONT_FAMILY);
|
|
@@ -13646,7 +14101,6 @@ function renderC4Containers(container, parsed, layout, palette, isDark, onClickI
|
|
|
13646
14101
|
const scaleY = (availH - DIAGRAM_PADDING7 * 2) / diagramH;
|
|
13647
14102
|
const scale = Math.min(MAX_SCALE6, scaleX, scaleY);
|
|
13648
14103
|
const scaledW = diagramW * scale;
|
|
13649
|
-
const scaledH = diagramH * scale;
|
|
13650
14104
|
const offsetX = (width - scaledW) / 2;
|
|
13651
14105
|
const offsetY = titleHeight + DIAGRAM_PADDING7;
|
|
13652
14106
|
const svg = d3Selection7.select(container).append("svg").attr("width", width).attr("height", height).style("font-family", FONT_FAMILY);
|
|
@@ -14259,7 +14713,6 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
|
|
|
14259
14713
|
const scaleY = (availH - DIAGRAM_PADDING8 * 2) / diagramH;
|
|
14260
14714
|
const scale = Math.min(MAX_SCALE7, scaleX, scaleY);
|
|
14261
14715
|
const scaledW = diagramW * scale;
|
|
14262
|
-
const scaledH = diagramH * scale;
|
|
14263
14716
|
const offsetX = (width - scaledW) / 2;
|
|
14264
14717
|
const offsetY = titleHeight + DIAGRAM_PADDING8;
|
|
14265
14718
|
const svg = d3Selection8.select(container).append("svg").attr("width", width).attr("height", height).style("font-family", FONT_FAMILY);
|
|
@@ -15251,6 +15704,7 @@ var init_compute = __esm({
|
|
|
15251
15704
|
// src/infra/layout.ts
|
|
15252
15705
|
var layout_exports8 = {};
|
|
15253
15706
|
__export(layout_exports8, {
|
|
15707
|
+
fixEdgeWaypoints: () => fixEdgeWaypoints,
|
|
15254
15708
|
layoutInfra: () => layoutInfra,
|
|
15255
15709
|
separateGroups: () => separateGroups
|
|
15256
15710
|
});
|
|
@@ -15435,6 +15889,8 @@ function formatUptime(fraction) {
|
|
|
15435
15889
|
return `${pct.toFixed(1)}%`;
|
|
15436
15890
|
}
|
|
15437
15891
|
function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
15892
|
+
const groupDeltas = /* @__PURE__ */ new Map();
|
|
15893
|
+
let converged = false;
|
|
15438
15894
|
for (let iter = 0; iter < maxIterations; iter++) {
|
|
15439
15895
|
let anyOverlap = false;
|
|
15440
15896
|
for (let i = 0; i < groups.length; i++) {
|
|
@@ -15452,6 +15908,9 @@ function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
|
15452
15908
|
const groupToShift = aCenter <= bCenter ? gb : ga;
|
|
15453
15909
|
if (isLR) groupToShift.y += shift;
|
|
15454
15910
|
else groupToShift.x += shift;
|
|
15911
|
+
const prev = groupDeltas.get(groupToShift.id) ?? { dx: 0, dy: 0 };
|
|
15912
|
+
if (isLR) groupDeltas.set(groupToShift.id, { dx: prev.dx, dy: prev.dy + shift });
|
|
15913
|
+
else groupDeltas.set(groupToShift.id, { dx: prev.dx + shift, dy: prev.dy });
|
|
15455
15914
|
for (const node of nodes) {
|
|
15456
15915
|
if (node.groupId === groupToShift.id) {
|
|
15457
15916
|
if (isLR) node.y += shift;
|
|
@@ -15460,19 +15919,48 @@ function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
|
15460
15919
|
}
|
|
15461
15920
|
}
|
|
15462
15921
|
}
|
|
15463
|
-
if (!anyOverlap)
|
|
15922
|
+
if (!anyOverlap) {
|
|
15923
|
+
converged = true;
|
|
15924
|
+
break;
|
|
15925
|
+
}
|
|
15926
|
+
}
|
|
15927
|
+
if (!converged && maxIterations > 0) {
|
|
15928
|
+
console.warn(`separateGroups: hit maxIterations (${maxIterations}) without fully resolving all group overlaps`);
|
|
15929
|
+
}
|
|
15930
|
+
return groupDeltas;
|
|
15931
|
+
}
|
|
15932
|
+
function fixEdgeWaypoints(edges, nodes, groupDeltas) {
|
|
15933
|
+
if (groupDeltas.size === 0) return;
|
|
15934
|
+
const nodeToGroup = /* @__PURE__ */ new Map();
|
|
15935
|
+
for (const node of nodes) nodeToGroup.set(node.id, node.groupId);
|
|
15936
|
+
for (const edge of edges) {
|
|
15937
|
+
const srcGroup = nodeToGroup.get(edge.sourceId) ?? null;
|
|
15938
|
+
const tgtGroup = nodeToGroup.get(edge.targetId) ?? null;
|
|
15939
|
+
const srcDelta = srcGroup ? groupDeltas.get(srcGroup) : void 0;
|
|
15940
|
+
const tgtDelta = tgtGroup ? groupDeltas.get(tgtGroup) : void 0;
|
|
15941
|
+
if (!srcDelta && !tgtDelta) continue;
|
|
15942
|
+
if (srcDelta && tgtDelta && srcGroup !== tgtGroup) {
|
|
15943
|
+
edge.points = [];
|
|
15944
|
+
continue;
|
|
15945
|
+
}
|
|
15946
|
+
const delta = srcDelta ?? tgtDelta;
|
|
15947
|
+
for (const pt of edge.points) {
|
|
15948
|
+
pt.x += delta.dx;
|
|
15949
|
+
pt.y += delta.dy;
|
|
15950
|
+
}
|
|
15464
15951
|
}
|
|
15465
15952
|
}
|
|
15466
15953
|
function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
15467
15954
|
if (computed.nodes.length === 0) {
|
|
15468
|
-
return { nodes: [], edges: [], groups: [], options: {}, width: 0, height: 0 };
|
|
15955
|
+
return { nodes: [], edges: [], groups: [], options: {}, direction: computed.direction, width: 0, height: 0 };
|
|
15469
15956
|
}
|
|
15957
|
+
const isLR = computed.direction !== "TB";
|
|
15470
15958
|
const g = new dagre7.graphlib.Graph();
|
|
15471
15959
|
g.setGraph({
|
|
15472
15960
|
rankdir: computed.direction === "TB" ? "TB" : "LR",
|
|
15473
|
-
nodesep:
|
|
15474
|
-
ranksep:
|
|
15475
|
-
edgesep:
|
|
15961
|
+
nodesep: isLR ? 70 : 60,
|
|
15962
|
+
ranksep: isLR ? 150 : 120,
|
|
15963
|
+
edgesep: 30
|
|
15476
15964
|
});
|
|
15477
15965
|
g.setDefaultEdgeLabel(() => ({}));
|
|
15478
15966
|
const groupedNodeIds = /* @__PURE__ */ new Set();
|
|
@@ -15480,7 +15968,6 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
15480
15968
|
if (node.groupId) groupedNodeIds.add(node.id);
|
|
15481
15969
|
}
|
|
15482
15970
|
const GROUP_INFLATE = GROUP_PADDING3 * 2 + GROUP_HEADER_HEIGHT;
|
|
15483
|
-
const isLR = computed.direction !== "TB";
|
|
15484
15971
|
const widthMap = /* @__PURE__ */ new Map();
|
|
15485
15972
|
const heightMap = /* @__PURE__ */ new Map();
|
|
15486
15973
|
for (const node of computed.nodes) {
|
|
@@ -15615,7 +16102,8 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
15615
16102
|
lineNumber: group.lineNumber
|
|
15616
16103
|
};
|
|
15617
16104
|
});
|
|
15618
|
-
separateGroups(layoutGroups, layoutNodes, isLR);
|
|
16105
|
+
const groupDeltas = separateGroups(layoutGroups, layoutNodes, isLR);
|
|
16106
|
+
fixEdgeWaypoints(layoutEdges, layoutNodes, groupDeltas);
|
|
15619
16107
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
15620
16108
|
for (const node of layoutNodes) {
|
|
15621
16109
|
const left = node.x - node.width / 2;
|
|
@@ -15673,6 +16161,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
15673
16161
|
edges: layoutEdges,
|
|
15674
16162
|
groups: layoutGroups,
|
|
15675
16163
|
options: computed.options,
|
|
16164
|
+
direction: computed.direction,
|
|
15676
16165
|
width: totalWidth,
|
|
15677
16166
|
height: totalHeight
|
|
15678
16167
|
};
|
|
@@ -15714,23 +16203,23 @@ var init_layout8 = __esm({
|
|
|
15714
16203
|
]);
|
|
15715
16204
|
DISPLAY_NAMES = {
|
|
15716
16205
|
"cache-hit": "cache hit",
|
|
15717
|
-
"firewall-block": "
|
|
16206
|
+
"firewall-block": "firewall block",
|
|
15718
16207
|
"ratelimit-rps": "rate limit RPS",
|
|
15719
16208
|
"latency-ms": "latency",
|
|
15720
16209
|
"uptime": "uptime",
|
|
15721
16210
|
"instances": "instances",
|
|
15722
16211
|
"max-rps": "max RPS",
|
|
15723
|
-
"cb-error-threshold": "CB error",
|
|
15724
|
-
"cb-latency-threshold-ms": "CB latency",
|
|
16212
|
+
"cb-error-threshold": "CB error threshold",
|
|
16213
|
+
"cb-latency-threshold-ms": "CB latency threshold",
|
|
15725
16214
|
"concurrency": "concurrency",
|
|
15726
16215
|
"duration-ms": "duration",
|
|
15727
16216
|
"cold-start-ms": "cold start",
|
|
15728
16217
|
"buffer": "buffer",
|
|
15729
|
-
"drain-rate": "drain",
|
|
16218
|
+
"drain-rate": "drain rate",
|
|
15730
16219
|
"retention-hours": "retention",
|
|
15731
16220
|
"partitions": "partitions"
|
|
15732
16221
|
};
|
|
15733
|
-
GROUP_GAP =
|
|
16222
|
+
GROUP_GAP = GROUP_PADDING3 * 2 + GROUP_HEADER_HEIGHT;
|
|
15734
16223
|
}
|
|
15735
16224
|
});
|
|
15736
16225
|
|
|
@@ -15805,6 +16294,236 @@ function resolveNodeSlo(node, diagramOptions) {
|
|
|
15805
16294
|
if (availThreshold == null && latencyP90 == null) return null;
|
|
15806
16295
|
return { availThreshold, latencyP90, warningMargin };
|
|
15807
16296
|
}
|
|
16297
|
+
function buildPathD(pts, direction) {
|
|
16298
|
+
const gen = d3Shape7.line().x((d) => d.x).y((d) => d.y);
|
|
16299
|
+
if (pts.length <= 2) {
|
|
16300
|
+
gen.curve(direction === "TB" ? d3Shape7.curveBumpY : d3Shape7.curveBumpX);
|
|
16301
|
+
} else {
|
|
16302
|
+
gen.curve(d3Shape7.curveCatmullRom.alpha(0.5));
|
|
16303
|
+
}
|
|
16304
|
+
return gen(pts) ?? "";
|
|
16305
|
+
}
|
|
16306
|
+
function computePortPts(edges, nodeMap, direction) {
|
|
16307
|
+
const srcPts = /* @__PURE__ */ new Map();
|
|
16308
|
+
const tgtPts = /* @__PURE__ */ new Map();
|
|
16309
|
+
const PAD = 0.1;
|
|
16310
|
+
const activeEdges = edges.filter((e) => e.points.length > 0);
|
|
16311
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
16312
|
+
for (const e of activeEdges) {
|
|
16313
|
+
if (!bySource.has(e.sourceId)) bySource.set(e.sourceId, []);
|
|
16314
|
+
bySource.get(e.sourceId).push(e);
|
|
16315
|
+
}
|
|
16316
|
+
for (const [sourceId, es] of bySource) {
|
|
16317
|
+
if (es.length < 2) continue;
|
|
16318
|
+
const source = nodeMap.get(sourceId);
|
|
16319
|
+
if (!source) continue;
|
|
16320
|
+
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);
|
|
16321
|
+
const n = sorted.length;
|
|
16322
|
+
for (let i = 0; i < n; i++) {
|
|
16323
|
+
const frac = n === 1 ? 0.5 : PAD + (1 - 2 * PAD) * i / (n - 1);
|
|
16324
|
+
const { e, t } = sorted[i];
|
|
16325
|
+
const isBackward = direction === "LR" ? t.x < source.x : t.y < source.y;
|
|
16326
|
+
if (direction === "LR") {
|
|
16327
|
+
srcPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16328
|
+
x: isBackward ? source.x - source.width / 2 : source.x + source.width / 2,
|
|
16329
|
+
y: source.y - source.height / 2 + frac * source.height
|
|
16330
|
+
});
|
|
16331
|
+
} else {
|
|
16332
|
+
srcPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16333
|
+
x: source.x - source.width / 2 + frac * source.width,
|
|
16334
|
+
y: isBackward ? source.y - source.height / 2 : source.y + source.height / 2
|
|
16335
|
+
});
|
|
16336
|
+
}
|
|
16337
|
+
}
|
|
16338
|
+
}
|
|
16339
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
16340
|
+
for (const e of activeEdges) {
|
|
16341
|
+
if (!byTarget.has(e.targetId)) byTarget.set(e.targetId, []);
|
|
16342
|
+
byTarget.get(e.targetId).push(e);
|
|
16343
|
+
}
|
|
16344
|
+
for (const [targetId, es] of byTarget) {
|
|
16345
|
+
if (es.length < 2) continue;
|
|
16346
|
+
const target = nodeMap.get(targetId);
|
|
16347
|
+
if (!target) continue;
|
|
16348
|
+
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);
|
|
16349
|
+
const n = sorted.length;
|
|
16350
|
+
for (let i = 0; i < n; i++) {
|
|
16351
|
+
const frac = n === 1 ? 0.5 : PAD + (1 - 2 * PAD) * i / (n - 1);
|
|
16352
|
+
const { e, s } = sorted[i];
|
|
16353
|
+
const isBackward = direction === "LR" ? target.x < s.x : target.y < s.y;
|
|
16354
|
+
if (direction === "LR") {
|
|
16355
|
+
tgtPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16356
|
+
x: isBackward ? target.x + target.width / 2 : target.x - target.width / 2,
|
|
16357
|
+
y: target.y - target.height / 2 + frac * target.height
|
|
16358
|
+
});
|
|
16359
|
+
} else {
|
|
16360
|
+
tgtPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16361
|
+
x: target.x - target.width / 2 + frac * target.width,
|
|
16362
|
+
y: isBackward ? target.y + target.height / 2 : target.y - target.height / 2
|
|
16363
|
+
});
|
|
16364
|
+
}
|
|
16365
|
+
}
|
|
16366
|
+
}
|
|
16367
|
+
return { srcPts, tgtPts };
|
|
16368
|
+
}
|
|
16369
|
+
function findRoutingLane(blocking, targetY, margin) {
|
|
16370
|
+
const MERGE_SLOP = 4;
|
|
16371
|
+
const sorted = [...blocking].sort((a, b) => a.y + a.height / 2 - (b.y + b.height / 2));
|
|
16372
|
+
const merged = [];
|
|
16373
|
+
for (const r of sorted) {
|
|
16374
|
+
const lo = r.y - MERGE_SLOP;
|
|
16375
|
+
const hi = r.y + r.height + MERGE_SLOP;
|
|
16376
|
+
if (merged.length && lo <= merged[merged.length - 1][1]) {
|
|
16377
|
+
merged[merged.length - 1][1] = Math.max(merged[merged.length - 1][1], hi);
|
|
16378
|
+
} else {
|
|
16379
|
+
merged.push([lo, hi]);
|
|
16380
|
+
}
|
|
16381
|
+
}
|
|
16382
|
+
if (merged.length === 0) return targetY;
|
|
16383
|
+
const MIN_GAP = 10;
|
|
16384
|
+
const candidates = [
|
|
16385
|
+
merged[0][0] - margin,
|
|
16386
|
+
// above all blocking rects
|
|
16387
|
+
merged[merged.length - 1][1] + margin
|
|
16388
|
+
// below all blocking rects
|
|
16389
|
+
];
|
|
16390
|
+
for (let i = 0; i < merged.length - 1; i++) {
|
|
16391
|
+
const gapLo = merged[i][1];
|
|
16392
|
+
const gapHi = merged[i + 1][0];
|
|
16393
|
+
if (gapHi - gapLo >= MIN_GAP) {
|
|
16394
|
+
candidates.push((gapLo + gapHi) / 2);
|
|
16395
|
+
}
|
|
16396
|
+
}
|
|
16397
|
+
return candidates.reduce(
|
|
16398
|
+
(best, c) => Math.abs(c - targetY) < Math.abs(best - targetY) ? c : best,
|
|
16399
|
+
candidates[0]
|
|
16400
|
+
);
|
|
16401
|
+
}
|
|
16402
|
+
function segmentIntersectsRect(p1, p2, rect) {
|
|
16403
|
+
const { x: rx, y: ry, width: rw, height: rh } = rect;
|
|
16404
|
+
const rr = rx + rw;
|
|
16405
|
+
const rb = ry + rh;
|
|
16406
|
+
const inRect = (p) => p.x >= rx && p.x <= rr && p.y >= ry && p.y <= rb;
|
|
16407
|
+
if (inRect(p1) || inRect(p2)) return true;
|
|
16408
|
+
if (Math.max(p1.x, p2.x) < rx || Math.min(p1.x, p2.x) > rr) return false;
|
|
16409
|
+
if (Math.max(p1.y, p2.y) < ry || Math.min(p1.y, p2.y) > rb) return false;
|
|
16410
|
+
const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
|
|
16411
|
+
const crosses = (a, b) => {
|
|
16412
|
+
const d1 = cross(a, b, p1);
|
|
16413
|
+
const d2 = cross(a, b, p2);
|
|
16414
|
+
const d3 = cross(p1, p2, a);
|
|
16415
|
+
const d4 = cross(p1, p2, b);
|
|
16416
|
+
return (d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d3 > 0 && d4 < 0 || d3 < 0 && d4 > 0);
|
|
16417
|
+
};
|
|
16418
|
+
const tl = { x: rx, y: ry };
|
|
16419
|
+
const tr = { x: rr, y: ry };
|
|
16420
|
+
const br = { x: rr, y: rb };
|
|
16421
|
+
const bl = { x: rx, y: rb };
|
|
16422
|
+
return crosses(tl, tr) || crosses(tr, br) || crosses(br, bl) || crosses(bl, tl);
|
|
16423
|
+
}
|
|
16424
|
+
function curveIntersectsRect(sc, tc, rect, direction) {
|
|
16425
|
+
if (direction === "LR") {
|
|
16426
|
+
const midX = (sc.x + tc.x) / 2;
|
|
16427
|
+
const m1 = { x: midX, y: sc.y };
|
|
16428
|
+
const m2 = { x: midX, y: tc.y };
|
|
16429
|
+
return segmentIntersectsRect(sc, m1, rect) || segmentIntersectsRect(m1, m2, rect) || segmentIntersectsRect(m2, tc, rect);
|
|
16430
|
+
} else {
|
|
16431
|
+
const midY = (sc.y + tc.y) / 2;
|
|
16432
|
+
const m1 = { x: sc.x, y: midY };
|
|
16433
|
+
const m2 = { x: tc.x, y: midY };
|
|
16434
|
+
return segmentIntersectsRect(sc, m1, rect) || segmentIntersectsRect(m1, m2, rect) || segmentIntersectsRect(m2, tc, rect);
|
|
16435
|
+
}
|
|
16436
|
+
}
|
|
16437
|
+
function edgeWaypoints(source, target, groups, nodes, direction, margin = 30, srcExitPt, tgtEnterPt) {
|
|
16438
|
+
const sc = { x: source.x, y: source.y };
|
|
16439
|
+
const tc = { x: target.x, y: target.y };
|
|
16440
|
+
const isBackward = direction === "LR" ? tc.x < sc.x : tc.y < sc.y;
|
|
16441
|
+
if (isBackward) {
|
|
16442
|
+
if (direction === "LR") {
|
|
16443
|
+
const xBandObs = [];
|
|
16444
|
+
for (const g of groups) {
|
|
16445
|
+
if (g.x + g.width < tc.x - margin || g.x > sc.x + margin) continue;
|
|
16446
|
+
xBandObs.push({ x: g.x, y: g.y, width: g.width, height: g.height });
|
|
16447
|
+
}
|
|
16448
|
+
for (const n of nodes) {
|
|
16449
|
+
if (n.id === source.id || n.id === target.id) continue;
|
|
16450
|
+
const nLeft = n.x - n.width / 2;
|
|
16451
|
+
const nRight = n.x + n.width / 2;
|
|
16452
|
+
if (nRight < tc.x - margin || nLeft > sc.x + margin) continue;
|
|
16453
|
+
xBandObs.push({ x: nLeft, y: n.y - n.height / 2, width: n.width, height: n.height });
|
|
16454
|
+
}
|
|
16455
|
+
const midY = (sc.y + tc.y) / 2;
|
|
16456
|
+
const routeY2 = xBandObs.length > 0 ? findRoutingLane(xBandObs, midY, margin) : midY;
|
|
16457
|
+
const exitBorder = srcExitPt ?? nodeBorderPoint(source, { x: sc.x, y: routeY2 });
|
|
16458
|
+
const exitPt2 = { x: exitBorder.x, y: routeY2 };
|
|
16459
|
+
const enterPt2 = { x: tc.x, y: routeY2 };
|
|
16460
|
+
const tp2 = tgtEnterPt ?? nodeBorderPoint(target, enterPt2);
|
|
16461
|
+
return srcExitPt ? [srcExitPt, exitPt2, enterPt2, tp2] : [exitBorder, exitPt2, enterPt2, tp2];
|
|
16462
|
+
} else {
|
|
16463
|
+
const yBandObs = [];
|
|
16464
|
+
for (const g of groups) {
|
|
16465
|
+
if (g.y + g.height < tc.y - margin || g.y > sc.y + margin) continue;
|
|
16466
|
+
yBandObs.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 nTop = n.y - n.height / 2;
|
|
16471
|
+
const nBot = n.y + n.height / 2;
|
|
16472
|
+
if (nBot < tc.y - margin || nTop > sc.y + margin) continue;
|
|
16473
|
+
yBandObs.push({ x: n.x - n.width / 2, y: nTop, width: n.width, height: n.height });
|
|
16474
|
+
}
|
|
16475
|
+
const rotated = yBandObs.map((r) => ({ x: r.y, y: r.x, width: r.height, height: r.width }));
|
|
16476
|
+
const midX = (sc.x + tc.x) / 2;
|
|
16477
|
+
const routeX = rotated.length > 0 ? findRoutingLane(rotated, midX, margin) : midX;
|
|
16478
|
+
const exitPt2 = srcExitPt ?? { x: routeX, y: sc.y };
|
|
16479
|
+
const enterPt2 = { x: routeX, y: tc.y };
|
|
16480
|
+
return [
|
|
16481
|
+
srcExitPt ?? nodeBorderPoint(source, exitPt2),
|
|
16482
|
+
exitPt2,
|
|
16483
|
+
enterPt2,
|
|
16484
|
+
tgtEnterPt ?? nodeBorderPoint(target, enterPt2)
|
|
16485
|
+
];
|
|
16486
|
+
}
|
|
16487
|
+
}
|
|
16488
|
+
const blocking = [];
|
|
16489
|
+
const blockingGroupIds = /* @__PURE__ */ new Set();
|
|
16490
|
+
const pathSrc = srcExitPt ?? sc;
|
|
16491
|
+
const pathTgt = tgtEnterPt ?? tc;
|
|
16492
|
+
for (const g of groups) {
|
|
16493
|
+
if (g.id === source.groupId || g.id === target.groupId) continue;
|
|
16494
|
+
const gRect = { x: g.x, y: g.y, width: g.width, height: g.height };
|
|
16495
|
+
if (curveIntersectsRect(pathSrc, pathTgt, gRect, direction)) {
|
|
16496
|
+
blocking.push(gRect);
|
|
16497
|
+
blockingGroupIds.add(g.id);
|
|
16498
|
+
}
|
|
16499
|
+
}
|
|
16500
|
+
for (const n of nodes) {
|
|
16501
|
+
if (n.id === source.id || n.id === target.id) continue;
|
|
16502
|
+
if (n.groupId && (n.groupId === source.groupId || n.groupId === target.groupId)) continue;
|
|
16503
|
+
if (n.groupId && blockingGroupIds.has(n.groupId)) continue;
|
|
16504
|
+
const nodeRect = { x: n.x - n.width / 2, y: n.y - n.height / 2, width: n.width, height: n.height };
|
|
16505
|
+
if (curveIntersectsRect(pathSrc, pathTgt, nodeRect, direction)) {
|
|
16506
|
+
blocking.push(nodeRect);
|
|
16507
|
+
}
|
|
16508
|
+
}
|
|
16509
|
+
if (blocking.length === 0) {
|
|
16510
|
+
const sp = srcExitPt ?? nodeBorderPoint(source, tc);
|
|
16511
|
+
const tp2 = tgtEnterPt ?? nodeBorderPoint(target, sp);
|
|
16512
|
+
return [sp, tp2];
|
|
16513
|
+
}
|
|
16514
|
+
const obsLeft = Math.min(...blocking.map((o) => o.x));
|
|
16515
|
+
const obsRight = Math.max(...blocking.map((o) => o.x + o.width));
|
|
16516
|
+
const routeY = findRoutingLane(blocking, tc.y, margin);
|
|
16517
|
+
const exitX = direction === "LR" ? Math.max(sc.x, obsLeft - margin) : obsLeft - margin;
|
|
16518
|
+
const enterX = direction === "LR" ? Math.min(tc.x, obsRight + margin) : obsRight + margin;
|
|
16519
|
+
const exitPt = { x: exitX, y: routeY };
|
|
16520
|
+
const enterPt = { x: enterX, y: routeY };
|
|
16521
|
+
const tp = tgtEnterPt ?? nodeBorderPoint(target, enterPt);
|
|
16522
|
+
if (srcExitPt) {
|
|
16523
|
+
return [srcExitPt, exitPt, enterPt, tp];
|
|
16524
|
+
}
|
|
16525
|
+
return [nodeBorderPoint(source, exitPt), exitPt, enterPt, tp];
|
|
16526
|
+
}
|
|
15808
16527
|
function nodeBorderPoint(node, target) {
|
|
15809
16528
|
const hw = node.width / 2;
|
|
15810
16529
|
const hh = node.height / 2;
|
|
@@ -16088,33 +16807,29 @@ function renderGroups(svg, groups, palette, isDark) {
|
|
|
16088
16807
|
}
|
|
16089
16808
|
}
|
|
16090
16809
|
}
|
|
16091
|
-
function renderEdgePaths(svg, edges, nodes, palette, isDark, animate) {
|
|
16810
|
+
function renderEdgePaths(svg, edges, nodes, groups, palette, isDark, animate, direction) {
|
|
16092
16811
|
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
|
|
16093
16812
|
const maxRps = Math.max(...edges.map((e) => e.computedRps), 1);
|
|
16813
|
+
const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
|
|
16094
16814
|
for (const edge of edges) {
|
|
16095
16815
|
if (edge.points.length === 0) continue;
|
|
16096
16816
|
const targetNode = nodeMap.get(edge.targetId);
|
|
16097
16817
|
const sourceNode = nodeMap.get(edge.sourceId);
|
|
16098
16818
|
const color = edgeColor(edge, palette);
|
|
16099
16819
|
const strokeW = edgeWidth();
|
|
16100
|
-
|
|
16101
|
-
|
|
16102
|
-
|
|
16103
|
-
|
|
16104
|
-
|
|
16105
|
-
|
|
16106
|
-
|
|
16107
|
-
|
|
16108
|
-
|
|
16109
|
-
|
|
16110
|
-
|
|
16111
|
-
|
|
16112
|
-
|
|
16113
|
-
if (targetNode && pts.length > 0) {
|
|
16114
|
-
const bp = nodeBorderPoint(targetNode, pts[pts.length - 1]);
|
|
16115
|
-
pts = [...pts, bp];
|
|
16116
|
-
}
|
|
16117
|
-
const pathD = lineGenerator7(pts) ?? "";
|
|
16820
|
+
if (!sourceNode || !targetNode) continue;
|
|
16821
|
+
const key = `${edge.sourceId}:${edge.targetId}`;
|
|
16822
|
+
const pts = edgeWaypoints(
|
|
16823
|
+
sourceNode,
|
|
16824
|
+
targetNode,
|
|
16825
|
+
groups,
|
|
16826
|
+
nodes,
|
|
16827
|
+
direction,
|
|
16828
|
+
30,
|
|
16829
|
+
srcPts.get(key),
|
|
16830
|
+
tgtPts.get(key)
|
|
16831
|
+
);
|
|
16832
|
+
const pathD = buildPathD(pts, direction);
|
|
16118
16833
|
const edgeG = svg.append("g").attr("class", "infra-edge").attr("data-line-number", edge.lineNumber);
|
|
16119
16834
|
edgeG.append("path").attr("d", pathD).attr("fill", "none").attr("stroke", color).attr("stroke-width", strokeW);
|
|
16120
16835
|
if (animate && edge.computedRps > 0) {
|
|
@@ -16129,19 +16844,34 @@ function renderEdgePaths(svg, edges, nodes, palette, isDark, animate) {
|
|
|
16129
16844
|
}
|
|
16130
16845
|
}
|
|
16131
16846
|
}
|
|
16132
|
-
function renderEdgeLabels(svg, edges, palette, isDark, animate) {
|
|
16847
|
+
function renderEdgeLabels(svg, edges, nodes, groups, palette, isDark, animate, direction) {
|
|
16848
|
+
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
|
|
16849
|
+
const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
|
|
16133
16850
|
for (const edge of edges) {
|
|
16134
16851
|
if (edge.points.length === 0) continue;
|
|
16135
16852
|
if (!edge.label) continue;
|
|
16136
|
-
const
|
|
16137
|
-
const
|
|
16853
|
+
const sourceNode = nodeMap.get(edge.sourceId);
|
|
16854
|
+
const targetNode = nodeMap.get(edge.targetId);
|
|
16855
|
+
if (!sourceNode || !targetNode) continue;
|
|
16856
|
+
const key = `${edge.sourceId}:${edge.targetId}`;
|
|
16857
|
+
const wps = edgeWaypoints(
|
|
16858
|
+
sourceNode,
|
|
16859
|
+
targetNode,
|
|
16860
|
+
groups,
|
|
16861
|
+
nodes,
|
|
16862
|
+
direction,
|
|
16863
|
+
30,
|
|
16864
|
+
srcPts.get(key),
|
|
16865
|
+
tgtPts.get(key)
|
|
16866
|
+
);
|
|
16867
|
+
const midPt = wps[Math.floor(wps.length / 2)];
|
|
16138
16868
|
const labelText = edge.label;
|
|
16139
16869
|
const g = svg.append("g").attr("class", animate ? "infra-edge-label" : "");
|
|
16140
16870
|
const textWidth = labelText.length * 6.5 + 8;
|
|
16141
16871
|
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);
|
|
16142
16872
|
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);
|
|
16143
16873
|
if (animate) {
|
|
16144
|
-
const pathD =
|
|
16874
|
+
const pathD = buildPathD(wps, direction);
|
|
16145
16875
|
g.insert("path", ":first-child").attr("d", pathD).attr("fill", "none").attr("stroke", "transparent").attr("stroke-width", 20);
|
|
16146
16876
|
}
|
|
16147
16877
|
}
|
|
@@ -16551,7 +17281,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
16551
17281
|
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);
|
|
16552
17282
|
}
|
|
16553
17283
|
renderGroups(svg, layout.groups, palette, isDark);
|
|
16554
|
-
renderEdgePaths(svg, layout.edges, layout.nodes, palette, isDark, shouldAnimate);
|
|
17284
|
+
renderEdgePaths(svg, layout.edges, layout.nodes, layout.groups, palette, isDark, shouldAnimate, layout.direction);
|
|
16555
17285
|
const fanoutSourceIds = collectFanoutSourceIds(layout.edges);
|
|
16556
17286
|
const scaledGroupIds = new Set(
|
|
16557
17287
|
layout.groups.filter((g) => {
|
|
@@ -16563,7 +17293,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
16563
17293
|
if (shouldAnimate) {
|
|
16564
17294
|
renderRejectParticles(svg, layout.nodes);
|
|
16565
17295
|
}
|
|
16566
|
-
renderEdgeLabels(svg, layout.edges, palette, isDark, shouldAnimate);
|
|
17296
|
+
renderEdgeLabels(svg, layout.edges, layout.nodes, layout.groups, palette, isDark, shouldAnimate, layout.direction);
|
|
16567
17297
|
if (hasLegend) {
|
|
16568
17298
|
if (fixedLegend) {
|
|
16569
17299
|
const containerWidth = container.clientWidth || totalWidth;
|
|
@@ -16581,7 +17311,7 @@ function parseAndLayoutInfra(content) {
|
|
|
16581
17311
|
const layout = layoutInfra(computed);
|
|
16582
17312
|
return { parsed, computed, layout };
|
|
16583
17313
|
}
|
|
16584
|
-
var 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,
|
|
17314
|
+
var 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;
|
|
16585
17315
|
var init_renderer8 = __esm({
|
|
16586
17316
|
"src/infra/renderer.ts"() {
|
|
16587
17317
|
"use strict";
|
|
@@ -16625,7 +17355,6 @@ var init_renderer8 = __esm({
|
|
|
16625
17355
|
REJECT_DURATION_MAX = 3;
|
|
16626
17356
|
REJECT_COUNT_MIN = 1;
|
|
16627
17357
|
REJECT_COUNT_MAX = 3;
|
|
16628
|
-
lineGenerator7 = d3Shape7.line().x((d) => d.x).y((d) => d.y).curve(d3Shape7.curveBasis);
|
|
16629
17358
|
PROP_DISPLAY = {
|
|
16630
17359
|
"cache-hit": "cache hit",
|
|
16631
17360
|
"firewall-block": "firewall block",
|
|
@@ -16810,7 +17539,7 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
|
|
|
16810
17539
|
}
|
|
16811
17540
|
}
|
|
16812
17541
|
} else if (edge.points.length >= 2) {
|
|
16813
|
-
const pathD =
|
|
17542
|
+
const pathD = lineGenerator7(edge.points);
|
|
16814
17543
|
if (pathD) {
|
|
16815
17544
|
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");
|
|
16816
17545
|
}
|
|
@@ -16874,7 +17603,7 @@ function renderStateForExport(content, theme, palette) {
|
|
|
16874
17603
|
document.body.removeChild(container);
|
|
16875
17604
|
}
|
|
16876
17605
|
}
|
|
16877
|
-
var 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,
|
|
17606
|
+
var 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;
|
|
16878
17607
|
var init_state_renderer = __esm({
|
|
16879
17608
|
"src/graph/state-renderer.ts"() {
|
|
16880
17609
|
"use strict";
|
|
@@ -16894,7 +17623,7 @@ var init_state_renderer = __esm({
|
|
|
16894
17623
|
PSEUDOSTATE_RADIUS = 10;
|
|
16895
17624
|
STATE_CORNER_RADIUS = 10;
|
|
16896
17625
|
GROUP_EXTRA_PADDING2 = 12;
|
|
16897
|
-
|
|
17626
|
+
lineGenerator7 = d3Shape8.line().x((d) => d.x).y((d) => d.y).curve(d3Shape8.curveBasis);
|
|
16898
17627
|
}
|
|
16899
17628
|
});
|
|
16900
17629
|
|
|
@@ -18057,7 +18786,6 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
18057
18786
|
if (secY === void 0) continue;
|
|
18058
18787
|
const isCollapsed = collapsedSections?.has(sec.lineNumber) ?? false;
|
|
18059
18788
|
const lineColor = palette.textMuted;
|
|
18060
|
-
const HIT_AREA_HEIGHT = 36;
|
|
18061
18789
|
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));
|
|
18062
18790
|
const BAND_HEIGHT = 22;
|
|
18063
18791
|
const bandX = sectionLineX1 - 10;
|
|
@@ -19450,7 +20178,6 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
19450
20178
|
const positions = groupNodes.map((n) => yScale(n));
|
|
19451
20179
|
const minY = Math.min(...positions) - bandPad;
|
|
19452
20180
|
const maxY = Math.max(...positions) + bandPad;
|
|
19453
|
-
const bandColor = group.color ?? mutedColor;
|
|
19454
20181
|
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", () => {
|
|
19455
20182
|
if (onClickItem) onClickItem(group.lineNumber);
|
|
19456
20183
|
});
|
|
@@ -19494,7 +20221,6 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
19494
20221
|
const positions = groupNodes.map((n) => xScale(n));
|
|
19495
20222
|
const minX = Math.min(...positions) - bandPad;
|
|
19496
20223
|
const maxX = Math.max(...positions) + bandPad;
|
|
19497
|
-
const bandColor = group.color ?? mutedColor;
|
|
19498
20224
|
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", () => {
|
|
19499
20225
|
if (onClickItem) onClickItem(group.lineNumber);
|
|
19500
20226
|
});
|
|
@@ -19812,6 +20538,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19812
20538
|
const textColor = palette.text;
|
|
19813
20539
|
const mutedColor = palette.border;
|
|
19814
20540
|
const bgColor = palette.bg;
|
|
20541
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
19815
20542
|
const colors = getSeriesColors(palette);
|
|
19816
20543
|
const groupColorMap = /* @__PURE__ */ new Map();
|
|
19817
20544
|
timelineGroups.forEach((grp, i) => {
|
|
@@ -20073,7 +20800,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20073
20800
|
if (ev.endDate) {
|
|
20074
20801
|
const y2 = yScale(parseTimelineDate(ev.endDate));
|
|
20075
20802
|
const rectH = Math.max(y2 - y, 4);
|
|
20076
|
-
let fill2 = evColor;
|
|
20803
|
+
let fill2 = mix(evColor, bg, 30);
|
|
20077
20804
|
if (ev.uncertain) {
|
|
20078
20805
|
const gradientId = `uncertain-vg-${ev.lineNumber}`;
|
|
20079
20806
|
const defs = svg.select("defs").node() || svg.append("defs").node();
|
|
@@ -20081,13 +20808,13 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20081
20808
|
{ offset: "0%", opacity: 1 },
|
|
20082
20809
|
{ offset: "80%", opacity: 1 },
|
|
20083
20810
|
{ offset: "100%", opacity: 0 }
|
|
20084
|
-
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", laneColor).attr("stop-opacity", (d) => d.opacity);
|
|
20811
|
+
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(laneColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
|
|
20085
20812
|
fill2 = `url(#${gradientId})`;
|
|
20086
20813
|
}
|
|
20087
|
-
evG.append("rect").attr("x", laneCenter - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2);
|
|
20814
|
+
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);
|
|
20088
20815
|
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);
|
|
20089
20816
|
} else {
|
|
20090
|
-
evG.append("circle").attr("cx", laneCenter).attr("cy", y).attr("r", 4).attr("fill", evColor).attr("stroke",
|
|
20817
|
+
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);
|
|
20091
20818
|
evG.append("text").attr("x", laneCenter + 10).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
|
|
20092
20819
|
}
|
|
20093
20820
|
}
|
|
@@ -20180,7 +20907,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20180
20907
|
if (ev.endDate) {
|
|
20181
20908
|
const y2 = yScale(parseTimelineDate(ev.endDate));
|
|
20182
20909
|
const rectH = Math.max(y2 - y, 4);
|
|
20183
|
-
let fill2 = color;
|
|
20910
|
+
let fill2 = mix(color, bg, 30);
|
|
20184
20911
|
if (ev.uncertain) {
|
|
20185
20912
|
const gradientId = `uncertain-v-${ev.lineNumber}`;
|
|
20186
20913
|
const defs = svg.select("defs").node() || svg.append("defs").node();
|
|
@@ -20188,13 +20915,13 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20188
20915
|
{ offset: "0%", opacity: 1 },
|
|
20189
20916
|
{ offset: "80%", opacity: 1 },
|
|
20190
20917
|
{ offset: "100%", opacity: 0 }
|
|
20191
|
-
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", color).attr("stop-opacity", (d) => d.opacity);
|
|
20918
|
+
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
|
|
20192
20919
|
fill2 = `url(#${gradientId})`;
|
|
20193
20920
|
}
|
|
20194
|
-
evG.append("rect").attr("x", axisX - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2);
|
|
20921
|
+
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);
|
|
20195
20922
|
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);
|
|
20196
20923
|
} else {
|
|
20197
|
-
evG.append("circle").attr("cx", axisX).attr("cy", y).attr("r", 4).attr("fill", color).attr("stroke",
|
|
20924
|
+
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);
|
|
20198
20925
|
evG.append("text").attr("x", axisX + 16).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
|
|
20199
20926
|
}
|
|
20200
20927
|
evG.append("text").attr("x", axisX - 14).attr(
|
|
@@ -20345,7 +21072,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20345
21072
|
const rectW = Math.max(x2 - x, 4);
|
|
20346
21073
|
const estLabelWidth = ev.label.length * 7 + 16;
|
|
20347
21074
|
const labelFitsInside = rectW >= estLabelWidth;
|
|
20348
|
-
let fill2 = evColor;
|
|
21075
|
+
let fill2 = mix(evColor, bg, 30);
|
|
20349
21076
|
if (ev.uncertain) {
|
|
20350
21077
|
const gradientId = `uncertain-${ev.lineNumber}`;
|
|
20351
21078
|
const defs = svg.select("defs").node() || svg.append("defs").node();
|
|
@@ -20353,12 +21080,12 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20353
21080
|
{ offset: "0%", opacity: 1 },
|
|
20354
21081
|
{ offset: "80%", opacity: 1 },
|
|
20355
21082
|
{ offset: "100%", opacity: 0 }
|
|
20356
|
-
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", evColor).attr("stop-opacity", (d) => d.opacity);
|
|
21083
|
+
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(evColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
|
|
20357
21084
|
fill2 = `url(#${gradientId})`;
|
|
20358
21085
|
}
|
|
20359
|
-
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);
|
|
21086
|
+
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);
|
|
20360
21087
|
if (labelFitsInside) {
|
|
20361
|
-
evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill",
|
|
21088
|
+
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);
|
|
20362
21089
|
} else {
|
|
20363
21090
|
const wouldFlipLeft = x + rectW > innerWidth * 0.6;
|
|
20364
21091
|
const labelFitsLeft = x - 6 - estLabelWidth > 0;
|
|
@@ -20370,7 +21097,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20370
21097
|
const wouldFlipLeft = x > innerWidth * 0.6;
|
|
20371
21098
|
const labelFitsLeft = x - 10 - estLabelWidth > 0;
|
|
20372
21099
|
const flipLeft = wouldFlipLeft && labelFitsLeft;
|
|
20373
|
-
evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", evColor).attr("stroke",
|
|
21100
|
+
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);
|
|
20374
21101
|
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);
|
|
20375
21102
|
}
|
|
20376
21103
|
});
|
|
@@ -20483,7 +21210,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20483
21210
|
const rectW = Math.max(x2 - x, 4);
|
|
20484
21211
|
const estLabelWidth = ev.label.length * 7 + 16;
|
|
20485
21212
|
const labelFitsInside = rectW >= estLabelWidth;
|
|
20486
|
-
let fill2 = color;
|
|
21213
|
+
let fill2 = mix(color, bg, 30);
|
|
20487
21214
|
if (ev.uncertain) {
|
|
20488
21215
|
const gradientId = `uncertain-ts-${ev.lineNumber}`;
|
|
20489
21216
|
const defs = svg.select("defs").node() || svg.append("defs").node();
|
|
@@ -20491,12 +21218,12 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20491
21218
|
{ offset: "0%", opacity: 1 },
|
|
20492
21219
|
{ offset: "80%", opacity: 1 },
|
|
20493
21220
|
{ offset: "100%", opacity: 0 }
|
|
20494
|
-
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", color).attr("stop-opacity", (d) => d.opacity);
|
|
21221
|
+
]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
|
|
20495
21222
|
fill2 = `url(#${gradientId})`;
|
|
20496
21223
|
}
|
|
20497
|
-
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);
|
|
21224
|
+
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);
|
|
20498
21225
|
if (labelFitsInside) {
|
|
20499
|
-
evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill",
|
|
21226
|
+
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);
|
|
20500
21227
|
} else {
|
|
20501
21228
|
const wouldFlipLeft = x + rectW > innerWidth * 0.6;
|
|
20502
21229
|
const labelFitsLeft = x - 6 - estLabelWidth > 0;
|
|
@@ -20508,7 +21235,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20508
21235
|
const wouldFlipLeft = x > innerWidth * 0.6;
|
|
20509
21236
|
const labelFitsLeft = x - 10 - estLabelWidth > 0;
|
|
20510
21237
|
const flipLeft = wouldFlipLeft && labelFitsLeft;
|
|
20511
|
-
evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", color).attr("stroke",
|
|
21238
|
+
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);
|
|
20512
21239
|
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);
|
|
20513
21240
|
}
|
|
20514
21241
|
});
|
|
@@ -20663,8 +21390,8 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20663
21390
|
} else {
|
|
20664
21391
|
color = ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor;
|
|
20665
21392
|
}
|
|
20666
|
-
el.selectAll("rect").attr("fill", color);
|
|
20667
|
-
el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", color);
|
|
21393
|
+
el.selectAll("rect").attr("fill", mix(color, bg, 30)).attr("stroke", color);
|
|
21394
|
+
el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", mix(color, bg, 30)).attr("stroke", color);
|
|
20668
21395
|
});
|
|
20669
21396
|
};
|
|
20670
21397
|
var drawSwimlaneIcon = drawSwimlaneIcon2, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
|
|
@@ -21129,7 +21856,6 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
21129
21856
|
const init2 = initD3Chart(container, palette, exportDims);
|
|
21130
21857
|
if (!init2) return;
|
|
21131
21858
|
const { svg, width, height, textColor } = init2;
|
|
21132
|
-
const mutedColor = palette.textMuted;
|
|
21133
21859
|
const borderColor = palette.border;
|
|
21134
21860
|
const defaultColors = [
|
|
21135
21861
|
palette.colors.blue,
|
|
@@ -21153,13 +21879,17 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
21153
21879
|
const f = r.length === 3 ? r[0] + r[0] + r[1] + r[1] + r[2] + r[2] : r;
|
|
21154
21880
|
return [parseInt(f.substring(0, 2), 16), parseInt(f.substring(2, 4), 16), parseInt(f.substring(4, 6), 16)];
|
|
21155
21881
|
};
|
|
21156
|
-
const [ar, ag, ab] = parse(a), [br,
|
|
21882
|
+
const [ar, ag, ab] = parse(a), [br, bg2, bb] = parse(b), t = pct / 100;
|
|
21157
21883
|
const c = (x, y) => Math.round(x * t + y * (1 - t)).toString(16).padStart(2, "0");
|
|
21158
|
-
return `#${c(ar, br)}${c(ag,
|
|
21884
|
+
return `#${c(ar, br)}${c(ag, bg2)}${c(ab, bb)}`;
|
|
21159
21885
|
};
|
|
21160
|
-
const
|
|
21886
|
+
const bg = isDark ? palette.surface : palette.bg;
|
|
21887
|
+
const getQuadrantColor = (label, defaultIdx) => {
|
|
21161
21888
|
return label?.color ?? defaultColors[defaultIdx % defaultColors.length];
|
|
21162
21889
|
};
|
|
21890
|
+
const getQuadrantFill = (label, defaultIdx) => {
|
|
21891
|
+
return mixHex(getQuadrantColor(label, defaultIdx), bg, 30);
|
|
21892
|
+
};
|
|
21163
21893
|
const quadrantDefs = [
|
|
21164
21894
|
{
|
|
21165
21895
|
position: "top-left",
|
|
@@ -21210,12 +21940,11 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
21210
21940
|
// purple
|
|
21211
21941
|
}
|
|
21212
21942
|
];
|
|
21213
|
-
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",
|
|
21214
|
-
const contrastColor = "#ffffff";
|
|
21943
|
+
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);
|
|
21215
21944
|
const shadowColor = "rgba(0,0,0,0.4)";
|
|
21216
21945
|
const getQuadrantLabelColor = (d) => {
|
|
21217
|
-
const
|
|
21218
|
-
return mixHex("#000000",
|
|
21946
|
+
const color = getQuadrantColor(d.label, d.colorIdx);
|
|
21947
|
+
return mixHex("#000000", color, 40);
|
|
21219
21948
|
};
|
|
21220
21949
|
const LABEL_MAX_FONT = 48;
|
|
21221
21950
|
const LABEL_MIN_FONT = 14;
|
|
@@ -21356,7 +22085,7 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
21356
22085
|
const pointColor = quadDef?.label?.color ?? defaultColors[quadDef?.colorIdx ?? 0];
|
|
21357
22086
|
const pointG = pointsG.append("g").attr("class", "point-group").attr("data-line-number", String(point.lineNumber));
|
|
21358
22087
|
pointG.append("circle").attr("cx", cx).attr("cy", cy).attr("r", 6).attr("fill", "#ffffff").attr("stroke", pointColor).attr("stroke-width", 2);
|
|
21359
|
-
pointG.append("text").attr("x", cx).attr("y", cy - 10).attr("text-anchor", "middle").attr("fill",
|
|
22088
|
+
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);
|
|
21360
22089
|
const tipHtml = `<strong>${point.label}</strong><br>x: ${point.x.toFixed(2)}, y: ${point.y.toFixed(2)}`;
|
|
21361
22090
|
pointG.style("cursor", onClickItem ? "pointer" : "default").on("mouseenter", (event) => {
|
|
21362
22091
|
showTooltip(tooltip, tipHtml, event);
|
|
@@ -22629,6 +23358,34 @@ function decodeDiagramUrl(hash) {
|
|
|
22629
23358
|
}
|
|
22630
23359
|
}
|
|
22631
23360
|
|
|
23361
|
+
// src/completion.ts
|
|
23362
|
+
init_parser3();
|
|
23363
|
+
init_flowchart_parser();
|
|
23364
|
+
init_parser9();
|
|
23365
|
+
init_parser2();
|
|
23366
|
+
var registry = /* @__PURE__ */ new Map();
|
|
23367
|
+
function registerExtractor(kind, fn) {
|
|
23368
|
+
registry.set(kind, fn);
|
|
23369
|
+
}
|
|
23370
|
+
function extractDiagramSymbols(docText) {
|
|
23371
|
+
let chartType = null;
|
|
23372
|
+
for (const line10 of docText.split("\n")) {
|
|
23373
|
+
const m = line10.match(/^\s*chart\s*:\s*(.+)/i);
|
|
23374
|
+
if (m) {
|
|
23375
|
+
chartType = m[1].trim().toLowerCase();
|
|
23376
|
+
break;
|
|
23377
|
+
}
|
|
23378
|
+
}
|
|
23379
|
+
if (!chartType) return null;
|
|
23380
|
+
const fn = registry.get(chartType);
|
|
23381
|
+
if (!fn) return null;
|
|
23382
|
+
return fn(docText);
|
|
23383
|
+
}
|
|
23384
|
+
registerExtractor("er", extractSymbols3);
|
|
23385
|
+
registerExtractor("flowchart", extractSymbols);
|
|
23386
|
+
registerExtractor("infra", extractSymbols4);
|
|
23387
|
+
registerExtractor("class", extractSymbols2);
|
|
23388
|
+
|
|
22632
23389
|
// src/index.ts
|
|
22633
23390
|
init_branding();
|
|
22634
23391
|
export {
|
|
@@ -22660,6 +23417,7 @@ export {
|
|
|
22660
23417
|
contrastText,
|
|
22661
23418
|
decodeDiagramUrl,
|
|
22662
23419
|
encodeDiagramUrl,
|
|
23420
|
+
extractDiagramSymbols,
|
|
22663
23421
|
formatDateLabel,
|
|
22664
23422
|
formatDgmoError,
|
|
22665
23423
|
getAvailablePalettes,
|
|
@@ -22723,6 +23481,7 @@ export {
|
|
|
22723
23481
|
parseState,
|
|
22724
23482
|
parseTimelineDate,
|
|
22725
23483
|
parseVisualization,
|
|
23484
|
+
registerExtractor,
|
|
22726
23485
|
registerPalette,
|
|
22727
23486
|
render,
|
|
22728
23487
|
renderArcDiagram,
|