@diagrammo/dgmo 0.6.1 → 0.6.2
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 +76 -0
- package/dist/cli.cjs +160 -159
- package/dist/index.cjs +780 -147
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +780 -147
- package/dist/index.js.map +1 -1
- package/docs/ai-integration.md +33 -50
- package/package.json +4 -3
- package/src/c4/layout.ts +68 -5
- package/src/cli.ts +124 -2
- package/src/er/classify.ts +206 -0
- package/src/er/layout.ts +259 -94
- package/src/er/renderer.ts +231 -17
- package/src/infra/layout.ts +60 -13
- package/src/infra/renderer.ts +375 -32
- package/src/initiative-status/layout.ts +46 -30
- package/.claude/skills/dgmo-chart/SKILL.md +0 -141
- package/.claude/skills/dgmo-flowchart/SKILL.md +0 -61
- package/.claude/skills/dgmo-generate/SKILL.md +0 -59
- package/.claude/skills/dgmo-sequence/SKILL.md +0 -104
package/dist/index.cjs
CHANGED
|
@@ -10497,110 +10497,211 @@ function computeNodeDimensions2(table) {
|
|
|
10497
10497
|
const height = headerHeight + columnsHeight + (columnsHeight === 0 ? 4 : 0);
|
|
10498
10498
|
return { width, height, headerHeight, columnsHeight };
|
|
10499
10499
|
}
|
|
10500
|
+
function findConnectedComponents(tableIds, relationships) {
|
|
10501
|
+
const adj = /* @__PURE__ */ new Map();
|
|
10502
|
+
for (const id of tableIds) adj.set(id, /* @__PURE__ */ new Set());
|
|
10503
|
+
for (const rel of relationships) {
|
|
10504
|
+
adj.get(rel.source)?.add(rel.target);
|
|
10505
|
+
adj.get(rel.target)?.add(rel.source);
|
|
10506
|
+
}
|
|
10507
|
+
const visited = /* @__PURE__ */ new Set();
|
|
10508
|
+
const components = [];
|
|
10509
|
+
for (const id of tableIds) {
|
|
10510
|
+
if (visited.has(id)) continue;
|
|
10511
|
+
const comp = [];
|
|
10512
|
+
const queue = [id];
|
|
10513
|
+
while (queue.length > 0) {
|
|
10514
|
+
const cur = queue.shift();
|
|
10515
|
+
if (visited.has(cur)) continue;
|
|
10516
|
+
visited.add(cur);
|
|
10517
|
+
comp.push(cur);
|
|
10518
|
+
for (const nb of adj.get(cur) ?? []) {
|
|
10519
|
+
if (!visited.has(nb)) queue.push(nb);
|
|
10520
|
+
}
|
|
10521
|
+
}
|
|
10522
|
+
components.push(comp);
|
|
10523
|
+
}
|
|
10524
|
+
return components;
|
|
10525
|
+
}
|
|
10526
|
+
function layoutComponent(tables, rels, dimMap) {
|
|
10527
|
+
const nodePositions = /* @__PURE__ */ new Map();
|
|
10528
|
+
const edgePoints = /* @__PURE__ */ new Map();
|
|
10529
|
+
if (tables.length === 1) {
|
|
10530
|
+
const dims = dimMap.get(tables[0].id);
|
|
10531
|
+
nodePositions.set(tables[0].id, { x: dims.width / 2, y: dims.height / 2, ...dims });
|
|
10532
|
+
return { nodePositions, edgePoints, width: dims.width, height: dims.height };
|
|
10533
|
+
}
|
|
10534
|
+
const g = new import_dagre3.default.graphlib.Graph({ multigraph: true });
|
|
10535
|
+
g.setGraph({ rankdir: "LR", nodesep: 40, ranksep: 80, edgesep: 20 });
|
|
10536
|
+
g.setDefaultEdgeLabel(() => ({}));
|
|
10537
|
+
for (const table of tables) {
|
|
10538
|
+
const dims = dimMap.get(table.id);
|
|
10539
|
+
g.setNode(table.id, { width: dims.width, height: dims.height });
|
|
10540
|
+
}
|
|
10541
|
+
for (const rel of rels) {
|
|
10542
|
+
g.setEdge(rel.source, rel.target, { label: rel.label ?? "" }, String(rel.lineNumber));
|
|
10543
|
+
}
|
|
10544
|
+
import_dagre3.default.layout(g);
|
|
10545
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
10546
|
+
for (const table of tables) {
|
|
10547
|
+
const pos = g.node(table.id);
|
|
10548
|
+
const dims = dimMap.get(table.id);
|
|
10549
|
+
minX = Math.min(minX, pos.x - dims.width / 2);
|
|
10550
|
+
minY = Math.min(minY, pos.y - dims.height / 2);
|
|
10551
|
+
maxX = Math.max(maxX, pos.x + dims.width / 2);
|
|
10552
|
+
maxY = Math.max(maxY, pos.y + dims.height / 2);
|
|
10553
|
+
}
|
|
10554
|
+
for (const rel of rels) {
|
|
10555
|
+
const ed = g.edge(rel.source, rel.target, String(rel.lineNumber));
|
|
10556
|
+
for (const pt of ed?.points ?? []) {
|
|
10557
|
+
minX = Math.min(minX, pt.x);
|
|
10558
|
+
minY = Math.min(minY, pt.y);
|
|
10559
|
+
maxX = Math.max(maxX, pt.x);
|
|
10560
|
+
maxY = Math.max(maxY, pt.y);
|
|
10561
|
+
}
|
|
10562
|
+
if (rel.label && (ed?.points ?? []).length > 0) {
|
|
10563
|
+
const pts = ed.points;
|
|
10564
|
+
const mid = pts[Math.floor(pts.length / 2)];
|
|
10565
|
+
const hw = (rel.label.length * 7 + 8) / 2;
|
|
10566
|
+
minX = Math.min(minX, mid.x - hw);
|
|
10567
|
+
maxX = Math.max(maxX, mid.x + hw);
|
|
10568
|
+
}
|
|
10569
|
+
}
|
|
10570
|
+
for (const table of tables) {
|
|
10571
|
+
const pos = g.node(table.id);
|
|
10572
|
+
const dims = dimMap.get(table.id);
|
|
10573
|
+
nodePositions.set(table.id, {
|
|
10574
|
+
x: pos.x - minX,
|
|
10575
|
+
y: pos.y - minY,
|
|
10576
|
+
...dims
|
|
10577
|
+
});
|
|
10578
|
+
}
|
|
10579
|
+
for (const rel of rels) {
|
|
10580
|
+
const ed = g.edge(rel.source, rel.target, String(rel.lineNumber));
|
|
10581
|
+
edgePoints.set(
|
|
10582
|
+
rel.lineNumber,
|
|
10583
|
+
(ed?.points ?? []).map((pt) => ({ x: pt.x - minX, y: pt.y - minY }))
|
|
10584
|
+
);
|
|
10585
|
+
}
|
|
10586
|
+
return {
|
|
10587
|
+
nodePositions,
|
|
10588
|
+
edgePoints,
|
|
10589
|
+
width: Math.max(0, maxX - minX),
|
|
10590
|
+
height: Math.max(0, maxY - minY)
|
|
10591
|
+
};
|
|
10592
|
+
}
|
|
10593
|
+
function packComponents(items) {
|
|
10594
|
+
if (items.length === 0) return [];
|
|
10595
|
+
const sorted = [...items].sort((a, b) => {
|
|
10596
|
+
const aConnected = a.compIds.length > 1 ? 1 : 0;
|
|
10597
|
+
const bConnected = b.compIds.length > 1 ? 1 : 0;
|
|
10598
|
+
if (aConnected !== bConnected) return bConnected - aConnected;
|
|
10599
|
+
return b.compLayout.height - a.compLayout.height;
|
|
10600
|
+
});
|
|
10601
|
+
const totalArea = items.reduce(
|
|
10602
|
+
(s, c) => s + (c.compLayout.width || MIN_WIDTH2) * (c.compLayout.height || HEADER_BASE2),
|
|
10603
|
+
0
|
|
10604
|
+
);
|
|
10605
|
+
const targetW = Math.max(
|
|
10606
|
+
Math.sqrt(totalArea) * 1.5,
|
|
10607
|
+
sorted[0].compLayout.width
|
|
10608
|
+
// at least as wide as the widest component
|
|
10609
|
+
);
|
|
10610
|
+
const placements = [];
|
|
10611
|
+
let curX = 0;
|
|
10612
|
+
let curY = 0;
|
|
10613
|
+
let rowH = 0;
|
|
10614
|
+
for (const item of sorted) {
|
|
10615
|
+
const w = item.compLayout.width || MIN_WIDTH2;
|
|
10616
|
+
const h = item.compLayout.height || HEADER_BASE2;
|
|
10617
|
+
if (curX > 0 && curX + w > targetW) {
|
|
10618
|
+
curY += rowH + COMP_GAP;
|
|
10619
|
+
curX = 0;
|
|
10620
|
+
rowH = 0;
|
|
10621
|
+
}
|
|
10622
|
+
placements.push({ compIds: item.compIds, compLayout: item.compLayout, offsetX: curX, offsetY: curY });
|
|
10623
|
+
curX += w + COMP_GAP;
|
|
10624
|
+
rowH = Math.max(rowH, h);
|
|
10625
|
+
}
|
|
10626
|
+
return placements;
|
|
10627
|
+
}
|
|
10500
10628
|
function layoutERDiagram(parsed) {
|
|
10501
10629
|
if (parsed.tables.length === 0) {
|
|
10502
10630
|
return { nodes: [], edges: [], width: 0, height: 0 };
|
|
10503
10631
|
}
|
|
10504
|
-
const g = new import_dagre3.default.graphlib.Graph();
|
|
10505
|
-
g.setGraph({
|
|
10506
|
-
rankdir: "TB",
|
|
10507
|
-
nodesep: 60,
|
|
10508
|
-
ranksep: 80,
|
|
10509
|
-
edgesep: 20
|
|
10510
|
-
});
|
|
10511
|
-
g.setDefaultEdgeLabel(() => ({}));
|
|
10512
10632
|
const dimMap = /* @__PURE__ */ new Map();
|
|
10513
10633
|
for (const table of parsed.tables) {
|
|
10514
|
-
|
|
10515
|
-
dimMap.set(table.id, dims);
|
|
10516
|
-
g.setNode(table.id, {
|
|
10517
|
-
label: table.name,
|
|
10518
|
-
width: dims.width,
|
|
10519
|
-
height: dims.height
|
|
10520
|
-
});
|
|
10634
|
+
dimMap.set(table.id, computeNodeDimensions2(table));
|
|
10521
10635
|
}
|
|
10522
|
-
|
|
10523
|
-
|
|
10636
|
+
const compIdSets = findConnectedComponents(
|
|
10637
|
+
parsed.tables.map((t) => t.id),
|
|
10638
|
+
parsed.relationships
|
|
10639
|
+
);
|
|
10640
|
+
const tableById = new Map(parsed.tables.map((t) => [t.id, t]));
|
|
10641
|
+
const componentItems = compIdSets.map((ids) => {
|
|
10642
|
+
const tables = ids.map((id) => tableById.get(id));
|
|
10643
|
+
const rels = parsed.relationships.filter((r) => ids.includes(r.source));
|
|
10644
|
+
return { compIds: ids, compLayout: layoutComponent(tables, rels, dimMap) };
|
|
10645
|
+
});
|
|
10646
|
+
const packed = packComponents(componentItems);
|
|
10647
|
+
const placementByTableId = /* @__PURE__ */ new Map();
|
|
10648
|
+
for (const p of packed) {
|
|
10649
|
+
for (const id of p.compIds) placementByTableId.set(id, p);
|
|
10650
|
+
}
|
|
10651
|
+
const placementByRelLine = /* @__PURE__ */ new Map();
|
|
10652
|
+
for (const p of packed) {
|
|
10653
|
+
for (const lineNum of p.compLayout.edgePoints.keys()) {
|
|
10654
|
+
placementByRelLine.set(lineNum, p);
|
|
10655
|
+
}
|
|
10524
10656
|
}
|
|
10525
|
-
import_dagre3.default.layout(g);
|
|
10526
10657
|
const layoutNodes = parsed.tables.map((table) => {
|
|
10527
|
-
const
|
|
10528
|
-
const
|
|
10658
|
+
const p = placementByTableId.get(table.id);
|
|
10659
|
+
const pos = p.compLayout.nodePositions.get(table.id);
|
|
10529
10660
|
return {
|
|
10530
10661
|
...table,
|
|
10531
|
-
x: pos.x,
|
|
10532
|
-
y: pos.y,
|
|
10533
|
-
width:
|
|
10534
|
-
height:
|
|
10535
|
-
headerHeight:
|
|
10536
|
-
columnsHeight:
|
|
10662
|
+
x: pos.x + p.offsetX + HALF_MARGIN,
|
|
10663
|
+
y: pos.y + p.offsetY + HALF_MARGIN,
|
|
10664
|
+
width: pos.width,
|
|
10665
|
+
height: pos.height,
|
|
10666
|
+
headerHeight: pos.headerHeight,
|
|
10667
|
+
columnsHeight: pos.columnsHeight
|
|
10537
10668
|
};
|
|
10538
10669
|
});
|
|
10539
10670
|
const layoutEdges = parsed.relationships.map((rel) => {
|
|
10540
|
-
const
|
|
10671
|
+
const p = placementByRelLine.get(rel.lineNumber);
|
|
10672
|
+
const pts = p?.compLayout.edgePoints.get(rel.lineNumber) ?? [];
|
|
10541
10673
|
return {
|
|
10542
10674
|
source: rel.source,
|
|
10543
10675
|
target: rel.target,
|
|
10544
10676
|
cardinality: rel.cardinality,
|
|
10545
|
-
points:
|
|
10677
|
+
points: pts.map((pt) => ({
|
|
10678
|
+
x: pt.x + (p?.offsetX ?? 0) + HALF_MARGIN,
|
|
10679
|
+
y: pt.y + (p?.offsetY ?? 0) + HALF_MARGIN
|
|
10680
|
+
})),
|
|
10546
10681
|
label: rel.label,
|
|
10547
10682
|
lineNumber: rel.lineNumber
|
|
10548
10683
|
};
|
|
10549
10684
|
});
|
|
10550
|
-
let minX = Infinity;
|
|
10551
|
-
let minY = Infinity;
|
|
10552
10685
|
let maxX = 0;
|
|
10553
10686
|
let maxY = 0;
|
|
10554
10687
|
for (const node of layoutNodes) {
|
|
10555
|
-
|
|
10556
|
-
|
|
10557
|
-
const top = node.y - node.height / 2;
|
|
10558
|
-
const bottom = node.y + node.height / 2;
|
|
10559
|
-
if (left < minX) minX = left;
|
|
10560
|
-
if (right > maxX) maxX = right;
|
|
10561
|
-
if (top < minY) minY = top;
|
|
10562
|
-
if (bottom > maxY) maxY = bottom;
|
|
10688
|
+
maxX = Math.max(maxX, node.x + node.width / 2);
|
|
10689
|
+
maxY = Math.max(maxY, node.y + node.height / 2);
|
|
10563
10690
|
}
|
|
10564
10691
|
for (const edge of layoutEdges) {
|
|
10565
10692
|
for (const pt of edge.points) {
|
|
10566
|
-
|
|
10567
|
-
|
|
10568
|
-
if (pt.y < minY) minY = pt.y;
|
|
10569
|
-
if (pt.y > maxY) maxY = pt.y;
|
|
10570
|
-
}
|
|
10571
|
-
if (edge.label && edge.points.length > 0) {
|
|
10572
|
-
const midPt = edge.points[Math.floor(edge.points.length / 2)];
|
|
10573
|
-
const labelHalfW = (edge.label.length * 7 + 8) / 2;
|
|
10574
|
-
if (midPt.x + labelHalfW > maxX) maxX = midPt.x + labelHalfW;
|
|
10575
|
-
if (midPt.x - labelHalfW < minX) minX = midPt.x - labelHalfW;
|
|
10693
|
+
maxX = Math.max(maxX, pt.x);
|
|
10694
|
+
maxY = Math.max(maxY, pt.y);
|
|
10576
10695
|
}
|
|
10577
10696
|
}
|
|
10578
|
-
const EDGE_MARGIN2 = 60;
|
|
10579
|
-
const HALF_MARGIN = EDGE_MARGIN2 / 2;
|
|
10580
|
-
const shiftX = -minX + HALF_MARGIN;
|
|
10581
|
-
const shiftY = -minY + HALF_MARGIN;
|
|
10582
|
-
for (const node of layoutNodes) {
|
|
10583
|
-
node.x += shiftX;
|
|
10584
|
-
node.y += shiftY;
|
|
10585
|
-
}
|
|
10586
|
-
for (const edge of layoutEdges) {
|
|
10587
|
-
for (const pt of edge.points) {
|
|
10588
|
-
pt.x += shiftX;
|
|
10589
|
-
pt.y += shiftY;
|
|
10590
|
-
}
|
|
10591
|
-
}
|
|
10592
|
-
maxX += shiftX;
|
|
10593
|
-
maxY += shiftY;
|
|
10594
|
-
const totalWidth = maxX + HALF_MARGIN;
|
|
10595
|
-
const totalHeight = maxY + HALF_MARGIN;
|
|
10596
10697
|
return {
|
|
10597
10698
|
nodes: layoutNodes,
|
|
10598
10699
|
edges: layoutEdges,
|
|
10599
|
-
width:
|
|
10600
|
-
height:
|
|
10700
|
+
width: maxX + HALF_MARGIN,
|
|
10701
|
+
height: maxY + HALF_MARGIN
|
|
10601
10702
|
};
|
|
10602
10703
|
}
|
|
10603
|
-
var import_dagre3, MIN_WIDTH2, CHAR_WIDTH4, PADDING_X2, HEADER_BASE2, MEMBER_LINE_HEIGHT3, COMPARTMENT_PADDING_Y3, SEPARATOR_HEIGHT2;
|
|
10704
|
+
var import_dagre3, MIN_WIDTH2, CHAR_WIDTH4, PADDING_X2, HEADER_BASE2, MEMBER_LINE_HEIGHT3, COMPARTMENT_PADDING_Y3, SEPARATOR_HEIGHT2, HALF_MARGIN, COMP_GAP;
|
|
10604
10705
|
var init_layout4 = __esm({
|
|
10605
10706
|
"src/er/layout.ts"() {
|
|
10606
10707
|
"use strict";
|
|
@@ -10612,6 +10713,135 @@ var init_layout4 = __esm({
|
|
|
10612
10713
|
MEMBER_LINE_HEIGHT3 = 18;
|
|
10613
10714
|
COMPARTMENT_PADDING_Y3 = 8;
|
|
10614
10715
|
SEPARATOR_HEIGHT2 = 1;
|
|
10716
|
+
HALF_MARGIN = 30;
|
|
10717
|
+
COMP_GAP = 60;
|
|
10718
|
+
}
|
|
10719
|
+
});
|
|
10720
|
+
|
|
10721
|
+
// src/er/classify.ts
|
|
10722
|
+
function classifyEREntities(tables, relationships) {
|
|
10723
|
+
const result = /* @__PURE__ */ new Map();
|
|
10724
|
+
if (tables.length === 0) return result;
|
|
10725
|
+
const indegreeMap = {};
|
|
10726
|
+
for (const t of tables) indegreeMap[t.id] = 0;
|
|
10727
|
+
for (const rel of relationships) {
|
|
10728
|
+
if (rel.source === rel.target) continue;
|
|
10729
|
+
if (rel.cardinality.from === "1" && rel.cardinality.to !== "1") {
|
|
10730
|
+
indegreeMap[rel.source] = (indegreeMap[rel.source] ?? 0) + 1;
|
|
10731
|
+
}
|
|
10732
|
+
if (rel.cardinality.to === "1" && rel.cardinality.from !== "1") {
|
|
10733
|
+
indegreeMap[rel.target] = (indegreeMap[rel.target] ?? 0) + 1;
|
|
10734
|
+
}
|
|
10735
|
+
}
|
|
10736
|
+
const tableStarNeighbors = /* @__PURE__ */ new Map();
|
|
10737
|
+
for (const rel of relationships) {
|
|
10738
|
+
if (rel.source === rel.target) continue;
|
|
10739
|
+
if (rel.cardinality.from === "*") {
|
|
10740
|
+
if (!tableStarNeighbors.has(rel.source)) tableStarNeighbors.set(rel.source, /* @__PURE__ */ new Set());
|
|
10741
|
+
tableStarNeighbors.get(rel.source).add(rel.target);
|
|
10742
|
+
}
|
|
10743
|
+
if (rel.cardinality.to === "*") {
|
|
10744
|
+
if (!tableStarNeighbors.has(rel.target)) tableStarNeighbors.set(rel.target, /* @__PURE__ */ new Set());
|
|
10745
|
+
tableStarNeighbors.get(rel.target).add(rel.source);
|
|
10746
|
+
}
|
|
10747
|
+
}
|
|
10748
|
+
const mmParticipants = /* @__PURE__ */ new Set();
|
|
10749
|
+
for (const [id, neighbors] of tableStarNeighbors) {
|
|
10750
|
+
if (neighbors.size >= 2) mmParticipants.add(id);
|
|
10751
|
+
}
|
|
10752
|
+
const indegreeValues = Object.values(indegreeMap);
|
|
10753
|
+
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
10754
|
+
const variance = indegreeValues.reduce((a, b) => a + (b - mean) ** 2, 0) / indegreeValues.length;
|
|
10755
|
+
const stddev = Math.sqrt(variance);
|
|
10756
|
+
const sorted = [...indegreeValues].sort((a, b) => a - b);
|
|
10757
|
+
const median = sorted.length % 2 === 0 ? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2 : sorted[Math.floor(sorted.length / 2)];
|
|
10758
|
+
for (const table of tables) {
|
|
10759
|
+
const id = table.id;
|
|
10760
|
+
const cols = table.columns;
|
|
10761
|
+
const fkCols = cols.filter((c) => c.constraints.includes("fk"));
|
|
10762
|
+
const pkFkCols = cols.filter(
|
|
10763
|
+
(c) => c.constraints.includes("pk") && c.constraints.includes("fk")
|
|
10764
|
+
);
|
|
10765
|
+
const fkCount = fkCols.length;
|
|
10766
|
+
const fkRatio = cols.length === 0 ? 0 : fkCount / cols.length;
|
|
10767
|
+
const indegree = indegreeMap[id] ?? 0;
|
|
10768
|
+
const nameLower = table.name.toLowerCase();
|
|
10769
|
+
const externalRels = relationships.filter(
|
|
10770
|
+
(r) => (r.source === id || r.target === id) && r.source !== r.target
|
|
10771
|
+
);
|
|
10772
|
+
const hasSelfRef = relationships.some((r) => r.source === id && r.target === id);
|
|
10773
|
+
const externalTargets = /* @__PURE__ */ new Set();
|
|
10774
|
+
for (const rel of externalRels) {
|
|
10775
|
+
externalTargets.add(rel.source === id ? rel.target : rel.source);
|
|
10776
|
+
}
|
|
10777
|
+
if (hasSelfRef && externalRels.length === 0) {
|
|
10778
|
+
result.set(id, "self-referential");
|
|
10779
|
+
continue;
|
|
10780
|
+
}
|
|
10781
|
+
const isInheritancePattern = pkFkCols.length >= 2 && externalTargets.size === 1;
|
|
10782
|
+
const junctionByRatio = fkRatio >= 0.6 && !isInheritancePattern;
|
|
10783
|
+
const junctionByCompositePk = pkFkCols.length >= 2 && externalTargets.size >= 2;
|
|
10784
|
+
const junctionByMm = mmParticipants.has(id);
|
|
10785
|
+
if (junctionByRatio || junctionByCompositePk || junctionByMm) {
|
|
10786
|
+
result.set(id, "junction");
|
|
10787
|
+
continue;
|
|
10788
|
+
}
|
|
10789
|
+
if (fkRatio >= 0.4 && fkRatio < 0.6 && pkFkCols.length < 2 && !mmParticipants.has(id)) {
|
|
10790
|
+
result.set(id, "ambiguous");
|
|
10791
|
+
continue;
|
|
10792
|
+
}
|
|
10793
|
+
const nameMatchesLookup = LOOKUP_NAME_SUFFIXES.some((s) => nameLower.endsWith(s));
|
|
10794
|
+
if (nameMatchesLookup && cols.length <= 6 && fkCount <= 1 && indegree > median) {
|
|
10795
|
+
result.set(id, "lookup");
|
|
10796
|
+
continue;
|
|
10797
|
+
}
|
|
10798
|
+
if (tables.length >= 6 && indegree > 0 && indegree > mean + 1.5 * stddev && indegree >= 2 * mean) {
|
|
10799
|
+
result.set(id, "hub");
|
|
10800
|
+
continue;
|
|
10801
|
+
}
|
|
10802
|
+
if (fkCount > 0) {
|
|
10803
|
+
result.set(id, "dependent");
|
|
10804
|
+
continue;
|
|
10805
|
+
}
|
|
10806
|
+
result.set(id, "core");
|
|
10807
|
+
}
|
|
10808
|
+
return result;
|
|
10809
|
+
}
|
|
10810
|
+
var ROLE_COLORS, ROLE_LABELS, ROLE_ORDER, LOOKUP_NAME_SUFFIXES;
|
|
10811
|
+
var init_classify = __esm({
|
|
10812
|
+
"src/er/classify.ts"() {
|
|
10813
|
+
"use strict";
|
|
10814
|
+
ROLE_COLORS = {
|
|
10815
|
+
core: "green",
|
|
10816
|
+
dependent: "blue",
|
|
10817
|
+
junction: "red",
|
|
10818
|
+
ambiguous: "purple",
|
|
10819
|
+
lookup: "yellow",
|
|
10820
|
+
hub: "orange",
|
|
10821
|
+
"self-referential": "teal",
|
|
10822
|
+
unclassified: "gray"
|
|
10823
|
+
};
|
|
10824
|
+
ROLE_LABELS = {
|
|
10825
|
+
core: "Core entity",
|
|
10826
|
+
dependent: "Dependent",
|
|
10827
|
+
junction: "Junction / M:M",
|
|
10828
|
+
ambiguous: "Bridge",
|
|
10829
|
+
lookup: "Lookup / Reference",
|
|
10830
|
+
hub: "Hub",
|
|
10831
|
+
"self-referential": "Self-referential",
|
|
10832
|
+
unclassified: "Unclassified"
|
|
10833
|
+
};
|
|
10834
|
+
ROLE_ORDER = [
|
|
10835
|
+
"core",
|
|
10836
|
+
"dependent",
|
|
10837
|
+
"junction",
|
|
10838
|
+
"ambiguous",
|
|
10839
|
+
"lookup",
|
|
10840
|
+
"hub",
|
|
10841
|
+
"self-referential",
|
|
10842
|
+
"unclassified"
|
|
10843
|
+
];
|
|
10844
|
+
LOOKUP_NAME_SUFFIXES = ["_type", "_status", "_code", "_category"];
|
|
10615
10845
|
}
|
|
10616
10846
|
});
|
|
10617
10847
|
|
|
@@ -10681,25 +10911,41 @@ function drawCardinality(g, point, prevPoint, cardinality, color, useLabels) {
|
|
|
10681
10911
|
g.append("line").attr("x1", bx + px * spread).attr("y1", by + py * spread).attr("x2", bx - px * spread).attr("y2", by - py * spread).attr("stroke", color).attr("stroke-width", sw);
|
|
10682
10912
|
}
|
|
10683
10913
|
}
|
|
10684
|
-
function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem, exportDims, activeTagGroup) {
|
|
10914
|
+
function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem, exportDims, activeTagGroup, semanticColorsActive) {
|
|
10685
10915
|
d3Selection5.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
10686
|
-
const
|
|
10687
|
-
const
|
|
10688
|
-
if (width <= 0 || height <= 0) return;
|
|
10916
|
+
const useSemanticColors = parsed.tagGroups.length === 0 && layout.nodes.every((n) => !n.color);
|
|
10917
|
+
const legendReserveH = useSemanticColors ? LEGEND_HEIGHT + DIAGRAM_PADDING5 : 0;
|
|
10689
10918
|
const titleHeight = parsed.title ? 40 : 0;
|
|
10690
10919
|
const diagramW = layout.width;
|
|
10691
10920
|
const diagramH = layout.height;
|
|
10692
|
-
const
|
|
10693
|
-
const
|
|
10694
|
-
|
|
10695
|
-
|
|
10696
|
-
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
10921
|
+
const naturalW = diagramW + DIAGRAM_PADDING5 * 2;
|
|
10922
|
+
const naturalH = diagramH + titleHeight + legendReserveH + DIAGRAM_PADDING5 * 2;
|
|
10923
|
+
let viewW;
|
|
10924
|
+
let viewH;
|
|
10925
|
+
let scale;
|
|
10926
|
+
let offsetX;
|
|
10927
|
+
let offsetY;
|
|
10928
|
+
if (exportDims) {
|
|
10929
|
+
viewW = exportDims.width ?? naturalW;
|
|
10930
|
+
viewH = exportDims.height ?? naturalH;
|
|
10931
|
+
const availH = viewH - titleHeight - legendReserveH;
|
|
10932
|
+
const scaleX = (viewW - DIAGRAM_PADDING5 * 2) / diagramW;
|
|
10933
|
+
const scaleY = (availH - DIAGRAM_PADDING5 * 2) / diagramH;
|
|
10934
|
+
scale = Math.min(MAX_SCALE4, scaleX, scaleY);
|
|
10935
|
+
const scaledW = diagramW * scale;
|
|
10936
|
+
offsetX = (viewW - scaledW) / 2;
|
|
10937
|
+
offsetY = titleHeight + DIAGRAM_PADDING5;
|
|
10938
|
+
} else {
|
|
10939
|
+
viewW = naturalW;
|
|
10940
|
+
viewH = naturalH;
|
|
10941
|
+
scale = 1;
|
|
10942
|
+
offsetX = DIAGRAM_PADDING5;
|
|
10943
|
+
offsetY = titleHeight + DIAGRAM_PADDING5;
|
|
10944
|
+
}
|
|
10945
|
+
if (viewW <= 0 || viewH <= 0) return;
|
|
10946
|
+
const svg = d3Selection5.select(container).append("svg").attr("width", exportDims ? viewW : "100%").attr("height", exportDims ? viewH : "100%").attr("viewBox", `0 0 ${viewW} ${viewH}`).attr("preserveAspectRatio", "xMidYMid meet").style("font-family", FONT_FAMILY);
|
|
10701
10947
|
if (parsed.title) {
|
|
10702
|
-
const titleEl = svg.append("text").attr("class", "chart-title").attr("x",
|
|
10948
|
+
const titleEl = svg.append("text").attr("class", "chart-title").attr("x", viewW / 2).attr("y", 30).attr("text-anchor", "middle").attr("fill", palette.text).attr("font-size", "20px").attr("font-weight", "700").style("cursor", onClickItem && parsed.titleLineNumber ? "pointer" : "default").text(parsed.title);
|
|
10703
10949
|
if (parsed.titleLineNumber) {
|
|
10704
10950
|
titleEl.attr("data-line-number", parsed.titleLineNumber);
|
|
10705
10951
|
if (onClickItem) {
|
|
@@ -10713,6 +10959,8 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10713
10959
|
}
|
|
10714
10960
|
const contentG = svg.append("g").attr("transform", `translate(${offsetX}, ${offsetY}) scale(${scale})`);
|
|
10715
10961
|
const seriesColors2 = getSeriesColors(palette);
|
|
10962
|
+
const semanticRoles = useSemanticColors ? classifyEREntities(parsed.tables, parsed.relationships) : null;
|
|
10963
|
+
const semanticActive = semanticRoles !== null && (semanticColorsActive ?? true);
|
|
10716
10964
|
const useLabels = parsed.options.notation === "labels";
|
|
10717
10965
|
for (const edge of layout.edges) {
|
|
10718
10966
|
if (edge.points.length < 2) continue;
|
|
@@ -10752,7 +11000,8 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10752
11000
|
for (let ni = 0; ni < layout.nodes.length; ni++) {
|
|
10753
11001
|
const node = layout.nodes[ni];
|
|
10754
11002
|
const tagColor = resolveTagColor(node.metadata, parsed.tagGroups, activeTagGroup ?? null);
|
|
10755
|
-
const
|
|
11003
|
+
const semanticColor = semanticActive ? palette.colors[ROLE_COLORS[semanticRoles.get(node.id) ?? "unclassified"]] : semanticRoles ? palette.primary : void 0;
|
|
11004
|
+
const nodeColor2 = node.color ?? tagColor ?? semanticColor ?? seriesColors2[ni % seriesColors2.length];
|
|
10756
11005
|
const nodeG = contentG.append("g").attr("transform", `translate(${node.x}, ${node.y})`).attr("class", "er-table").attr("data-line-number", String(node.lineNumber)).attr("data-node-id", node.id);
|
|
10757
11006
|
if (activeTagGroup) {
|
|
10758
11007
|
const tagKey = activeTagGroup.toLowerCase();
|
|
@@ -10761,6 +11010,10 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10761
11010
|
nodeG.attr(`data-tag-${tagKey}`, tagValue.toLowerCase());
|
|
10762
11011
|
}
|
|
10763
11012
|
}
|
|
11013
|
+
if (semanticRoles) {
|
|
11014
|
+
const role = semanticRoles.get(node.id);
|
|
11015
|
+
if (role) nodeG.attr("data-er-role", role);
|
|
11016
|
+
}
|
|
10764
11017
|
if (onClickItem) {
|
|
10765
11018
|
nodeG.style("cursor", "pointer").on("click", () => {
|
|
10766
11019
|
onClickItem(node.lineNumber);
|
|
@@ -10801,7 +11054,7 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10801
11054
|
legendG.attr("data-legend-active", activeTagGroup.toLowerCase());
|
|
10802
11055
|
}
|
|
10803
11056
|
let legendX = DIAGRAM_PADDING5;
|
|
10804
|
-
let legendY =
|
|
11057
|
+
let legendY = viewH - DIAGRAM_PADDING5;
|
|
10805
11058
|
for (const group of parsed.tagGroups) {
|
|
10806
11059
|
const groupG = legendG.append("g").attr("data-legend-group", group.name.toLowerCase());
|
|
10807
11060
|
const labelText = groupG.append("text").attr("x", legendX).attr("y", legendY + LEGEND_PILL_H / 2).attr("dominant-baseline", "central").attr("fill", palette.textMuted).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-family", FONT_FAMILY).text(`${group.name}:`);
|
|
@@ -10820,6 +11073,62 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10820
11073
|
legendX += LEGEND_GROUP_GAP;
|
|
10821
11074
|
}
|
|
10822
11075
|
}
|
|
11076
|
+
if (semanticRoles) {
|
|
11077
|
+
const presentRoles = ROLE_ORDER.filter((role) => {
|
|
11078
|
+
for (const r of semanticRoles.values()) {
|
|
11079
|
+
if (r === role) return true;
|
|
11080
|
+
}
|
|
11081
|
+
return false;
|
|
11082
|
+
});
|
|
11083
|
+
if (presentRoles.length > 0) {
|
|
11084
|
+
const measureLabelW = (text, fontSize) => {
|
|
11085
|
+
const dummy = svg.append("text").attr("font-size", fontSize).attr("font-family", FONT_FAMILY).attr("visibility", "hidden").text(text);
|
|
11086
|
+
const measured = dummy.node()?.getComputedTextLength?.() ?? 0;
|
|
11087
|
+
dummy.remove();
|
|
11088
|
+
return measured > 0 ? measured : text.length * fontSize * 0.6;
|
|
11089
|
+
};
|
|
11090
|
+
const labelWidths = /* @__PURE__ */ new Map();
|
|
11091
|
+
for (const role of presentRoles) {
|
|
11092
|
+
labelWidths.set(role, measureLabelW(ROLE_LABELS[role], LEGEND_ENTRY_FONT_SIZE));
|
|
11093
|
+
}
|
|
11094
|
+
const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
|
|
11095
|
+
const groupName = "Role";
|
|
11096
|
+
const pillWidth = groupName.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD;
|
|
11097
|
+
const pillH = LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2;
|
|
11098
|
+
let totalWidth;
|
|
11099
|
+
let entriesWidth = 0;
|
|
11100
|
+
if (semanticActive) {
|
|
11101
|
+
for (const role of presentRoles) {
|
|
11102
|
+
entriesWidth += LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + labelWidths.get(role) + LEGEND_ENTRY_TRAIL;
|
|
11103
|
+
}
|
|
11104
|
+
totalWidth = LEGEND_CAPSULE_PAD * 2 + pillWidth + LEGEND_ENTRY_TRAIL + entriesWidth;
|
|
11105
|
+
} else {
|
|
11106
|
+
totalWidth = pillWidth;
|
|
11107
|
+
}
|
|
11108
|
+
const legendX = (viewW - totalWidth) / 2;
|
|
11109
|
+
const legendY = viewH - DIAGRAM_PADDING5 - LEGEND_HEIGHT;
|
|
11110
|
+
const semanticLegendG = svg.append("g").attr("class", "er-semantic-legend").attr("data-legend-group", "role").attr("transform", `translate(${legendX}, ${legendY})`).style("cursor", "pointer");
|
|
11111
|
+
if (semanticActive) {
|
|
11112
|
+
semanticLegendG.append("rect").attr("width", totalWidth).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
|
|
11113
|
+
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);
|
|
11114
|
+
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);
|
|
11115
|
+
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);
|
|
11116
|
+
let entryX = LEGEND_CAPSULE_PAD + pillWidth + LEGEND_ENTRY_TRAIL;
|
|
11117
|
+
for (const role of presentRoles) {
|
|
11118
|
+
const label = ROLE_LABELS[role];
|
|
11119
|
+
const roleColor = palette.colors[ROLE_COLORS[role]];
|
|
11120
|
+
const entryG = semanticLegendG.append("g").attr("data-legend-entry", role);
|
|
11121
|
+
entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", roleColor);
|
|
11122
|
+
const textX = entryX + LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP;
|
|
11123
|
+
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);
|
|
11124
|
+
entryX = textX + labelWidths.get(role) + LEGEND_ENTRY_TRAIL;
|
|
11125
|
+
}
|
|
11126
|
+
} else {
|
|
11127
|
+
semanticLegendG.append("rect").attr("width", pillWidth).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
|
|
11128
|
+
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);
|
|
11129
|
+
}
|
|
11130
|
+
}
|
|
11131
|
+
}
|
|
10823
11132
|
}
|
|
10824
11133
|
function renderERDiagramForExport(content, theme, palette) {
|
|
10825
11134
|
const parsed = parseERDiagram(content, palette);
|
|
@@ -10869,6 +11178,7 @@ var init_renderer5 = __esm({
|
|
|
10869
11178
|
init_legend_constants();
|
|
10870
11179
|
init_parser3();
|
|
10871
11180
|
init_layout4();
|
|
11181
|
+
init_classify();
|
|
10872
11182
|
DIAGRAM_PADDING5 = 20;
|
|
10873
11183
|
MAX_SCALE4 = 3;
|
|
10874
11184
|
TABLE_FONT_SIZE = 13;
|
|
@@ -10996,9 +11306,10 @@ function layoutInitiativeStatus(parsed, collapseResult) {
|
|
|
10996
11306
|
const dagreEdge = g.edge(edge.source, edge.target, `e${i}`);
|
|
10997
11307
|
const dagrePoints = dagreEdge?.points ?? [];
|
|
10998
11308
|
const hasIntermediateRank = allNodeX.some((x) => x > src.x + 20 && x < tgt.x - 20);
|
|
10999
|
-
const step = Math.min((enterX - exitX) * 0.15, 20);
|
|
11309
|
+
const step = Math.max(0, Math.min((enterX - exitX) * 0.15, 20));
|
|
11000
11310
|
const isBackEdge = tgt.x < src.x - 5;
|
|
11001
|
-
const
|
|
11311
|
+
const isTopExit = !isBackEdge && tgt.x > src.x && !hasIntermediateRank && tgt.y < src.y - NODESEP;
|
|
11312
|
+
const isBottomExit = !isBackEdge && tgt.x > src.x && !hasIntermediateRank && tgt.y > src.y + NODESEP;
|
|
11002
11313
|
let points;
|
|
11003
11314
|
if (isBackEdge) {
|
|
11004
11315
|
const routeAbove = Math.min(src.y, tgt.y) > avgNodeY;
|
|
@@ -11008,31 +11319,44 @@ function layoutInitiativeStatus(parsed, collapseResult) {
|
|
|
11008
11319
|
const spreadDir = avgNodeX < rawMidX ? 1 : -1;
|
|
11009
11320
|
const unclamped = Math.abs(src.x - tgt.x) < NODE_WIDTH ? rawMidX + spreadDir * BACK_EDGE_MIN_SPREAD : rawMidX;
|
|
11010
11321
|
const midX = Math.min(src.x, Math.max(tgt.x, unclamped));
|
|
11322
|
+
const srcDepart = Math.max(midX + 1, src.x - TOP_EXIT_STEP);
|
|
11323
|
+
const tgtApproach = Math.min(midX - 1, tgt.x + TOP_EXIT_STEP);
|
|
11011
11324
|
if (routeAbove) {
|
|
11012
11325
|
const arcY = Math.min(src.y - srcHalfH, tgt.y - tgtHalfH) - BACK_EDGE_MARGIN;
|
|
11013
11326
|
points = [
|
|
11014
11327
|
{ x: src.x, y: src.y - srcHalfH },
|
|
11328
|
+
{ x: srcDepart, y: src.y - srcHalfH - TOP_EXIT_STEP },
|
|
11015
11329
|
{ x: midX, y: arcY },
|
|
11330
|
+
{ x: tgtApproach, y: tgt.y - tgtHalfH - TOP_EXIT_STEP },
|
|
11016
11331
|
{ x: tgt.x, y: tgt.y - tgtHalfH }
|
|
11017
11332
|
];
|
|
11018
11333
|
} else {
|
|
11019
11334
|
const arcY = Math.max(src.y + srcHalfH, tgt.y + tgtHalfH) + BACK_EDGE_MARGIN;
|
|
11020
11335
|
points = [
|
|
11021
11336
|
{ x: src.x, y: src.y + srcHalfH },
|
|
11337
|
+
{ x: srcDepart, y: src.y + srcHalfH + TOP_EXIT_STEP },
|
|
11022
11338
|
{ x: midX, y: arcY },
|
|
11339
|
+
{ x: tgtApproach, y: tgt.y + tgtHalfH + TOP_EXIT_STEP },
|
|
11023
11340
|
{ x: tgt.x, y: tgt.y + tgtHalfH }
|
|
11024
11341
|
];
|
|
11025
11342
|
}
|
|
11026
|
-
} else if (
|
|
11027
|
-
const exitY =
|
|
11028
|
-
const
|
|
11029
|
-
const spreadEntryY = tgt.y + yOffset;
|
|
11030
|
-
const midX = (spreadExitX + enterX) / 2;
|
|
11031
|
-
const midY = (exitY + spreadEntryY) / 2;
|
|
11343
|
+
} else if (isTopExit) {
|
|
11344
|
+
const exitY = src.y - src.height / 2;
|
|
11345
|
+
const p1x = Math.min(Math.max(src.x, src.x + yOffset + TOP_EXIT_STEP), (src.x + enterX) / 2 - 1);
|
|
11032
11346
|
points = [
|
|
11033
|
-
{ x:
|
|
11034
|
-
{ x:
|
|
11035
|
-
{ x: enterX, y:
|
|
11347
|
+
{ x: src.x, y: exitY },
|
|
11348
|
+
{ x: p1x, y: exitY - TOP_EXIT_STEP },
|
|
11349
|
+
{ x: enterX - step, y: tgt.y + yOffset },
|
|
11350
|
+
{ x: enterX, y: tgt.y }
|
|
11351
|
+
];
|
|
11352
|
+
} else if (isBottomExit) {
|
|
11353
|
+
const exitY = src.y + src.height / 2;
|
|
11354
|
+
const p1x = Math.min(Math.max(src.x, src.x + yOffset + TOP_EXIT_STEP), (src.x + enterX) / 2 - 1);
|
|
11355
|
+
points = [
|
|
11356
|
+
{ x: src.x, y: exitY },
|
|
11357
|
+
{ x: p1x, y: exitY + TOP_EXIT_STEP },
|
|
11358
|
+
{ x: enterX - step, y: tgt.y + yOffset },
|
|
11359
|
+
{ x: enterX, y: tgt.y }
|
|
11036
11360
|
];
|
|
11037
11361
|
} else if (tgt.x > src.x && !hasIntermediateRank) {
|
|
11038
11362
|
points = [
|
|
@@ -11129,7 +11453,7 @@ function layoutInitiativeStatus(parsed, collapseResult) {
|
|
|
11129
11453
|
totalHeight += 40;
|
|
11130
11454
|
return { nodes: layoutNodes, edges: layoutEdges, groups: layoutGroups, width: totalWidth, height: totalHeight };
|
|
11131
11455
|
}
|
|
11132
|
-
var import_dagre4, STATUS_PRIORITY, PHI, NODE_HEIGHT, NODE_WIDTH, GROUP_PADDING, NODESEP, RANKSEP, PARALLEL_SPACING, PARALLEL_EDGE_MARGIN, MAX_PARALLEL_EDGES, BACK_EDGE_MARGIN, BACK_EDGE_MIN_SPREAD, CHAR_WIDTH_RATIO, NODE_FONT_SIZE, NODE_TEXT_PADDING;
|
|
11456
|
+
var import_dagre4, STATUS_PRIORITY, PHI, NODE_HEIGHT, NODE_WIDTH, GROUP_PADDING, NODESEP, RANKSEP, PARALLEL_SPACING, PARALLEL_EDGE_MARGIN, MAX_PARALLEL_EDGES, BACK_EDGE_MARGIN, BACK_EDGE_MIN_SPREAD, TOP_EXIT_STEP, CHAR_WIDTH_RATIO, NODE_FONT_SIZE, NODE_TEXT_PADDING;
|
|
11133
11457
|
var init_layout5 = __esm({
|
|
11134
11458
|
"src/initiative-status/layout.ts"() {
|
|
11135
11459
|
"use strict";
|
|
@@ -11146,6 +11470,7 @@ var init_layout5 = __esm({
|
|
|
11146
11470
|
MAX_PARALLEL_EDGES = 5;
|
|
11147
11471
|
BACK_EDGE_MARGIN = 40;
|
|
11148
11472
|
BACK_EDGE_MIN_SPREAD = Math.round(NODE_WIDTH * 0.75);
|
|
11473
|
+
TOP_EXIT_STEP = 10;
|
|
11149
11474
|
CHAR_WIDTH_RATIO = 0.6;
|
|
11150
11475
|
NODE_FONT_SIZE = 13;
|
|
11151
11476
|
NODE_TEXT_PADDING = 12;
|
|
@@ -11644,7 +11969,7 @@ __export(layout_exports6, {
|
|
|
11644
11969
|
layoutC4Deployment: () => layoutC4Deployment,
|
|
11645
11970
|
rollUpContextRelationships: () => rollUpContextRelationships
|
|
11646
11971
|
});
|
|
11647
|
-
function computeEdgePenalty(edgeList, nodePositions, degrees) {
|
|
11972
|
+
function computeEdgePenalty(edgeList, nodePositions, degrees, nodeGeometry) {
|
|
11648
11973
|
let penalty = 0;
|
|
11649
11974
|
for (const edge of edgeList) {
|
|
11650
11975
|
const sx = nodePositions.get(edge.source);
|
|
@@ -11654,6 +11979,32 @@ function computeEdgePenalty(edgeList, nodePositions, degrees) {
|
|
|
11654
11979
|
const weight = Math.min(degrees.get(edge.source) ?? 1, degrees.get(edge.target) ?? 1);
|
|
11655
11980
|
penalty += dist * weight;
|
|
11656
11981
|
}
|
|
11982
|
+
if (nodeGeometry) {
|
|
11983
|
+
for (const edge of edgeList) {
|
|
11984
|
+
const geomA = nodeGeometry.get(edge.source);
|
|
11985
|
+
const geomB = nodeGeometry.get(edge.target);
|
|
11986
|
+
if (!geomA || !geomB) continue;
|
|
11987
|
+
const ax = nodePositions.get(edge.source) ?? 0;
|
|
11988
|
+
const bx = nodePositions.get(edge.target) ?? 0;
|
|
11989
|
+
const ay = geomA.y;
|
|
11990
|
+
const by = geomB.y;
|
|
11991
|
+
if (ay === by) continue;
|
|
11992
|
+
const edgeMinX = Math.min(ax, bx);
|
|
11993
|
+
const edgeMaxX = Math.max(ax, bx);
|
|
11994
|
+
const edgeMinY = Math.min(ay, by);
|
|
11995
|
+
const edgeMaxY = Math.max(ay, by);
|
|
11996
|
+
for (const [name, geomC] of nodeGeometry) {
|
|
11997
|
+
if (name === edge.source || name === edge.target) continue;
|
|
11998
|
+
const cx = nodePositions.get(name) ?? 0;
|
|
11999
|
+
const cy = geomC.y;
|
|
12000
|
+
const hw = geomC.width / 2;
|
|
12001
|
+
const hh = geomC.height / 2;
|
|
12002
|
+
if (cx + hw > edgeMinX && cx - hw < edgeMaxX && cy + hh > edgeMinY && cy - hh < edgeMaxY) {
|
|
12003
|
+
penalty += EDGE_NODE_COLLISION_WEIGHT;
|
|
12004
|
+
}
|
|
12005
|
+
}
|
|
12006
|
+
}
|
|
12007
|
+
}
|
|
11657
12008
|
return penalty;
|
|
11658
12009
|
}
|
|
11659
12010
|
function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
@@ -11663,6 +12014,11 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11663
12014
|
degrees.set(edge.source, (degrees.get(edge.source) ?? 0) + 1);
|
|
11664
12015
|
degrees.set(edge.target, (degrees.get(edge.target) ?? 0) + 1);
|
|
11665
12016
|
}
|
|
12017
|
+
const nodeGeometry = /* @__PURE__ */ new Map();
|
|
12018
|
+
for (const name of g.nodes()) {
|
|
12019
|
+
const pos = g.node(name);
|
|
12020
|
+
if (pos) nodeGeometry.set(name, { y: pos.y, width: pos.width, height: pos.height });
|
|
12021
|
+
}
|
|
11666
12022
|
const rankMap = /* @__PURE__ */ new Map();
|
|
11667
12023
|
for (const name of g.nodes()) {
|
|
11668
12024
|
const pos = g.node(name);
|
|
@@ -11705,7 +12061,7 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11705
12061
|
const pos = g.node(name);
|
|
11706
12062
|
if (pos) basePositions.set(name, pos.x);
|
|
11707
12063
|
}
|
|
11708
|
-
const currentPenalty = computeEdgePenalty(edgeList, basePositions, degrees);
|
|
12064
|
+
const currentPenalty = computeEdgePenalty(edgeList, basePositions, degrees, nodeGeometry);
|
|
11709
12065
|
let bestPerm = [...partition];
|
|
11710
12066
|
let bestPenalty = currentPenalty;
|
|
11711
12067
|
if (partition.length <= 8) {
|
|
@@ -11715,7 +12071,7 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11715
12071
|
for (let i = 0; i < perm.length; i++) {
|
|
11716
12072
|
testPositions.set(perm[i], xSlots[i]);
|
|
11717
12073
|
}
|
|
11718
|
-
const penalty = computeEdgePenalty(edgeList, testPositions, degrees);
|
|
12074
|
+
const penalty = computeEdgePenalty(edgeList, testPositions, degrees, nodeGeometry);
|
|
11719
12075
|
if (penalty < bestPenalty) {
|
|
11720
12076
|
bestPenalty = penalty;
|
|
11721
12077
|
bestPerm = [...perm];
|
|
@@ -11733,13 +12089,13 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11733
12089
|
for (let k = 0; k < workingOrder.length; k++) {
|
|
11734
12090
|
testPositions.set(workingOrder[k], xSlots[k]);
|
|
11735
12091
|
}
|
|
11736
|
-
const before = computeEdgePenalty(edgeList, testPositions, degrees);
|
|
12092
|
+
const before = computeEdgePenalty(edgeList, testPositions, degrees, nodeGeometry);
|
|
11737
12093
|
[workingOrder[i], workingOrder[i + 1]] = [workingOrder[i + 1], workingOrder[i]];
|
|
11738
12094
|
const testPositions2 = new Map(basePositions);
|
|
11739
12095
|
for (let k = 0; k < workingOrder.length; k++) {
|
|
11740
12096
|
testPositions2.set(workingOrder[k], xSlots[k]);
|
|
11741
12097
|
}
|
|
11742
|
-
const after = computeEdgePenalty(edgeList, testPositions2, degrees);
|
|
12098
|
+
const after = computeEdgePenalty(edgeList, testPositions2, degrees, nodeGeometry);
|
|
11743
12099
|
if (after < before) {
|
|
11744
12100
|
improved = true;
|
|
11745
12101
|
if (after < bestPenalty) {
|
|
@@ -11978,7 +12334,7 @@ function computeLegendGroups3(tagGroups) {
|
|
|
11978
12334
|
const nameW = group.name.length * LEGEND_PILL_FONT_W4 + LEGEND_PILL_PAD4 * 2;
|
|
11979
12335
|
let capsuleW = LEGEND_CAPSULE_PAD4;
|
|
11980
12336
|
for (const e of entries) {
|
|
11981
|
-
capsuleW += LEGEND_DOT_R4 * 2 + LEGEND_ENTRY_DOT_GAP4 + e.value.length *
|
|
12337
|
+
capsuleW += LEGEND_DOT_R4 * 2 + LEGEND_ENTRY_DOT_GAP4 + e.value.length * LEGEND_ENTRY_FONT_W5 + LEGEND_ENTRY_TRAIL4;
|
|
11982
12338
|
}
|
|
11983
12339
|
capsuleW += LEGEND_CAPSULE_PAD4;
|
|
11984
12340
|
result.push({
|
|
@@ -13059,7 +13415,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
|
|
|
13059
13415
|
}
|
|
13060
13416
|
return { nodes, edges, legend: legendGroups, groupBoundaries, width: totalWidth, height: totalHeight };
|
|
13061
13417
|
}
|
|
13062
|
-
var import_dagre5, CHAR_WIDTH5, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, DESC_LINE_HEIGHT, DESC_CHAR_WIDTH, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_CHAR_WIDTH, MARGIN3, BOUNDARY_PAD, GROUP_BOUNDARY_PAD, LEGEND_HEIGHT4, LEGEND_PILL_FONT_SIZE2, LEGEND_PILL_FONT_W4, LEGEND_PILL_PAD4, LEGEND_DOT_R4, LEGEND_ENTRY_FONT_SIZE2,
|
|
13418
|
+
var import_dagre5, CHAR_WIDTH5, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, DESC_LINE_HEIGHT, DESC_CHAR_WIDTH, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_CHAR_WIDTH, MARGIN3, BOUNDARY_PAD, GROUP_BOUNDARY_PAD, LEGEND_HEIGHT4, LEGEND_PILL_FONT_SIZE2, LEGEND_PILL_FONT_W4, LEGEND_PILL_PAD4, LEGEND_DOT_R4, LEGEND_ENTRY_FONT_SIZE2, LEGEND_ENTRY_FONT_W5, LEGEND_ENTRY_DOT_GAP4, LEGEND_ENTRY_TRAIL4, LEGEND_CAPSULE_PAD4, EDGE_NODE_COLLISION_WEIGHT, META_EXCLUDE_KEYS;
|
|
13063
13419
|
var init_layout6 = __esm({
|
|
13064
13420
|
"src/c4/layout.ts"() {
|
|
13065
13421
|
"use strict";
|
|
@@ -13085,10 +13441,11 @@ var init_layout6 = __esm({
|
|
|
13085
13441
|
LEGEND_PILL_PAD4 = 16;
|
|
13086
13442
|
LEGEND_DOT_R4 = 4;
|
|
13087
13443
|
LEGEND_ENTRY_FONT_SIZE2 = 10;
|
|
13088
|
-
|
|
13444
|
+
LEGEND_ENTRY_FONT_W5 = LEGEND_ENTRY_FONT_SIZE2 * 0.6;
|
|
13089
13445
|
LEGEND_ENTRY_DOT_GAP4 = 4;
|
|
13090
13446
|
LEGEND_ENTRY_TRAIL4 = 8;
|
|
13091
13447
|
LEGEND_CAPSULE_PAD4 = 4;
|
|
13448
|
+
EDGE_NODE_COLLISION_WEIGHT = 5e3;
|
|
13092
13449
|
META_EXCLUDE_KEYS = /* @__PURE__ */ new Set(["description", "tech", "technology", "is a"]);
|
|
13093
13450
|
}
|
|
13094
13451
|
});
|
|
@@ -15273,6 +15630,7 @@ var init_compute = __esm({
|
|
|
15273
15630
|
// src/infra/layout.ts
|
|
15274
15631
|
var layout_exports8 = {};
|
|
15275
15632
|
__export(layout_exports8, {
|
|
15633
|
+
fixEdgeWaypoints: () => fixEdgeWaypoints,
|
|
15276
15634
|
layoutInfra: () => layoutInfra,
|
|
15277
15635
|
separateGroups: () => separateGroups
|
|
15278
15636
|
});
|
|
@@ -15456,6 +15814,8 @@ function formatUptime(fraction) {
|
|
|
15456
15814
|
return `${pct.toFixed(1)}%`;
|
|
15457
15815
|
}
|
|
15458
15816
|
function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
15817
|
+
const groupDeltas = /* @__PURE__ */ new Map();
|
|
15818
|
+
let converged = false;
|
|
15459
15819
|
for (let iter = 0; iter < maxIterations; iter++) {
|
|
15460
15820
|
let anyOverlap = false;
|
|
15461
15821
|
for (let i = 0; i < groups.length; i++) {
|
|
@@ -15473,6 +15833,9 @@ function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
|
15473
15833
|
const groupToShift = aCenter <= bCenter ? gb : ga;
|
|
15474
15834
|
if (isLR) groupToShift.y += shift;
|
|
15475
15835
|
else groupToShift.x += shift;
|
|
15836
|
+
const prev = groupDeltas.get(groupToShift.id) ?? { dx: 0, dy: 0 };
|
|
15837
|
+
if (isLR) groupDeltas.set(groupToShift.id, { dx: prev.dx, dy: prev.dy + shift });
|
|
15838
|
+
else groupDeltas.set(groupToShift.id, { dx: prev.dx + shift, dy: prev.dy });
|
|
15476
15839
|
for (const node of nodes) {
|
|
15477
15840
|
if (node.groupId === groupToShift.id) {
|
|
15478
15841
|
if (isLR) node.y += shift;
|
|
@@ -15481,19 +15844,48 @@ function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
|
15481
15844
|
}
|
|
15482
15845
|
}
|
|
15483
15846
|
}
|
|
15484
|
-
if (!anyOverlap)
|
|
15847
|
+
if (!anyOverlap) {
|
|
15848
|
+
converged = true;
|
|
15849
|
+
break;
|
|
15850
|
+
}
|
|
15851
|
+
}
|
|
15852
|
+
if (!converged && maxIterations > 0) {
|
|
15853
|
+
console.warn(`separateGroups: hit maxIterations (${maxIterations}) without fully resolving all group overlaps`);
|
|
15854
|
+
}
|
|
15855
|
+
return groupDeltas;
|
|
15856
|
+
}
|
|
15857
|
+
function fixEdgeWaypoints(edges, nodes, groupDeltas) {
|
|
15858
|
+
if (groupDeltas.size === 0) return;
|
|
15859
|
+
const nodeToGroup = /* @__PURE__ */ new Map();
|
|
15860
|
+
for (const node of nodes) nodeToGroup.set(node.id, node.groupId);
|
|
15861
|
+
for (const edge of edges) {
|
|
15862
|
+
const srcGroup = nodeToGroup.get(edge.sourceId) ?? null;
|
|
15863
|
+
const tgtGroup = nodeToGroup.get(edge.targetId) ?? null;
|
|
15864
|
+
const srcDelta = srcGroup ? groupDeltas.get(srcGroup) : void 0;
|
|
15865
|
+
const tgtDelta = tgtGroup ? groupDeltas.get(tgtGroup) : void 0;
|
|
15866
|
+
if (!srcDelta && !tgtDelta) continue;
|
|
15867
|
+
if (srcDelta && tgtDelta && srcGroup !== tgtGroup) {
|
|
15868
|
+
edge.points = [];
|
|
15869
|
+
continue;
|
|
15870
|
+
}
|
|
15871
|
+
const delta = srcDelta ?? tgtDelta;
|
|
15872
|
+
for (const pt of edge.points) {
|
|
15873
|
+
pt.x += delta.dx;
|
|
15874
|
+
pt.y += delta.dy;
|
|
15875
|
+
}
|
|
15485
15876
|
}
|
|
15486
15877
|
}
|
|
15487
15878
|
function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
15488
15879
|
if (computed.nodes.length === 0) {
|
|
15489
|
-
return { nodes: [], edges: [], groups: [], options: {}, width: 0, height: 0 };
|
|
15880
|
+
return { nodes: [], edges: [], groups: [], options: {}, direction: computed.direction, width: 0, height: 0 };
|
|
15490
15881
|
}
|
|
15882
|
+
const isLR = computed.direction !== "TB";
|
|
15491
15883
|
const g = new import_dagre7.default.graphlib.Graph();
|
|
15492
15884
|
g.setGraph({
|
|
15493
15885
|
rankdir: computed.direction === "TB" ? "TB" : "LR",
|
|
15494
|
-
nodesep:
|
|
15495
|
-
ranksep:
|
|
15496
|
-
edgesep:
|
|
15886
|
+
nodesep: isLR ? 70 : 60,
|
|
15887
|
+
ranksep: isLR ? 150 : 120,
|
|
15888
|
+
edgesep: 30
|
|
15497
15889
|
});
|
|
15498
15890
|
g.setDefaultEdgeLabel(() => ({}));
|
|
15499
15891
|
const groupedNodeIds = /* @__PURE__ */ new Set();
|
|
@@ -15501,7 +15893,6 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
15501
15893
|
if (node.groupId) groupedNodeIds.add(node.id);
|
|
15502
15894
|
}
|
|
15503
15895
|
const GROUP_INFLATE = GROUP_PADDING3 * 2 + GROUP_HEADER_HEIGHT;
|
|
15504
|
-
const isLR = computed.direction !== "TB";
|
|
15505
15896
|
const widthMap = /* @__PURE__ */ new Map();
|
|
15506
15897
|
const heightMap = /* @__PURE__ */ new Map();
|
|
15507
15898
|
for (const node of computed.nodes) {
|
|
@@ -15636,7 +16027,8 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
15636
16027
|
lineNumber: group.lineNumber
|
|
15637
16028
|
};
|
|
15638
16029
|
});
|
|
15639
|
-
separateGroups(layoutGroups, layoutNodes, isLR);
|
|
16030
|
+
const groupDeltas = separateGroups(layoutGroups, layoutNodes, isLR);
|
|
16031
|
+
fixEdgeWaypoints(layoutEdges, layoutNodes, groupDeltas);
|
|
15640
16032
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
15641
16033
|
for (const node of layoutNodes) {
|
|
15642
16034
|
const left = node.x - node.width / 2;
|
|
@@ -15694,6 +16086,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
15694
16086
|
edges: layoutEdges,
|
|
15695
16087
|
groups: layoutGroups,
|
|
15696
16088
|
options: computed.options,
|
|
16089
|
+
direction: computed.direction,
|
|
15697
16090
|
width: totalWidth,
|
|
15698
16091
|
height: totalHeight
|
|
15699
16092
|
};
|
|
@@ -15736,23 +16129,23 @@ var init_layout8 = __esm({
|
|
|
15736
16129
|
]);
|
|
15737
16130
|
DISPLAY_NAMES = {
|
|
15738
16131
|
"cache-hit": "cache hit",
|
|
15739
|
-
"firewall-block": "
|
|
16132
|
+
"firewall-block": "firewall block",
|
|
15740
16133
|
"ratelimit-rps": "rate limit RPS",
|
|
15741
16134
|
"latency-ms": "latency",
|
|
15742
16135
|
"uptime": "uptime",
|
|
15743
16136
|
"instances": "instances",
|
|
15744
16137
|
"max-rps": "max RPS",
|
|
15745
|
-
"cb-error-threshold": "CB error",
|
|
15746
|
-
"cb-latency-threshold-ms": "CB latency",
|
|
16138
|
+
"cb-error-threshold": "CB error threshold",
|
|
16139
|
+
"cb-latency-threshold-ms": "CB latency threshold",
|
|
15747
16140
|
"concurrency": "concurrency",
|
|
15748
16141
|
"duration-ms": "duration",
|
|
15749
16142
|
"cold-start-ms": "cold start",
|
|
15750
16143
|
"buffer": "buffer",
|
|
15751
|
-
"drain-rate": "drain",
|
|
16144
|
+
"drain-rate": "drain rate",
|
|
15752
16145
|
"retention-hours": "retention",
|
|
15753
16146
|
"partitions": "partitions"
|
|
15754
16147
|
};
|
|
15755
|
-
GROUP_GAP =
|
|
16148
|
+
GROUP_GAP = GROUP_PADDING3 * 2 + GROUP_HEADER_HEIGHT;
|
|
15756
16149
|
}
|
|
15757
16150
|
});
|
|
15758
16151
|
|
|
@@ -15825,6 +16218,236 @@ function resolveNodeSlo(node, diagramOptions) {
|
|
|
15825
16218
|
if (availThreshold == null && latencyP90 == null) return null;
|
|
15826
16219
|
return { availThreshold, latencyP90, warningMargin };
|
|
15827
16220
|
}
|
|
16221
|
+
function buildPathD(pts, direction) {
|
|
16222
|
+
const gen = d3Shape7.line().x((d) => d.x).y((d) => d.y);
|
|
16223
|
+
if (pts.length <= 2) {
|
|
16224
|
+
gen.curve(direction === "TB" ? d3Shape7.curveBumpY : d3Shape7.curveBumpX);
|
|
16225
|
+
} else {
|
|
16226
|
+
gen.curve(d3Shape7.curveCatmullRom.alpha(0.5));
|
|
16227
|
+
}
|
|
16228
|
+
return gen(pts) ?? "";
|
|
16229
|
+
}
|
|
16230
|
+
function computePortPts(edges, nodeMap, direction) {
|
|
16231
|
+
const srcPts = /* @__PURE__ */ new Map();
|
|
16232
|
+
const tgtPts = /* @__PURE__ */ new Map();
|
|
16233
|
+
const PAD = 0.1;
|
|
16234
|
+
const activeEdges = edges.filter((e) => e.points.length > 0);
|
|
16235
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
16236
|
+
for (const e of activeEdges) {
|
|
16237
|
+
if (!bySource.has(e.sourceId)) bySource.set(e.sourceId, []);
|
|
16238
|
+
bySource.get(e.sourceId).push(e);
|
|
16239
|
+
}
|
|
16240
|
+
for (const [sourceId, es] of bySource) {
|
|
16241
|
+
if (es.length < 2) continue;
|
|
16242
|
+
const source = nodeMap.get(sourceId);
|
|
16243
|
+
if (!source) continue;
|
|
16244
|
+
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);
|
|
16245
|
+
const n = sorted.length;
|
|
16246
|
+
for (let i = 0; i < n; i++) {
|
|
16247
|
+
const frac = n === 1 ? 0.5 : PAD + (1 - 2 * PAD) * i / (n - 1);
|
|
16248
|
+
const { e, t } = sorted[i];
|
|
16249
|
+
const isBackward = direction === "LR" ? t.x < source.x : t.y < source.y;
|
|
16250
|
+
if (direction === "LR") {
|
|
16251
|
+
srcPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16252
|
+
x: isBackward ? source.x - source.width / 2 : source.x + source.width / 2,
|
|
16253
|
+
y: source.y - source.height / 2 + frac * source.height
|
|
16254
|
+
});
|
|
16255
|
+
} else {
|
|
16256
|
+
srcPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16257
|
+
x: source.x - source.width / 2 + frac * source.width,
|
|
16258
|
+
y: isBackward ? source.y - source.height / 2 : source.y + source.height / 2
|
|
16259
|
+
});
|
|
16260
|
+
}
|
|
16261
|
+
}
|
|
16262
|
+
}
|
|
16263
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
16264
|
+
for (const e of activeEdges) {
|
|
16265
|
+
if (!byTarget.has(e.targetId)) byTarget.set(e.targetId, []);
|
|
16266
|
+
byTarget.get(e.targetId).push(e);
|
|
16267
|
+
}
|
|
16268
|
+
for (const [targetId, es] of byTarget) {
|
|
16269
|
+
if (es.length < 2) continue;
|
|
16270
|
+
const target = nodeMap.get(targetId);
|
|
16271
|
+
if (!target) continue;
|
|
16272
|
+
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);
|
|
16273
|
+
const n = sorted.length;
|
|
16274
|
+
for (let i = 0; i < n; i++) {
|
|
16275
|
+
const frac = n === 1 ? 0.5 : PAD + (1 - 2 * PAD) * i / (n - 1);
|
|
16276
|
+
const { e, s } = sorted[i];
|
|
16277
|
+
const isBackward = direction === "LR" ? target.x < s.x : target.y < s.y;
|
|
16278
|
+
if (direction === "LR") {
|
|
16279
|
+
tgtPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16280
|
+
x: isBackward ? target.x + target.width / 2 : target.x - target.width / 2,
|
|
16281
|
+
y: target.y - target.height / 2 + frac * target.height
|
|
16282
|
+
});
|
|
16283
|
+
} else {
|
|
16284
|
+
tgtPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16285
|
+
x: target.x - target.width / 2 + frac * target.width,
|
|
16286
|
+
y: isBackward ? target.y + target.height / 2 : target.y - target.height / 2
|
|
16287
|
+
});
|
|
16288
|
+
}
|
|
16289
|
+
}
|
|
16290
|
+
}
|
|
16291
|
+
return { srcPts, tgtPts };
|
|
16292
|
+
}
|
|
16293
|
+
function findRoutingLane(blocking, targetY, margin) {
|
|
16294
|
+
const MERGE_SLOP = 4;
|
|
16295
|
+
const sorted = [...blocking].sort((a, b) => a.y + a.height / 2 - (b.y + b.height / 2));
|
|
16296
|
+
const merged = [];
|
|
16297
|
+
for (const r of sorted) {
|
|
16298
|
+
const lo = r.y - MERGE_SLOP;
|
|
16299
|
+
const hi = r.y + r.height + MERGE_SLOP;
|
|
16300
|
+
if (merged.length && lo <= merged[merged.length - 1][1]) {
|
|
16301
|
+
merged[merged.length - 1][1] = Math.max(merged[merged.length - 1][1], hi);
|
|
16302
|
+
} else {
|
|
16303
|
+
merged.push([lo, hi]);
|
|
16304
|
+
}
|
|
16305
|
+
}
|
|
16306
|
+
if (merged.length === 0) return targetY;
|
|
16307
|
+
const MIN_GAP = 10;
|
|
16308
|
+
const candidates = [
|
|
16309
|
+
merged[0][0] - margin,
|
|
16310
|
+
// above all blocking rects
|
|
16311
|
+
merged[merged.length - 1][1] + margin
|
|
16312
|
+
// below all blocking rects
|
|
16313
|
+
];
|
|
16314
|
+
for (let i = 0; i < merged.length - 1; i++) {
|
|
16315
|
+
const gapLo = merged[i][1];
|
|
16316
|
+
const gapHi = merged[i + 1][0];
|
|
16317
|
+
if (gapHi - gapLo >= MIN_GAP) {
|
|
16318
|
+
candidates.push((gapLo + gapHi) / 2);
|
|
16319
|
+
}
|
|
16320
|
+
}
|
|
16321
|
+
return candidates.reduce(
|
|
16322
|
+
(best, c) => Math.abs(c - targetY) < Math.abs(best - targetY) ? c : best,
|
|
16323
|
+
candidates[0]
|
|
16324
|
+
);
|
|
16325
|
+
}
|
|
16326
|
+
function segmentIntersectsRect(p1, p2, rect) {
|
|
16327
|
+
const { x: rx, y: ry, width: rw, height: rh } = rect;
|
|
16328
|
+
const rr = rx + rw;
|
|
16329
|
+
const rb = ry + rh;
|
|
16330
|
+
const inRect = (p) => p.x >= rx && p.x <= rr && p.y >= ry && p.y <= rb;
|
|
16331
|
+
if (inRect(p1) || inRect(p2)) return true;
|
|
16332
|
+
if (Math.max(p1.x, p2.x) < rx || Math.min(p1.x, p2.x) > rr) return false;
|
|
16333
|
+
if (Math.max(p1.y, p2.y) < ry || Math.min(p1.y, p2.y) > rb) return false;
|
|
16334
|
+
const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
|
|
16335
|
+
const crosses = (a, b) => {
|
|
16336
|
+
const d1 = cross(a, b, p1);
|
|
16337
|
+
const d2 = cross(a, b, p2);
|
|
16338
|
+
const d3 = cross(p1, p2, a);
|
|
16339
|
+
const d4 = cross(p1, p2, b);
|
|
16340
|
+
return (d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d3 > 0 && d4 < 0 || d3 < 0 && d4 > 0);
|
|
16341
|
+
};
|
|
16342
|
+
const tl = { x: rx, y: ry };
|
|
16343
|
+
const tr = { x: rr, y: ry };
|
|
16344
|
+
const br = { x: rr, y: rb };
|
|
16345
|
+
const bl = { x: rx, y: rb };
|
|
16346
|
+
return crosses(tl, tr) || crosses(tr, br) || crosses(br, bl) || crosses(bl, tl);
|
|
16347
|
+
}
|
|
16348
|
+
function curveIntersectsRect(sc, tc, rect, direction) {
|
|
16349
|
+
if (direction === "LR") {
|
|
16350
|
+
const midX = (sc.x + tc.x) / 2;
|
|
16351
|
+
const m1 = { x: midX, y: sc.y };
|
|
16352
|
+
const m2 = { x: midX, y: tc.y };
|
|
16353
|
+
return segmentIntersectsRect(sc, m1, rect) || segmentIntersectsRect(m1, m2, rect) || segmentIntersectsRect(m2, tc, rect);
|
|
16354
|
+
} else {
|
|
16355
|
+
const midY = (sc.y + tc.y) / 2;
|
|
16356
|
+
const m1 = { x: sc.x, y: midY };
|
|
16357
|
+
const m2 = { x: tc.x, y: midY };
|
|
16358
|
+
return segmentIntersectsRect(sc, m1, rect) || segmentIntersectsRect(m1, m2, rect) || segmentIntersectsRect(m2, tc, rect);
|
|
16359
|
+
}
|
|
16360
|
+
}
|
|
16361
|
+
function edgeWaypoints(source, target, groups, nodes, direction, margin = 30, srcExitPt, tgtEnterPt) {
|
|
16362
|
+
const sc = { x: source.x, y: source.y };
|
|
16363
|
+
const tc = { x: target.x, y: target.y };
|
|
16364
|
+
const isBackward = direction === "LR" ? tc.x < sc.x : tc.y < sc.y;
|
|
16365
|
+
if (isBackward) {
|
|
16366
|
+
if (direction === "LR") {
|
|
16367
|
+
const xBandObs = [];
|
|
16368
|
+
for (const g of groups) {
|
|
16369
|
+
if (g.x + g.width < tc.x - margin || g.x > sc.x + margin) continue;
|
|
16370
|
+
xBandObs.push({ x: g.x, y: g.y, width: g.width, height: g.height });
|
|
16371
|
+
}
|
|
16372
|
+
for (const n of nodes) {
|
|
16373
|
+
if (n.id === source.id || n.id === target.id) continue;
|
|
16374
|
+
const nLeft = n.x - n.width / 2;
|
|
16375
|
+
const nRight = n.x + n.width / 2;
|
|
16376
|
+
if (nRight < tc.x - margin || nLeft > sc.x + margin) continue;
|
|
16377
|
+
xBandObs.push({ x: nLeft, y: n.y - n.height / 2, width: n.width, height: n.height });
|
|
16378
|
+
}
|
|
16379
|
+
const midY = (sc.y + tc.y) / 2;
|
|
16380
|
+
const routeY2 = xBandObs.length > 0 ? findRoutingLane(xBandObs, midY, margin) : midY;
|
|
16381
|
+
const exitBorder = srcExitPt ?? nodeBorderPoint(source, { x: sc.x, y: routeY2 });
|
|
16382
|
+
const exitPt2 = { x: exitBorder.x, y: routeY2 };
|
|
16383
|
+
const enterPt2 = { x: tc.x, y: routeY2 };
|
|
16384
|
+
const tp2 = tgtEnterPt ?? nodeBorderPoint(target, enterPt2);
|
|
16385
|
+
return srcExitPt ? [srcExitPt, exitPt2, enterPt2, tp2] : [exitBorder, exitPt2, enterPt2, tp2];
|
|
16386
|
+
} else {
|
|
16387
|
+
const yBandObs = [];
|
|
16388
|
+
for (const g of groups) {
|
|
16389
|
+
if (g.y + g.height < tc.y - margin || g.y > sc.y + margin) continue;
|
|
16390
|
+
yBandObs.push({ x: g.x, y: g.y, width: g.width, height: g.height });
|
|
16391
|
+
}
|
|
16392
|
+
for (const n of nodes) {
|
|
16393
|
+
if (n.id === source.id || n.id === target.id) continue;
|
|
16394
|
+
const nTop = n.y - n.height / 2;
|
|
16395
|
+
const nBot = n.y + n.height / 2;
|
|
16396
|
+
if (nBot < tc.y - margin || nTop > sc.y + margin) continue;
|
|
16397
|
+
yBandObs.push({ x: n.x - n.width / 2, y: nTop, width: n.width, height: n.height });
|
|
16398
|
+
}
|
|
16399
|
+
const rotated = yBandObs.map((r) => ({ x: r.y, y: r.x, width: r.height, height: r.width }));
|
|
16400
|
+
const midX = (sc.x + tc.x) / 2;
|
|
16401
|
+
const routeX = rotated.length > 0 ? findRoutingLane(rotated, midX, margin) : midX;
|
|
16402
|
+
const exitPt2 = srcExitPt ?? { x: routeX, y: sc.y };
|
|
16403
|
+
const enterPt2 = { x: routeX, y: tc.y };
|
|
16404
|
+
return [
|
|
16405
|
+
srcExitPt ?? nodeBorderPoint(source, exitPt2),
|
|
16406
|
+
exitPt2,
|
|
16407
|
+
enterPt2,
|
|
16408
|
+
tgtEnterPt ?? nodeBorderPoint(target, enterPt2)
|
|
16409
|
+
];
|
|
16410
|
+
}
|
|
16411
|
+
}
|
|
16412
|
+
const blocking = [];
|
|
16413
|
+
const blockingGroupIds = /* @__PURE__ */ new Set();
|
|
16414
|
+
const pathSrc = srcExitPt ?? sc;
|
|
16415
|
+
const pathTgt = tgtEnterPt ?? tc;
|
|
16416
|
+
for (const g of groups) {
|
|
16417
|
+
if (g.id === source.groupId || g.id === target.groupId) continue;
|
|
16418
|
+
const gRect = { x: g.x, y: g.y, width: g.width, height: g.height };
|
|
16419
|
+
if (curveIntersectsRect(pathSrc, pathTgt, gRect, direction)) {
|
|
16420
|
+
blocking.push(gRect);
|
|
16421
|
+
blockingGroupIds.add(g.id);
|
|
16422
|
+
}
|
|
16423
|
+
}
|
|
16424
|
+
for (const n of nodes) {
|
|
16425
|
+
if (n.id === source.id || n.id === target.id) continue;
|
|
16426
|
+
if (n.groupId && (n.groupId === source.groupId || n.groupId === target.groupId)) continue;
|
|
16427
|
+
if (n.groupId && blockingGroupIds.has(n.groupId)) continue;
|
|
16428
|
+
const nodeRect = { x: n.x - n.width / 2, y: n.y - n.height / 2, width: n.width, height: n.height };
|
|
16429
|
+
if (curveIntersectsRect(pathSrc, pathTgt, nodeRect, direction)) {
|
|
16430
|
+
blocking.push(nodeRect);
|
|
16431
|
+
}
|
|
16432
|
+
}
|
|
16433
|
+
if (blocking.length === 0) {
|
|
16434
|
+
const sp = srcExitPt ?? nodeBorderPoint(source, tc);
|
|
16435
|
+
const tp2 = tgtEnterPt ?? nodeBorderPoint(target, sp);
|
|
16436
|
+
return [sp, tp2];
|
|
16437
|
+
}
|
|
16438
|
+
const obsLeft = Math.min(...blocking.map((o) => o.x));
|
|
16439
|
+
const obsRight = Math.max(...blocking.map((o) => o.x + o.width));
|
|
16440
|
+
const routeY = findRoutingLane(blocking, tc.y, margin);
|
|
16441
|
+
const exitX = direction === "LR" ? Math.max(sc.x, obsLeft - margin) : obsLeft - margin;
|
|
16442
|
+
const enterX = direction === "LR" ? Math.min(tc.x, obsRight + margin) : obsRight + margin;
|
|
16443
|
+
const exitPt = { x: exitX, y: routeY };
|
|
16444
|
+
const enterPt = { x: enterX, y: routeY };
|
|
16445
|
+
const tp = tgtEnterPt ?? nodeBorderPoint(target, enterPt);
|
|
16446
|
+
if (srcExitPt) {
|
|
16447
|
+
return [srcExitPt, exitPt, enterPt, tp];
|
|
16448
|
+
}
|
|
16449
|
+
return [nodeBorderPoint(source, exitPt), exitPt, enterPt, tp];
|
|
16450
|
+
}
|
|
15828
16451
|
function nodeBorderPoint(node, target) {
|
|
15829
16452
|
const hw = node.width / 2;
|
|
15830
16453
|
const hh = node.height / 2;
|
|
@@ -16108,33 +16731,29 @@ function renderGroups(svg, groups, palette, isDark) {
|
|
|
16108
16731
|
}
|
|
16109
16732
|
}
|
|
16110
16733
|
}
|
|
16111
|
-
function renderEdgePaths(svg, edges, nodes, palette, isDark, animate) {
|
|
16734
|
+
function renderEdgePaths(svg, edges, nodes, groups, palette, isDark, animate, direction) {
|
|
16112
16735
|
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
|
|
16113
16736
|
const maxRps = Math.max(...edges.map((e) => e.computedRps), 1);
|
|
16737
|
+
const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
|
|
16114
16738
|
for (const edge of edges) {
|
|
16115
16739
|
if (edge.points.length === 0) continue;
|
|
16116
16740
|
const targetNode = nodeMap.get(edge.targetId);
|
|
16117
16741
|
const sourceNode = nodeMap.get(edge.sourceId);
|
|
16118
16742
|
const color = edgeColor(edge, palette);
|
|
16119
16743
|
const strokeW = edgeWidth();
|
|
16120
|
-
|
|
16121
|
-
|
|
16122
|
-
|
|
16123
|
-
|
|
16124
|
-
|
|
16125
|
-
|
|
16126
|
-
|
|
16127
|
-
|
|
16128
|
-
|
|
16129
|
-
|
|
16130
|
-
|
|
16131
|
-
|
|
16132
|
-
|
|
16133
|
-
if (targetNode && pts.length > 0) {
|
|
16134
|
-
const bp = nodeBorderPoint(targetNode, pts[pts.length - 1]);
|
|
16135
|
-
pts = [...pts, bp];
|
|
16136
|
-
}
|
|
16137
|
-
const pathD = lineGenerator7(pts) ?? "";
|
|
16744
|
+
if (!sourceNode || !targetNode) continue;
|
|
16745
|
+
const key = `${edge.sourceId}:${edge.targetId}`;
|
|
16746
|
+
const pts = edgeWaypoints(
|
|
16747
|
+
sourceNode,
|
|
16748
|
+
targetNode,
|
|
16749
|
+
groups,
|
|
16750
|
+
nodes,
|
|
16751
|
+
direction,
|
|
16752
|
+
30,
|
|
16753
|
+
srcPts.get(key),
|
|
16754
|
+
tgtPts.get(key)
|
|
16755
|
+
);
|
|
16756
|
+
const pathD = buildPathD(pts, direction);
|
|
16138
16757
|
const edgeG = svg.append("g").attr("class", "infra-edge").attr("data-line-number", edge.lineNumber);
|
|
16139
16758
|
edgeG.append("path").attr("d", pathD).attr("fill", "none").attr("stroke", color).attr("stroke-width", strokeW);
|
|
16140
16759
|
if (animate && edge.computedRps > 0) {
|
|
@@ -16149,19 +16768,34 @@ function renderEdgePaths(svg, edges, nodes, palette, isDark, animate) {
|
|
|
16149
16768
|
}
|
|
16150
16769
|
}
|
|
16151
16770
|
}
|
|
16152
|
-
function renderEdgeLabels(svg, edges, palette, isDark, animate) {
|
|
16771
|
+
function renderEdgeLabels(svg, edges, nodes, groups, palette, isDark, animate, direction) {
|
|
16772
|
+
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
|
|
16773
|
+
const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
|
|
16153
16774
|
for (const edge of edges) {
|
|
16154
16775
|
if (edge.points.length === 0) continue;
|
|
16155
16776
|
if (!edge.label) continue;
|
|
16156
|
-
const
|
|
16157
|
-
const
|
|
16777
|
+
const sourceNode = nodeMap.get(edge.sourceId);
|
|
16778
|
+
const targetNode = nodeMap.get(edge.targetId);
|
|
16779
|
+
if (!sourceNode || !targetNode) continue;
|
|
16780
|
+
const key = `${edge.sourceId}:${edge.targetId}`;
|
|
16781
|
+
const wps = edgeWaypoints(
|
|
16782
|
+
sourceNode,
|
|
16783
|
+
targetNode,
|
|
16784
|
+
groups,
|
|
16785
|
+
nodes,
|
|
16786
|
+
direction,
|
|
16787
|
+
30,
|
|
16788
|
+
srcPts.get(key),
|
|
16789
|
+
tgtPts.get(key)
|
|
16790
|
+
);
|
|
16791
|
+
const midPt = wps[Math.floor(wps.length / 2)];
|
|
16158
16792
|
const labelText = edge.label;
|
|
16159
16793
|
const g = svg.append("g").attr("class", animate ? "infra-edge-label" : "");
|
|
16160
16794
|
const textWidth = labelText.length * 6.5 + 8;
|
|
16161
16795
|
g.append("rect").attr("x", midPt.x - textWidth / 2).attr("y", midPt.y - 8).attr("width", textWidth).attr("height", 16).attr("rx", 3).attr("fill", palette.bg).attr("opacity", 0.9);
|
|
16162
16796
|
g.append("text").attr("x", midPt.x).attr("y", midPt.y + 4).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).attr("font-size", EDGE_LABEL_FONT_SIZE7).attr("fill", palette.textMuted).text(labelText);
|
|
16163
16797
|
if (animate) {
|
|
16164
|
-
const pathD =
|
|
16798
|
+
const pathD = buildPathD(wps, direction);
|
|
16165
16799
|
g.insert("path", ":first-child").attr("d", pathD).attr("fill", "none").attr("stroke", "transparent").attr("stroke-width", 20);
|
|
16166
16800
|
}
|
|
16167
16801
|
}
|
|
@@ -16571,7 +17205,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
16571
17205
|
rootSvg.append("text").attr("class", "chart-title").attr("x", totalWidth / 2).attr("y", 28).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).attr("font-size", 18).attr("font-weight", "700").attr("fill", palette.text).attr("data-line-number", titleLineNumber != null ? titleLineNumber : "").text(title);
|
|
16572
17206
|
}
|
|
16573
17207
|
renderGroups(svg, layout.groups, palette, isDark);
|
|
16574
|
-
renderEdgePaths(svg, layout.edges, layout.nodes, palette, isDark, shouldAnimate);
|
|
17208
|
+
renderEdgePaths(svg, layout.edges, layout.nodes, layout.groups, palette, isDark, shouldAnimate, layout.direction);
|
|
16575
17209
|
const fanoutSourceIds = collectFanoutSourceIds(layout.edges);
|
|
16576
17210
|
const scaledGroupIds = new Set(
|
|
16577
17211
|
layout.groups.filter((g) => {
|
|
@@ -16583,7 +17217,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
16583
17217
|
if (shouldAnimate) {
|
|
16584
17218
|
renderRejectParticles(svg, layout.nodes);
|
|
16585
17219
|
}
|
|
16586
|
-
renderEdgeLabels(svg, layout.edges, palette, isDark, shouldAnimate);
|
|
17220
|
+
renderEdgeLabels(svg, layout.edges, layout.nodes, layout.groups, palette, isDark, shouldAnimate, layout.direction);
|
|
16587
17221
|
if (hasLegend) {
|
|
16588
17222
|
if (fixedLegend) {
|
|
16589
17223
|
const containerWidth = container.clientWidth || totalWidth;
|
|
@@ -16601,7 +17235,7 @@ function parseAndLayoutInfra(content) {
|
|
|
16601
17235
|
const layout = layoutInfra(computed);
|
|
16602
17236
|
return { parsed, computed, layout };
|
|
16603
17237
|
}
|
|
16604
|
-
var d3Selection9, d3Shape7, NODE_FONT_SIZE4, META_FONT_SIZE4, META_LINE_HEIGHT8, EDGE_LABEL_FONT_SIZE7, GROUP_LABEL_FONT_SIZE2, NODE_BORDER_RADIUS, EDGE_STROKE_WIDTH8, NODE_STROKE_WIDTH8, OVERLOAD_STROKE_WIDTH, ROLE_DOT_RADIUS, NODE_HEADER_HEIGHT2, NODE_SEPARATOR_GAP2, NODE_PAD_BOTTOM2, COLLAPSE_BAR_HEIGHT5, COLLAPSE_BAR_INSET2, LEGEND_FIXED_GAP3, COLOR_HEALTHY, COLOR_WARNING, COLOR_OVERLOADED, FLOW_SPEED_MIN, FLOW_SPEED_MAX, PARTICLE_R, PARTICLE_COUNT_MIN, PARTICLE_COUNT_MAX, NODE_PULSE_SPEED, NODE_PULSE_OVERLOAD, REJECT_PARTICLE_R, REJECT_DROP_DISTANCE, REJECT_DURATION_MIN, REJECT_DURATION_MAX, REJECT_COUNT_MIN, REJECT_COUNT_MAX,
|
|
17238
|
+
var d3Selection9, d3Shape7, NODE_FONT_SIZE4, META_FONT_SIZE4, META_LINE_HEIGHT8, EDGE_LABEL_FONT_SIZE7, GROUP_LABEL_FONT_SIZE2, NODE_BORDER_RADIUS, EDGE_STROKE_WIDTH8, NODE_STROKE_WIDTH8, OVERLOAD_STROKE_WIDTH, ROLE_DOT_RADIUS, NODE_HEADER_HEIGHT2, NODE_SEPARATOR_GAP2, NODE_PAD_BOTTOM2, COLLAPSE_BAR_HEIGHT5, COLLAPSE_BAR_INSET2, LEGEND_FIXED_GAP3, COLOR_HEALTHY, COLOR_WARNING, COLOR_OVERLOADED, FLOW_SPEED_MIN, FLOW_SPEED_MAX, PARTICLE_R, PARTICLE_COUNT_MIN, PARTICLE_COUNT_MAX, NODE_PULSE_SPEED, NODE_PULSE_OVERLOAD, REJECT_PARTICLE_R, REJECT_DROP_DISTANCE, REJECT_DURATION_MIN, REJECT_DURATION_MAX, REJECT_COUNT_MIN, REJECT_COUNT_MAX, PROP_DISPLAY, DESC_MAX_CHARS, RPS_FORMAT_KEYS, MS_FORMAT_KEYS, PCT_FORMAT_KEYS;
|
|
16605
17239
|
var init_renderer8 = __esm({
|
|
16606
17240
|
"src/infra/renderer.ts"() {
|
|
16607
17241
|
"use strict";
|
|
@@ -16647,7 +17281,6 @@ var init_renderer8 = __esm({
|
|
|
16647
17281
|
REJECT_DURATION_MAX = 3;
|
|
16648
17282
|
REJECT_COUNT_MIN = 1;
|
|
16649
17283
|
REJECT_COUNT_MAX = 3;
|
|
16650
|
-
lineGenerator7 = d3Shape7.line().x((d) => d.x).y((d) => d.y).curve(d3Shape7.curveBasis);
|
|
16651
17284
|
PROP_DISPLAY = {
|
|
16652
17285
|
"cache-hit": "cache hit",
|
|
16653
17286
|
"firewall-block": "firewall block",
|
|
@@ -16830,7 +17463,7 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
|
|
|
16830
17463
|
}
|
|
16831
17464
|
}
|
|
16832
17465
|
} else if (edge.points.length >= 2) {
|
|
16833
|
-
const pathD =
|
|
17466
|
+
const pathD = lineGenerator7(edge.points);
|
|
16834
17467
|
if (pathD) {
|
|
16835
17468
|
edgeG.append("path").attr("d", pathD).attr("fill", "none").attr("stroke", edgeColor2).attr("stroke-width", EDGE_STROKE_WIDTH9).attr("marker-end", `url(#${markerId})`).attr("class", "st-edge");
|
|
16836
17469
|
}
|
|
@@ -16894,7 +17527,7 @@ function renderStateForExport(content, theme, palette) {
|
|
|
16894
17527
|
document.body.removeChild(container);
|
|
16895
17528
|
}
|
|
16896
17529
|
}
|
|
16897
|
-
var d3Selection10, d3Shape8, DIAGRAM_PADDING9, MAX_SCALE8, NODE_FONT_SIZE5, EDGE_LABEL_FONT_SIZE8, GROUP_LABEL_FONT_SIZE3, EDGE_STROKE_WIDTH9, NODE_STROKE_WIDTH9, ARROWHEAD_W4, ARROWHEAD_H4, PSEUDOSTATE_RADIUS, STATE_CORNER_RADIUS, GROUP_EXTRA_PADDING2,
|
|
17530
|
+
var d3Selection10, d3Shape8, DIAGRAM_PADDING9, MAX_SCALE8, NODE_FONT_SIZE5, EDGE_LABEL_FONT_SIZE8, GROUP_LABEL_FONT_SIZE3, EDGE_STROKE_WIDTH9, NODE_STROKE_WIDTH9, ARROWHEAD_W4, ARROWHEAD_H4, PSEUDOSTATE_RADIUS, STATE_CORNER_RADIUS, GROUP_EXTRA_PADDING2, lineGenerator7;
|
|
16898
17531
|
var init_state_renderer = __esm({
|
|
16899
17532
|
"src/graph/state-renderer.ts"() {
|
|
16900
17533
|
"use strict";
|
|
@@ -16916,7 +17549,7 @@ var init_state_renderer = __esm({
|
|
|
16916
17549
|
PSEUDOSTATE_RADIUS = 10;
|
|
16917
17550
|
STATE_CORNER_RADIUS = 10;
|
|
16918
17551
|
GROUP_EXTRA_PADDING2 = 12;
|
|
16919
|
-
|
|
17552
|
+
lineGenerator7 = d3Shape8.line().x((d) => d.x).y((d) => d.y).curve(d3Shape8.curveBasis);
|
|
16920
17553
|
}
|
|
16921
17554
|
});
|
|
16922
17555
|
|