@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.js
CHANGED
|
@@ -10476,110 +10476,211 @@ function computeNodeDimensions2(table) {
|
|
|
10476
10476
|
const height = headerHeight + columnsHeight + (columnsHeight === 0 ? 4 : 0);
|
|
10477
10477
|
return { width, height, headerHeight, columnsHeight };
|
|
10478
10478
|
}
|
|
10479
|
+
function findConnectedComponents(tableIds, relationships) {
|
|
10480
|
+
const adj = /* @__PURE__ */ new Map();
|
|
10481
|
+
for (const id of tableIds) adj.set(id, /* @__PURE__ */ new Set());
|
|
10482
|
+
for (const rel of relationships) {
|
|
10483
|
+
adj.get(rel.source)?.add(rel.target);
|
|
10484
|
+
adj.get(rel.target)?.add(rel.source);
|
|
10485
|
+
}
|
|
10486
|
+
const visited = /* @__PURE__ */ new Set();
|
|
10487
|
+
const components = [];
|
|
10488
|
+
for (const id of tableIds) {
|
|
10489
|
+
if (visited.has(id)) continue;
|
|
10490
|
+
const comp = [];
|
|
10491
|
+
const queue = [id];
|
|
10492
|
+
while (queue.length > 0) {
|
|
10493
|
+
const cur = queue.shift();
|
|
10494
|
+
if (visited.has(cur)) continue;
|
|
10495
|
+
visited.add(cur);
|
|
10496
|
+
comp.push(cur);
|
|
10497
|
+
for (const nb of adj.get(cur) ?? []) {
|
|
10498
|
+
if (!visited.has(nb)) queue.push(nb);
|
|
10499
|
+
}
|
|
10500
|
+
}
|
|
10501
|
+
components.push(comp);
|
|
10502
|
+
}
|
|
10503
|
+
return components;
|
|
10504
|
+
}
|
|
10505
|
+
function layoutComponent(tables, rels, dimMap) {
|
|
10506
|
+
const nodePositions = /* @__PURE__ */ new Map();
|
|
10507
|
+
const edgePoints = /* @__PURE__ */ new Map();
|
|
10508
|
+
if (tables.length === 1) {
|
|
10509
|
+
const dims = dimMap.get(tables[0].id);
|
|
10510
|
+
nodePositions.set(tables[0].id, { x: dims.width / 2, y: dims.height / 2, ...dims });
|
|
10511
|
+
return { nodePositions, edgePoints, width: dims.width, height: dims.height };
|
|
10512
|
+
}
|
|
10513
|
+
const g = new dagre3.graphlib.Graph({ multigraph: true });
|
|
10514
|
+
g.setGraph({ rankdir: "LR", nodesep: 40, ranksep: 80, edgesep: 20 });
|
|
10515
|
+
g.setDefaultEdgeLabel(() => ({}));
|
|
10516
|
+
for (const table of tables) {
|
|
10517
|
+
const dims = dimMap.get(table.id);
|
|
10518
|
+
g.setNode(table.id, { width: dims.width, height: dims.height });
|
|
10519
|
+
}
|
|
10520
|
+
for (const rel of rels) {
|
|
10521
|
+
g.setEdge(rel.source, rel.target, { label: rel.label ?? "" }, String(rel.lineNumber));
|
|
10522
|
+
}
|
|
10523
|
+
dagre3.layout(g);
|
|
10524
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
10525
|
+
for (const table of tables) {
|
|
10526
|
+
const pos = g.node(table.id);
|
|
10527
|
+
const dims = dimMap.get(table.id);
|
|
10528
|
+
minX = Math.min(minX, pos.x - dims.width / 2);
|
|
10529
|
+
minY = Math.min(minY, pos.y - dims.height / 2);
|
|
10530
|
+
maxX = Math.max(maxX, pos.x + dims.width / 2);
|
|
10531
|
+
maxY = Math.max(maxY, pos.y + dims.height / 2);
|
|
10532
|
+
}
|
|
10533
|
+
for (const rel of rels) {
|
|
10534
|
+
const ed = g.edge(rel.source, rel.target, String(rel.lineNumber));
|
|
10535
|
+
for (const pt of ed?.points ?? []) {
|
|
10536
|
+
minX = Math.min(minX, pt.x);
|
|
10537
|
+
minY = Math.min(minY, pt.y);
|
|
10538
|
+
maxX = Math.max(maxX, pt.x);
|
|
10539
|
+
maxY = Math.max(maxY, pt.y);
|
|
10540
|
+
}
|
|
10541
|
+
if (rel.label && (ed?.points ?? []).length > 0) {
|
|
10542
|
+
const pts = ed.points;
|
|
10543
|
+
const mid = pts[Math.floor(pts.length / 2)];
|
|
10544
|
+
const hw = (rel.label.length * 7 + 8) / 2;
|
|
10545
|
+
minX = Math.min(minX, mid.x - hw);
|
|
10546
|
+
maxX = Math.max(maxX, mid.x + hw);
|
|
10547
|
+
}
|
|
10548
|
+
}
|
|
10549
|
+
for (const table of tables) {
|
|
10550
|
+
const pos = g.node(table.id);
|
|
10551
|
+
const dims = dimMap.get(table.id);
|
|
10552
|
+
nodePositions.set(table.id, {
|
|
10553
|
+
x: pos.x - minX,
|
|
10554
|
+
y: pos.y - minY,
|
|
10555
|
+
...dims
|
|
10556
|
+
});
|
|
10557
|
+
}
|
|
10558
|
+
for (const rel of rels) {
|
|
10559
|
+
const ed = g.edge(rel.source, rel.target, String(rel.lineNumber));
|
|
10560
|
+
edgePoints.set(
|
|
10561
|
+
rel.lineNumber,
|
|
10562
|
+
(ed?.points ?? []).map((pt) => ({ x: pt.x - minX, y: pt.y - minY }))
|
|
10563
|
+
);
|
|
10564
|
+
}
|
|
10565
|
+
return {
|
|
10566
|
+
nodePositions,
|
|
10567
|
+
edgePoints,
|
|
10568
|
+
width: Math.max(0, maxX - minX),
|
|
10569
|
+
height: Math.max(0, maxY - minY)
|
|
10570
|
+
};
|
|
10571
|
+
}
|
|
10572
|
+
function packComponents(items) {
|
|
10573
|
+
if (items.length === 0) return [];
|
|
10574
|
+
const sorted = [...items].sort((a, b) => {
|
|
10575
|
+
const aConnected = a.compIds.length > 1 ? 1 : 0;
|
|
10576
|
+
const bConnected = b.compIds.length > 1 ? 1 : 0;
|
|
10577
|
+
if (aConnected !== bConnected) return bConnected - aConnected;
|
|
10578
|
+
return b.compLayout.height - a.compLayout.height;
|
|
10579
|
+
});
|
|
10580
|
+
const totalArea = items.reduce(
|
|
10581
|
+
(s, c) => s + (c.compLayout.width || MIN_WIDTH2) * (c.compLayout.height || HEADER_BASE2),
|
|
10582
|
+
0
|
|
10583
|
+
);
|
|
10584
|
+
const targetW = Math.max(
|
|
10585
|
+
Math.sqrt(totalArea) * 1.5,
|
|
10586
|
+
sorted[0].compLayout.width
|
|
10587
|
+
// at least as wide as the widest component
|
|
10588
|
+
);
|
|
10589
|
+
const placements = [];
|
|
10590
|
+
let curX = 0;
|
|
10591
|
+
let curY = 0;
|
|
10592
|
+
let rowH = 0;
|
|
10593
|
+
for (const item of sorted) {
|
|
10594
|
+
const w = item.compLayout.width || MIN_WIDTH2;
|
|
10595
|
+
const h = item.compLayout.height || HEADER_BASE2;
|
|
10596
|
+
if (curX > 0 && curX + w > targetW) {
|
|
10597
|
+
curY += rowH + COMP_GAP;
|
|
10598
|
+
curX = 0;
|
|
10599
|
+
rowH = 0;
|
|
10600
|
+
}
|
|
10601
|
+
placements.push({ compIds: item.compIds, compLayout: item.compLayout, offsetX: curX, offsetY: curY });
|
|
10602
|
+
curX += w + COMP_GAP;
|
|
10603
|
+
rowH = Math.max(rowH, h);
|
|
10604
|
+
}
|
|
10605
|
+
return placements;
|
|
10606
|
+
}
|
|
10479
10607
|
function layoutERDiagram(parsed) {
|
|
10480
10608
|
if (parsed.tables.length === 0) {
|
|
10481
10609
|
return { nodes: [], edges: [], width: 0, height: 0 };
|
|
10482
10610
|
}
|
|
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
10611
|
const dimMap = /* @__PURE__ */ new Map();
|
|
10492
10612
|
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
|
-
});
|
|
10613
|
+
dimMap.set(table.id, computeNodeDimensions2(table));
|
|
10500
10614
|
}
|
|
10501
|
-
|
|
10502
|
-
|
|
10615
|
+
const compIdSets = findConnectedComponents(
|
|
10616
|
+
parsed.tables.map((t) => t.id),
|
|
10617
|
+
parsed.relationships
|
|
10618
|
+
);
|
|
10619
|
+
const tableById = new Map(parsed.tables.map((t) => [t.id, t]));
|
|
10620
|
+
const componentItems = compIdSets.map((ids) => {
|
|
10621
|
+
const tables = ids.map((id) => tableById.get(id));
|
|
10622
|
+
const rels = parsed.relationships.filter((r) => ids.includes(r.source));
|
|
10623
|
+
return { compIds: ids, compLayout: layoutComponent(tables, rels, dimMap) };
|
|
10624
|
+
});
|
|
10625
|
+
const packed = packComponents(componentItems);
|
|
10626
|
+
const placementByTableId = /* @__PURE__ */ new Map();
|
|
10627
|
+
for (const p of packed) {
|
|
10628
|
+
for (const id of p.compIds) placementByTableId.set(id, p);
|
|
10629
|
+
}
|
|
10630
|
+
const placementByRelLine = /* @__PURE__ */ new Map();
|
|
10631
|
+
for (const p of packed) {
|
|
10632
|
+
for (const lineNum of p.compLayout.edgePoints.keys()) {
|
|
10633
|
+
placementByRelLine.set(lineNum, p);
|
|
10634
|
+
}
|
|
10503
10635
|
}
|
|
10504
|
-
dagre3.layout(g);
|
|
10505
10636
|
const layoutNodes = parsed.tables.map((table) => {
|
|
10506
|
-
const
|
|
10507
|
-
const
|
|
10637
|
+
const p = placementByTableId.get(table.id);
|
|
10638
|
+
const pos = p.compLayout.nodePositions.get(table.id);
|
|
10508
10639
|
return {
|
|
10509
10640
|
...table,
|
|
10510
|
-
x: pos.x,
|
|
10511
|
-
y: pos.y,
|
|
10512
|
-
width:
|
|
10513
|
-
height:
|
|
10514
|
-
headerHeight:
|
|
10515
|
-
columnsHeight:
|
|
10641
|
+
x: pos.x + p.offsetX + HALF_MARGIN,
|
|
10642
|
+
y: pos.y + p.offsetY + HALF_MARGIN,
|
|
10643
|
+
width: pos.width,
|
|
10644
|
+
height: pos.height,
|
|
10645
|
+
headerHeight: pos.headerHeight,
|
|
10646
|
+
columnsHeight: pos.columnsHeight
|
|
10516
10647
|
};
|
|
10517
10648
|
});
|
|
10518
10649
|
const layoutEdges = parsed.relationships.map((rel) => {
|
|
10519
|
-
const
|
|
10650
|
+
const p = placementByRelLine.get(rel.lineNumber);
|
|
10651
|
+
const pts = p?.compLayout.edgePoints.get(rel.lineNumber) ?? [];
|
|
10520
10652
|
return {
|
|
10521
10653
|
source: rel.source,
|
|
10522
10654
|
target: rel.target,
|
|
10523
10655
|
cardinality: rel.cardinality,
|
|
10524
|
-
points:
|
|
10656
|
+
points: pts.map((pt) => ({
|
|
10657
|
+
x: pt.x + (p?.offsetX ?? 0) + HALF_MARGIN,
|
|
10658
|
+
y: pt.y + (p?.offsetY ?? 0) + HALF_MARGIN
|
|
10659
|
+
})),
|
|
10525
10660
|
label: rel.label,
|
|
10526
10661
|
lineNumber: rel.lineNumber
|
|
10527
10662
|
};
|
|
10528
10663
|
});
|
|
10529
|
-
let minX = Infinity;
|
|
10530
|
-
let minY = Infinity;
|
|
10531
10664
|
let maxX = 0;
|
|
10532
10665
|
let maxY = 0;
|
|
10533
10666
|
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;
|
|
10667
|
+
maxX = Math.max(maxX, node.x + node.width / 2);
|
|
10668
|
+
maxY = Math.max(maxY, node.y + node.height / 2);
|
|
10542
10669
|
}
|
|
10543
10670
|
for (const edge of layoutEdges) {
|
|
10544
10671
|
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;
|
|
10672
|
+
maxX = Math.max(maxX, pt.x);
|
|
10673
|
+
maxY = Math.max(maxY, pt.y);
|
|
10555
10674
|
}
|
|
10556
10675
|
}
|
|
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
10676
|
return {
|
|
10576
10677
|
nodes: layoutNodes,
|
|
10577
10678
|
edges: layoutEdges,
|
|
10578
|
-
width:
|
|
10579
|
-
height:
|
|
10679
|
+
width: maxX + HALF_MARGIN,
|
|
10680
|
+
height: maxY + HALF_MARGIN
|
|
10580
10681
|
};
|
|
10581
10682
|
}
|
|
10582
|
-
var MIN_WIDTH2, CHAR_WIDTH4, PADDING_X2, HEADER_BASE2, MEMBER_LINE_HEIGHT3, COMPARTMENT_PADDING_Y3, SEPARATOR_HEIGHT2;
|
|
10683
|
+
var MIN_WIDTH2, CHAR_WIDTH4, PADDING_X2, HEADER_BASE2, MEMBER_LINE_HEIGHT3, COMPARTMENT_PADDING_Y3, SEPARATOR_HEIGHT2, HALF_MARGIN, COMP_GAP;
|
|
10583
10684
|
var init_layout4 = __esm({
|
|
10584
10685
|
"src/er/layout.ts"() {
|
|
10585
10686
|
"use strict";
|
|
@@ -10590,6 +10691,135 @@ var init_layout4 = __esm({
|
|
|
10590
10691
|
MEMBER_LINE_HEIGHT3 = 18;
|
|
10591
10692
|
COMPARTMENT_PADDING_Y3 = 8;
|
|
10592
10693
|
SEPARATOR_HEIGHT2 = 1;
|
|
10694
|
+
HALF_MARGIN = 30;
|
|
10695
|
+
COMP_GAP = 60;
|
|
10696
|
+
}
|
|
10697
|
+
});
|
|
10698
|
+
|
|
10699
|
+
// src/er/classify.ts
|
|
10700
|
+
function classifyEREntities(tables, relationships) {
|
|
10701
|
+
const result = /* @__PURE__ */ new Map();
|
|
10702
|
+
if (tables.length === 0) return result;
|
|
10703
|
+
const indegreeMap = {};
|
|
10704
|
+
for (const t of tables) indegreeMap[t.id] = 0;
|
|
10705
|
+
for (const rel of relationships) {
|
|
10706
|
+
if (rel.source === rel.target) continue;
|
|
10707
|
+
if (rel.cardinality.from === "1" && rel.cardinality.to !== "1") {
|
|
10708
|
+
indegreeMap[rel.source] = (indegreeMap[rel.source] ?? 0) + 1;
|
|
10709
|
+
}
|
|
10710
|
+
if (rel.cardinality.to === "1" && rel.cardinality.from !== "1") {
|
|
10711
|
+
indegreeMap[rel.target] = (indegreeMap[rel.target] ?? 0) + 1;
|
|
10712
|
+
}
|
|
10713
|
+
}
|
|
10714
|
+
const tableStarNeighbors = /* @__PURE__ */ new Map();
|
|
10715
|
+
for (const rel of relationships) {
|
|
10716
|
+
if (rel.source === rel.target) continue;
|
|
10717
|
+
if (rel.cardinality.from === "*") {
|
|
10718
|
+
if (!tableStarNeighbors.has(rel.source)) tableStarNeighbors.set(rel.source, /* @__PURE__ */ new Set());
|
|
10719
|
+
tableStarNeighbors.get(rel.source).add(rel.target);
|
|
10720
|
+
}
|
|
10721
|
+
if (rel.cardinality.to === "*") {
|
|
10722
|
+
if (!tableStarNeighbors.has(rel.target)) tableStarNeighbors.set(rel.target, /* @__PURE__ */ new Set());
|
|
10723
|
+
tableStarNeighbors.get(rel.target).add(rel.source);
|
|
10724
|
+
}
|
|
10725
|
+
}
|
|
10726
|
+
const mmParticipants = /* @__PURE__ */ new Set();
|
|
10727
|
+
for (const [id, neighbors] of tableStarNeighbors) {
|
|
10728
|
+
if (neighbors.size >= 2) mmParticipants.add(id);
|
|
10729
|
+
}
|
|
10730
|
+
const indegreeValues = Object.values(indegreeMap);
|
|
10731
|
+
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
10732
|
+
const variance = indegreeValues.reduce((a, b) => a + (b - mean) ** 2, 0) / indegreeValues.length;
|
|
10733
|
+
const stddev = Math.sqrt(variance);
|
|
10734
|
+
const sorted = [...indegreeValues].sort((a, b) => a - b);
|
|
10735
|
+
const median = sorted.length % 2 === 0 ? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2 : sorted[Math.floor(sorted.length / 2)];
|
|
10736
|
+
for (const table of tables) {
|
|
10737
|
+
const id = table.id;
|
|
10738
|
+
const cols = table.columns;
|
|
10739
|
+
const fkCols = cols.filter((c) => c.constraints.includes("fk"));
|
|
10740
|
+
const pkFkCols = cols.filter(
|
|
10741
|
+
(c) => c.constraints.includes("pk") && c.constraints.includes("fk")
|
|
10742
|
+
);
|
|
10743
|
+
const fkCount = fkCols.length;
|
|
10744
|
+
const fkRatio = cols.length === 0 ? 0 : fkCount / cols.length;
|
|
10745
|
+
const indegree = indegreeMap[id] ?? 0;
|
|
10746
|
+
const nameLower = table.name.toLowerCase();
|
|
10747
|
+
const externalRels = relationships.filter(
|
|
10748
|
+
(r) => (r.source === id || r.target === id) && r.source !== r.target
|
|
10749
|
+
);
|
|
10750
|
+
const hasSelfRef = relationships.some((r) => r.source === id && r.target === id);
|
|
10751
|
+
const externalTargets = /* @__PURE__ */ new Set();
|
|
10752
|
+
for (const rel of externalRels) {
|
|
10753
|
+
externalTargets.add(rel.source === id ? rel.target : rel.source);
|
|
10754
|
+
}
|
|
10755
|
+
if (hasSelfRef && externalRels.length === 0) {
|
|
10756
|
+
result.set(id, "self-referential");
|
|
10757
|
+
continue;
|
|
10758
|
+
}
|
|
10759
|
+
const isInheritancePattern = pkFkCols.length >= 2 && externalTargets.size === 1;
|
|
10760
|
+
const junctionByRatio = fkRatio >= 0.6 && !isInheritancePattern;
|
|
10761
|
+
const junctionByCompositePk = pkFkCols.length >= 2 && externalTargets.size >= 2;
|
|
10762
|
+
const junctionByMm = mmParticipants.has(id);
|
|
10763
|
+
if (junctionByRatio || junctionByCompositePk || junctionByMm) {
|
|
10764
|
+
result.set(id, "junction");
|
|
10765
|
+
continue;
|
|
10766
|
+
}
|
|
10767
|
+
if (fkRatio >= 0.4 && fkRatio < 0.6 && pkFkCols.length < 2 && !mmParticipants.has(id)) {
|
|
10768
|
+
result.set(id, "ambiguous");
|
|
10769
|
+
continue;
|
|
10770
|
+
}
|
|
10771
|
+
const nameMatchesLookup = LOOKUP_NAME_SUFFIXES.some((s) => nameLower.endsWith(s));
|
|
10772
|
+
if (nameMatchesLookup && cols.length <= 6 && fkCount <= 1 && indegree > median) {
|
|
10773
|
+
result.set(id, "lookup");
|
|
10774
|
+
continue;
|
|
10775
|
+
}
|
|
10776
|
+
if (tables.length >= 6 && indegree > 0 && indegree > mean + 1.5 * stddev && indegree >= 2 * mean) {
|
|
10777
|
+
result.set(id, "hub");
|
|
10778
|
+
continue;
|
|
10779
|
+
}
|
|
10780
|
+
if (fkCount > 0) {
|
|
10781
|
+
result.set(id, "dependent");
|
|
10782
|
+
continue;
|
|
10783
|
+
}
|
|
10784
|
+
result.set(id, "core");
|
|
10785
|
+
}
|
|
10786
|
+
return result;
|
|
10787
|
+
}
|
|
10788
|
+
var ROLE_COLORS, ROLE_LABELS, ROLE_ORDER, LOOKUP_NAME_SUFFIXES;
|
|
10789
|
+
var init_classify = __esm({
|
|
10790
|
+
"src/er/classify.ts"() {
|
|
10791
|
+
"use strict";
|
|
10792
|
+
ROLE_COLORS = {
|
|
10793
|
+
core: "green",
|
|
10794
|
+
dependent: "blue",
|
|
10795
|
+
junction: "red",
|
|
10796
|
+
ambiguous: "purple",
|
|
10797
|
+
lookup: "yellow",
|
|
10798
|
+
hub: "orange",
|
|
10799
|
+
"self-referential": "teal",
|
|
10800
|
+
unclassified: "gray"
|
|
10801
|
+
};
|
|
10802
|
+
ROLE_LABELS = {
|
|
10803
|
+
core: "Core entity",
|
|
10804
|
+
dependent: "Dependent",
|
|
10805
|
+
junction: "Junction / M:M",
|
|
10806
|
+
ambiguous: "Bridge",
|
|
10807
|
+
lookup: "Lookup / Reference",
|
|
10808
|
+
hub: "Hub",
|
|
10809
|
+
"self-referential": "Self-referential",
|
|
10810
|
+
unclassified: "Unclassified"
|
|
10811
|
+
};
|
|
10812
|
+
ROLE_ORDER = [
|
|
10813
|
+
"core",
|
|
10814
|
+
"dependent",
|
|
10815
|
+
"junction",
|
|
10816
|
+
"ambiguous",
|
|
10817
|
+
"lookup",
|
|
10818
|
+
"hub",
|
|
10819
|
+
"self-referential",
|
|
10820
|
+
"unclassified"
|
|
10821
|
+
];
|
|
10822
|
+
LOOKUP_NAME_SUFFIXES = ["_type", "_status", "_code", "_category"];
|
|
10593
10823
|
}
|
|
10594
10824
|
});
|
|
10595
10825
|
|
|
@@ -10661,25 +10891,41 @@ function drawCardinality(g, point, prevPoint, cardinality, color, useLabels) {
|
|
|
10661
10891
|
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
10892
|
}
|
|
10663
10893
|
}
|
|
10664
|
-
function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem, exportDims, activeTagGroup) {
|
|
10894
|
+
function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem, exportDims, activeTagGroup, semanticColorsActive) {
|
|
10665
10895
|
d3Selection5.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
10666
|
-
const
|
|
10667
|
-
const
|
|
10668
|
-
if (width <= 0 || height <= 0) return;
|
|
10896
|
+
const useSemanticColors = parsed.tagGroups.length === 0 && layout.nodes.every((n) => !n.color);
|
|
10897
|
+
const legendReserveH = useSemanticColors ? LEGEND_HEIGHT + DIAGRAM_PADDING5 : 0;
|
|
10669
10898
|
const titleHeight = parsed.title ? 40 : 0;
|
|
10670
10899
|
const diagramW = layout.width;
|
|
10671
10900
|
const diagramH = layout.height;
|
|
10672
|
-
const
|
|
10673
|
-
const
|
|
10674
|
-
|
|
10675
|
-
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
10680
|
-
|
|
10901
|
+
const naturalW = diagramW + DIAGRAM_PADDING5 * 2;
|
|
10902
|
+
const naturalH = diagramH + titleHeight + legendReserveH + DIAGRAM_PADDING5 * 2;
|
|
10903
|
+
let viewW;
|
|
10904
|
+
let viewH;
|
|
10905
|
+
let scale;
|
|
10906
|
+
let offsetX;
|
|
10907
|
+
let offsetY;
|
|
10908
|
+
if (exportDims) {
|
|
10909
|
+
viewW = exportDims.width ?? naturalW;
|
|
10910
|
+
viewH = exportDims.height ?? naturalH;
|
|
10911
|
+
const availH = viewH - titleHeight - legendReserveH;
|
|
10912
|
+
const scaleX = (viewW - DIAGRAM_PADDING5 * 2) / diagramW;
|
|
10913
|
+
const scaleY = (availH - DIAGRAM_PADDING5 * 2) / diagramH;
|
|
10914
|
+
scale = Math.min(MAX_SCALE4, scaleX, scaleY);
|
|
10915
|
+
const scaledW = diagramW * scale;
|
|
10916
|
+
offsetX = (viewW - scaledW) / 2;
|
|
10917
|
+
offsetY = titleHeight + DIAGRAM_PADDING5;
|
|
10918
|
+
} else {
|
|
10919
|
+
viewW = naturalW;
|
|
10920
|
+
viewH = naturalH;
|
|
10921
|
+
scale = 1;
|
|
10922
|
+
offsetX = DIAGRAM_PADDING5;
|
|
10923
|
+
offsetY = titleHeight + DIAGRAM_PADDING5;
|
|
10924
|
+
}
|
|
10925
|
+
if (viewW <= 0 || viewH <= 0) return;
|
|
10926
|
+
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
10927
|
if (parsed.title) {
|
|
10682
|
-
const titleEl = svg.append("text").attr("class", "chart-title").attr("x",
|
|
10928
|
+
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
10929
|
if (parsed.titleLineNumber) {
|
|
10684
10930
|
titleEl.attr("data-line-number", parsed.titleLineNumber);
|
|
10685
10931
|
if (onClickItem) {
|
|
@@ -10693,6 +10939,8 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10693
10939
|
}
|
|
10694
10940
|
const contentG = svg.append("g").attr("transform", `translate(${offsetX}, ${offsetY}) scale(${scale})`);
|
|
10695
10941
|
const seriesColors2 = getSeriesColors(palette);
|
|
10942
|
+
const semanticRoles = useSemanticColors ? classifyEREntities(parsed.tables, parsed.relationships) : null;
|
|
10943
|
+
const semanticActive = semanticRoles !== null && (semanticColorsActive ?? true);
|
|
10696
10944
|
const useLabels = parsed.options.notation === "labels";
|
|
10697
10945
|
for (const edge of layout.edges) {
|
|
10698
10946
|
if (edge.points.length < 2) continue;
|
|
@@ -10732,7 +10980,8 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10732
10980
|
for (let ni = 0; ni < layout.nodes.length; ni++) {
|
|
10733
10981
|
const node = layout.nodes[ni];
|
|
10734
10982
|
const tagColor = resolveTagColor(node.metadata, parsed.tagGroups, activeTagGroup ?? null);
|
|
10735
|
-
const
|
|
10983
|
+
const semanticColor = semanticActive ? palette.colors[ROLE_COLORS[semanticRoles.get(node.id) ?? "unclassified"]] : semanticRoles ? palette.primary : void 0;
|
|
10984
|
+
const nodeColor2 = node.color ?? tagColor ?? semanticColor ?? seriesColors2[ni % seriesColors2.length];
|
|
10736
10985
|
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
10986
|
if (activeTagGroup) {
|
|
10738
10987
|
const tagKey = activeTagGroup.toLowerCase();
|
|
@@ -10741,6 +10990,10 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10741
10990
|
nodeG.attr(`data-tag-${tagKey}`, tagValue.toLowerCase());
|
|
10742
10991
|
}
|
|
10743
10992
|
}
|
|
10993
|
+
if (semanticRoles) {
|
|
10994
|
+
const role = semanticRoles.get(node.id);
|
|
10995
|
+
if (role) nodeG.attr("data-er-role", role);
|
|
10996
|
+
}
|
|
10744
10997
|
if (onClickItem) {
|
|
10745
10998
|
nodeG.style("cursor", "pointer").on("click", () => {
|
|
10746
10999
|
onClickItem(node.lineNumber);
|
|
@@ -10781,7 +11034,7 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10781
11034
|
legendG.attr("data-legend-active", activeTagGroup.toLowerCase());
|
|
10782
11035
|
}
|
|
10783
11036
|
let legendX = DIAGRAM_PADDING5;
|
|
10784
|
-
let legendY =
|
|
11037
|
+
let legendY = viewH - DIAGRAM_PADDING5;
|
|
10785
11038
|
for (const group of parsed.tagGroups) {
|
|
10786
11039
|
const groupG = legendG.append("g").attr("data-legend-group", group.name.toLowerCase());
|
|
10787
11040
|
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 +11053,62 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10800
11053
|
legendX += LEGEND_GROUP_GAP;
|
|
10801
11054
|
}
|
|
10802
11055
|
}
|
|
11056
|
+
if (semanticRoles) {
|
|
11057
|
+
const presentRoles = ROLE_ORDER.filter((role) => {
|
|
11058
|
+
for (const r of semanticRoles.values()) {
|
|
11059
|
+
if (r === role) return true;
|
|
11060
|
+
}
|
|
11061
|
+
return false;
|
|
11062
|
+
});
|
|
11063
|
+
if (presentRoles.length > 0) {
|
|
11064
|
+
const measureLabelW = (text, fontSize) => {
|
|
11065
|
+
const dummy = svg.append("text").attr("font-size", fontSize).attr("font-family", FONT_FAMILY).attr("visibility", "hidden").text(text);
|
|
11066
|
+
const measured = dummy.node()?.getComputedTextLength?.() ?? 0;
|
|
11067
|
+
dummy.remove();
|
|
11068
|
+
return measured > 0 ? measured : text.length * fontSize * 0.6;
|
|
11069
|
+
};
|
|
11070
|
+
const labelWidths = /* @__PURE__ */ new Map();
|
|
11071
|
+
for (const role of presentRoles) {
|
|
11072
|
+
labelWidths.set(role, measureLabelW(ROLE_LABELS[role], LEGEND_ENTRY_FONT_SIZE));
|
|
11073
|
+
}
|
|
11074
|
+
const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
|
|
11075
|
+
const groupName = "Role";
|
|
11076
|
+
const pillWidth = groupName.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD;
|
|
11077
|
+
const pillH = LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2;
|
|
11078
|
+
let totalWidth;
|
|
11079
|
+
let entriesWidth = 0;
|
|
11080
|
+
if (semanticActive) {
|
|
11081
|
+
for (const role of presentRoles) {
|
|
11082
|
+
entriesWidth += LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + labelWidths.get(role) + LEGEND_ENTRY_TRAIL;
|
|
11083
|
+
}
|
|
11084
|
+
totalWidth = LEGEND_CAPSULE_PAD * 2 + pillWidth + LEGEND_ENTRY_TRAIL + entriesWidth;
|
|
11085
|
+
} else {
|
|
11086
|
+
totalWidth = pillWidth;
|
|
11087
|
+
}
|
|
11088
|
+
const legendX = (viewW - totalWidth) / 2;
|
|
11089
|
+
const legendY = viewH - DIAGRAM_PADDING5 - LEGEND_HEIGHT;
|
|
11090
|
+
const semanticLegendG = svg.append("g").attr("class", "er-semantic-legend").attr("data-legend-group", "role").attr("transform", `translate(${legendX}, ${legendY})`).style("cursor", "pointer");
|
|
11091
|
+
if (semanticActive) {
|
|
11092
|
+
semanticLegendG.append("rect").attr("width", totalWidth).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
|
|
11093
|
+
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);
|
|
11094
|
+
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);
|
|
11095
|
+
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);
|
|
11096
|
+
let entryX = LEGEND_CAPSULE_PAD + pillWidth + LEGEND_ENTRY_TRAIL;
|
|
11097
|
+
for (const role of presentRoles) {
|
|
11098
|
+
const label = ROLE_LABELS[role];
|
|
11099
|
+
const roleColor = palette.colors[ROLE_COLORS[role]];
|
|
11100
|
+
const entryG = semanticLegendG.append("g").attr("data-legend-entry", role);
|
|
11101
|
+
entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", roleColor);
|
|
11102
|
+
const textX = entryX + LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP;
|
|
11103
|
+
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);
|
|
11104
|
+
entryX = textX + labelWidths.get(role) + LEGEND_ENTRY_TRAIL;
|
|
11105
|
+
}
|
|
11106
|
+
} else {
|
|
11107
|
+
semanticLegendG.append("rect").attr("width", pillWidth).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
|
|
11108
|
+
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);
|
|
11109
|
+
}
|
|
11110
|
+
}
|
|
11111
|
+
}
|
|
10803
11112
|
}
|
|
10804
11113
|
function renderERDiagramForExport(content, theme, palette) {
|
|
10805
11114
|
const parsed = parseERDiagram(content, palette);
|
|
@@ -10847,6 +11156,7 @@ var init_renderer5 = __esm({
|
|
|
10847
11156
|
init_legend_constants();
|
|
10848
11157
|
init_parser3();
|
|
10849
11158
|
init_layout4();
|
|
11159
|
+
init_classify();
|
|
10850
11160
|
DIAGRAM_PADDING5 = 20;
|
|
10851
11161
|
MAX_SCALE4 = 3;
|
|
10852
11162
|
TABLE_FONT_SIZE = 13;
|
|
@@ -10975,9 +11285,10 @@ function layoutInitiativeStatus(parsed, collapseResult) {
|
|
|
10975
11285
|
const dagreEdge = g.edge(edge.source, edge.target, `e${i}`);
|
|
10976
11286
|
const dagrePoints = dagreEdge?.points ?? [];
|
|
10977
11287
|
const hasIntermediateRank = allNodeX.some((x) => x > src.x + 20 && x < tgt.x - 20);
|
|
10978
|
-
const step = Math.min((enterX - exitX) * 0.15, 20);
|
|
11288
|
+
const step = Math.max(0, Math.min((enterX - exitX) * 0.15, 20));
|
|
10979
11289
|
const isBackEdge = tgt.x < src.x - 5;
|
|
10980
|
-
const
|
|
11290
|
+
const isTopExit = !isBackEdge && tgt.x > src.x && !hasIntermediateRank && tgt.y < src.y - NODESEP;
|
|
11291
|
+
const isBottomExit = !isBackEdge && tgt.x > src.x && !hasIntermediateRank && tgt.y > src.y + NODESEP;
|
|
10981
11292
|
let points;
|
|
10982
11293
|
if (isBackEdge) {
|
|
10983
11294
|
const routeAbove = Math.min(src.y, tgt.y) > avgNodeY;
|
|
@@ -10987,31 +11298,44 @@ function layoutInitiativeStatus(parsed, collapseResult) {
|
|
|
10987
11298
|
const spreadDir = avgNodeX < rawMidX ? 1 : -1;
|
|
10988
11299
|
const unclamped = Math.abs(src.x - tgt.x) < NODE_WIDTH ? rawMidX + spreadDir * BACK_EDGE_MIN_SPREAD : rawMidX;
|
|
10989
11300
|
const midX = Math.min(src.x, Math.max(tgt.x, unclamped));
|
|
11301
|
+
const srcDepart = Math.max(midX + 1, src.x - TOP_EXIT_STEP);
|
|
11302
|
+
const tgtApproach = Math.min(midX - 1, tgt.x + TOP_EXIT_STEP);
|
|
10990
11303
|
if (routeAbove) {
|
|
10991
11304
|
const arcY = Math.min(src.y - srcHalfH, tgt.y - tgtHalfH) - BACK_EDGE_MARGIN;
|
|
10992
11305
|
points = [
|
|
10993
11306
|
{ x: src.x, y: src.y - srcHalfH },
|
|
11307
|
+
{ x: srcDepart, y: src.y - srcHalfH - TOP_EXIT_STEP },
|
|
10994
11308
|
{ x: midX, y: arcY },
|
|
11309
|
+
{ x: tgtApproach, y: tgt.y - tgtHalfH - TOP_EXIT_STEP },
|
|
10995
11310
|
{ x: tgt.x, y: tgt.y - tgtHalfH }
|
|
10996
11311
|
];
|
|
10997
11312
|
} else {
|
|
10998
11313
|
const arcY = Math.max(src.y + srcHalfH, tgt.y + tgtHalfH) + BACK_EDGE_MARGIN;
|
|
10999
11314
|
points = [
|
|
11000
11315
|
{ x: src.x, y: src.y + srcHalfH },
|
|
11316
|
+
{ x: srcDepart, y: src.y + srcHalfH + TOP_EXIT_STEP },
|
|
11001
11317
|
{ x: midX, y: arcY },
|
|
11318
|
+
{ x: tgtApproach, y: tgt.y + tgtHalfH + TOP_EXIT_STEP },
|
|
11002
11319
|
{ x: tgt.x, y: tgt.y + tgtHalfH }
|
|
11003
11320
|
];
|
|
11004
11321
|
}
|
|
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;
|
|
11322
|
+
} else if (isTopExit) {
|
|
11323
|
+
const exitY = src.y - src.height / 2;
|
|
11324
|
+
const p1x = Math.min(Math.max(src.x, src.x + yOffset + TOP_EXIT_STEP), (src.x + enterX) / 2 - 1);
|
|
11011
11325
|
points = [
|
|
11012
|
-
{ x:
|
|
11013
|
-
{ x:
|
|
11014
|
-
{ x: enterX, y:
|
|
11326
|
+
{ x: src.x, y: exitY },
|
|
11327
|
+
{ x: p1x, y: exitY - TOP_EXIT_STEP },
|
|
11328
|
+
{ x: enterX - step, y: tgt.y + yOffset },
|
|
11329
|
+
{ x: enterX, y: tgt.y }
|
|
11330
|
+
];
|
|
11331
|
+
} else if (isBottomExit) {
|
|
11332
|
+
const exitY = src.y + src.height / 2;
|
|
11333
|
+
const p1x = Math.min(Math.max(src.x, src.x + yOffset + TOP_EXIT_STEP), (src.x + enterX) / 2 - 1);
|
|
11334
|
+
points = [
|
|
11335
|
+
{ x: src.x, y: exitY },
|
|
11336
|
+
{ x: p1x, y: exitY + TOP_EXIT_STEP },
|
|
11337
|
+
{ x: enterX - step, y: tgt.y + yOffset },
|
|
11338
|
+
{ x: enterX, y: tgt.y }
|
|
11015
11339
|
];
|
|
11016
11340
|
} else if (tgt.x > src.x && !hasIntermediateRank) {
|
|
11017
11341
|
points = [
|
|
@@ -11108,7 +11432,7 @@ function layoutInitiativeStatus(parsed, collapseResult) {
|
|
|
11108
11432
|
totalHeight += 40;
|
|
11109
11433
|
return { nodes: layoutNodes, edges: layoutEdges, groups: layoutGroups, width: totalWidth, height: totalHeight };
|
|
11110
11434
|
}
|
|
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;
|
|
11435
|
+
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
11436
|
var init_layout5 = __esm({
|
|
11113
11437
|
"src/initiative-status/layout.ts"() {
|
|
11114
11438
|
"use strict";
|
|
@@ -11124,6 +11448,7 @@ var init_layout5 = __esm({
|
|
|
11124
11448
|
MAX_PARALLEL_EDGES = 5;
|
|
11125
11449
|
BACK_EDGE_MARGIN = 40;
|
|
11126
11450
|
BACK_EDGE_MIN_SPREAD = Math.round(NODE_WIDTH * 0.75);
|
|
11451
|
+
TOP_EXIT_STEP = 10;
|
|
11127
11452
|
CHAR_WIDTH_RATIO = 0.6;
|
|
11128
11453
|
NODE_FONT_SIZE = 13;
|
|
11129
11454
|
NODE_TEXT_PADDING = 12;
|
|
@@ -11623,7 +11948,7 @@ __export(layout_exports6, {
|
|
|
11623
11948
|
rollUpContextRelationships: () => rollUpContextRelationships
|
|
11624
11949
|
});
|
|
11625
11950
|
import dagre5 from "@dagrejs/dagre";
|
|
11626
|
-
function computeEdgePenalty(edgeList, nodePositions, degrees) {
|
|
11951
|
+
function computeEdgePenalty(edgeList, nodePositions, degrees, nodeGeometry) {
|
|
11627
11952
|
let penalty = 0;
|
|
11628
11953
|
for (const edge of edgeList) {
|
|
11629
11954
|
const sx = nodePositions.get(edge.source);
|
|
@@ -11633,6 +11958,32 @@ function computeEdgePenalty(edgeList, nodePositions, degrees) {
|
|
|
11633
11958
|
const weight = Math.min(degrees.get(edge.source) ?? 1, degrees.get(edge.target) ?? 1);
|
|
11634
11959
|
penalty += dist * weight;
|
|
11635
11960
|
}
|
|
11961
|
+
if (nodeGeometry) {
|
|
11962
|
+
for (const edge of edgeList) {
|
|
11963
|
+
const geomA = nodeGeometry.get(edge.source);
|
|
11964
|
+
const geomB = nodeGeometry.get(edge.target);
|
|
11965
|
+
if (!geomA || !geomB) continue;
|
|
11966
|
+
const ax = nodePositions.get(edge.source) ?? 0;
|
|
11967
|
+
const bx = nodePositions.get(edge.target) ?? 0;
|
|
11968
|
+
const ay = geomA.y;
|
|
11969
|
+
const by = geomB.y;
|
|
11970
|
+
if (ay === by) continue;
|
|
11971
|
+
const edgeMinX = Math.min(ax, bx);
|
|
11972
|
+
const edgeMaxX = Math.max(ax, bx);
|
|
11973
|
+
const edgeMinY = Math.min(ay, by);
|
|
11974
|
+
const edgeMaxY = Math.max(ay, by);
|
|
11975
|
+
for (const [name, geomC] of nodeGeometry) {
|
|
11976
|
+
if (name === edge.source || name === edge.target) continue;
|
|
11977
|
+
const cx = nodePositions.get(name) ?? 0;
|
|
11978
|
+
const cy = geomC.y;
|
|
11979
|
+
const hw = geomC.width / 2;
|
|
11980
|
+
const hh = geomC.height / 2;
|
|
11981
|
+
if (cx + hw > edgeMinX && cx - hw < edgeMaxX && cy + hh > edgeMinY && cy - hh < edgeMaxY) {
|
|
11982
|
+
penalty += EDGE_NODE_COLLISION_WEIGHT;
|
|
11983
|
+
}
|
|
11984
|
+
}
|
|
11985
|
+
}
|
|
11986
|
+
}
|
|
11636
11987
|
return penalty;
|
|
11637
11988
|
}
|
|
11638
11989
|
function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
@@ -11642,6 +11993,11 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11642
11993
|
degrees.set(edge.source, (degrees.get(edge.source) ?? 0) + 1);
|
|
11643
11994
|
degrees.set(edge.target, (degrees.get(edge.target) ?? 0) + 1);
|
|
11644
11995
|
}
|
|
11996
|
+
const nodeGeometry = /* @__PURE__ */ new Map();
|
|
11997
|
+
for (const name of g.nodes()) {
|
|
11998
|
+
const pos = g.node(name);
|
|
11999
|
+
if (pos) nodeGeometry.set(name, { y: pos.y, width: pos.width, height: pos.height });
|
|
12000
|
+
}
|
|
11645
12001
|
const rankMap = /* @__PURE__ */ new Map();
|
|
11646
12002
|
for (const name of g.nodes()) {
|
|
11647
12003
|
const pos = g.node(name);
|
|
@@ -11684,7 +12040,7 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11684
12040
|
const pos = g.node(name);
|
|
11685
12041
|
if (pos) basePositions.set(name, pos.x);
|
|
11686
12042
|
}
|
|
11687
|
-
const currentPenalty = computeEdgePenalty(edgeList, basePositions, degrees);
|
|
12043
|
+
const currentPenalty = computeEdgePenalty(edgeList, basePositions, degrees, nodeGeometry);
|
|
11688
12044
|
let bestPerm = [...partition];
|
|
11689
12045
|
let bestPenalty = currentPenalty;
|
|
11690
12046
|
if (partition.length <= 8) {
|
|
@@ -11694,7 +12050,7 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11694
12050
|
for (let i = 0; i < perm.length; i++) {
|
|
11695
12051
|
testPositions.set(perm[i], xSlots[i]);
|
|
11696
12052
|
}
|
|
11697
|
-
const penalty = computeEdgePenalty(edgeList, testPositions, degrees);
|
|
12053
|
+
const penalty = computeEdgePenalty(edgeList, testPositions, degrees, nodeGeometry);
|
|
11698
12054
|
if (penalty < bestPenalty) {
|
|
11699
12055
|
bestPenalty = penalty;
|
|
11700
12056
|
bestPerm = [...perm];
|
|
@@ -11712,13 +12068,13 @@ function reduceCrossings(g, edgeList, nodeGroupMap) {
|
|
|
11712
12068
|
for (let k = 0; k < workingOrder.length; k++) {
|
|
11713
12069
|
testPositions.set(workingOrder[k], xSlots[k]);
|
|
11714
12070
|
}
|
|
11715
|
-
const before = computeEdgePenalty(edgeList, testPositions, degrees);
|
|
12071
|
+
const before = computeEdgePenalty(edgeList, testPositions, degrees, nodeGeometry);
|
|
11716
12072
|
[workingOrder[i], workingOrder[i + 1]] = [workingOrder[i + 1], workingOrder[i]];
|
|
11717
12073
|
const testPositions2 = new Map(basePositions);
|
|
11718
12074
|
for (let k = 0; k < workingOrder.length; k++) {
|
|
11719
12075
|
testPositions2.set(workingOrder[k], xSlots[k]);
|
|
11720
12076
|
}
|
|
11721
|
-
const after = computeEdgePenalty(edgeList, testPositions2, degrees);
|
|
12077
|
+
const after = computeEdgePenalty(edgeList, testPositions2, degrees, nodeGeometry);
|
|
11722
12078
|
if (after < before) {
|
|
11723
12079
|
improved = true;
|
|
11724
12080
|
if (after < bestPenalty) {
|
|
@@ -11957,7 +12313,7 @@ function computeLegendGroups3(tagGroups) {
|
|
|
11957
12313
|
const nameW = group.name.length * LEGEND_PILL_FONT_W4 + LEGEND_PILL_PAD4 * 2;
|
|
11958
12314
|
let capsuleW = LEGEND_CAPSULE_PAD4;
|
|
11959
12315
|
for (const e of entries) {
|
|
11960
|
-
capsuleW += LEGEND_DOT_R4 * 2 + LEGEND_ENTRY_DOT_GAP4 + e.value.length *
|
|
12316
|
+
capsuleW += LEGEND_DOT_R4 * 2 + LEGEND_ENTRY_DOT_GAP4 + e.value.length * LEGEND_ENTRY_FONT_W5 + LEGEND_ENTRY_TRAIL4;
|
|
11961
12317
|
}
|
|
11962
12318
|
capsuleW += LEGEND_CAPSULE_PAD4;
|
|
11963
12319
|
result.push({
|
|
@@ -13038,7 +13394,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
|
|
|
13038
13394
|
}
|
|
13039
13395
|
return { nodes, edges, legend: legendGroups, groupBoundaries, width: totalWidth, height: totalHeight };
|
|
13040
13396
|
}
|
|
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,
|
|
13397
|
+
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_W5, LEGEND_ENTRY_DOT_GAP4, LEGEND_ENTRY_TRAIL4, LEGEND_CAPSULE_PAD4, EDGE_NODE_COLLISION_WEIGHT, META_EXCLUDE_KEYS;
|
|
13042
13398
|
var init_layout6 = __esm({
|
|
13043
13399
|
"src/c4/layout.ts"() {
|
|
13044
13400
|
"use strict";
|
|
@@ -13063,10 +13419,11 @@ var init_layout6 = __esm({
|
|
|
13063
13419
|
LEGEND_PILL_PAD4 = 16;
|
|
13064
13420
|
LEGEND_DOT_R4 = 4;
|
|
13065
13421
|
LEGEND_ENTRY_FONT_SIZE2 = 10;
|
|
13066
|
-
|
|
13422
|
+
LEGEND_ENTRY_FONT_W5 = LEGEND_ENTRY_FONT_SIZE2 * 0.6;
|
|
13067
13423
|
LEGEND_ENTRY_DOT_GAP4 = 4;
|
|
13068
13424
|
LEGEND_ENTRY_TRAIL4 = 8;
|
|
13069
13425
|
LEGEND_CAPSULE_PAD4 = 4;
|
|
13426
|
+
EDGE_NODE_COLLISION_WEIGHT = 5e3;
|
|
13070
13427
|
META_EXCLUDE_KEYS = /* @__PURE__ */ new Set(["description", "tech", "technology", "is a"]);
|
|
13071
13428
|
}
|
|
13072
13429
|
});
|
|
@@ -15251,6 +15608,7 @@ var init_compute = __esm({
|
|
|
15251
15608
|
// src/infra/layout.ts
|
|
15252
15609
|
var layout_exports8 = {};
|
|
15253
15610
|
__export(layout_exports8, {
|
|
15611
|
+
fixEdgeWaypoints: () => fixEdgeWaypoints,
|
|
15254
15612
|
layoutInfra: () => layoutInfra,
|
|
15255
15613
|
separateGroups: () => separateGroups
|
|
15256
15614
|
});
|
|
@@ -15435,6 +15793,8 @@ function formatUptime(fraction) {
|
|
|
15435
15793
|
return `${pct.toFixed(1)}%`;
|
|
15436
15794
|
}
|
|
15437
15795
|
function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
15796
|
+
const groupDeltas = /* @__PURE__ */ new Map();
|
|
15797
|
+
let converged = false;
|
|
15438
15798
|
for (let iter = 0; iter < maxIterations; iter++) {
|
|
15439
15799
|
let anyOverlap = false;
|
|
15440
15800
|
for (let i = 0; i < groups.length; i++) {
|
|
@@ -15452,6 +15812,9 @@ function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
|
15452
15812
|
const groupToShift = aCenter <= bCenter ? gb : ga;
|
|
15453
15813
|
if (isLR) groupToShift.y += shift;
|
|
15454
15814
|
else groupToShift.x += shift;
|
|
15815
|
+
const prev = groupDeltas.get(groupToShift.id) ?? { dx: 0, dy: 0 };
|
|
15816
|
+
if (isLR) groupDeltas.set(groupToShift.id, { dx: prev.dx, dy: prev.dy + shift });
|
|
15817
|
+
else groupDeltas.set(groupToShift.id, { dx: prev.dx + shift, dy: prev.dy });
|
|
15455
15818
|
for (const node of nodes) {
|
|
15456
15819
|
if (node.groupId === groupToShift.id) {
|
|
15457
15820
|
if (isLR) node.y += shift;
|
|
@@ -15460,19 +15823,48 @@ function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
|
15460
15823
|
}
|
|
15461
15824
|
}
|
|
15462
15825
|
}
|
|
15463
|
-
if (!anyOverlap)
|
|
15826
|
+
if (!anyOverlap) {
|
|
15827
|
+
converged = true;
|
|
15828
|
+
break;
|
|
15829
|
+
}
|
|
15830
|
+
}
|
|
15831
|
+
if (!converged && maxIterations > 0) {
|
|
15832
|
+
console.warn(`separateGroups: hit maxIterations (${maxIterations}) without fully resolving all group overlaps`);
|
|
15833
|
+
}
|
|
15834
|
+
return groupDeltas;
|
|
15835
|
+
}
|
|
15836
|
+
function fixEdgeWaypoints(edges, nodes, groupDeltas) {
|
|
15837
|
+
if (groupDeltas.size === 0) return;
|
|
15838
|
+
const nodeToGroup = /* @__PURE__ */ new Map();
|
|
15839
|
+
for (const node of nodes) nodeToGroup.set(node.id, node.groupId);
|
|
15840
|
+
for (const edge of edges) {
|
|
15841
|
+
const srcGroup = nodeToGroup.get(edge.sourceId) ?? null;
|
|
15842
|
+
const tgtGroup = nodeToGroup.get(edge.targetId) ?? null;
|
|
15843
|
+
const srcDelta = srcGroup ? groupDeltas.get(srcGroup) : void 0;
|
|
15844
|
+
const tgtDelta = tgtGroup ? groupDeltas.get(tgtGroup) : void 0;
|
|
15845
|
+
if (!srcDelta && !tgtDelta) continue;
|
|
15846
|
+
if (srcDelta && tgtDelta && srcGroup !== tgtGroup) {
|
|
15847
|
+
edge.points = [];
|
|
15848
|
+
continue;
|
|
15849
|
+
}
|
|
15850
|
+
const delta = srcDelta ?? tgtDelta;
|
|
15851
|
+
for (const pt of edge.points) {
|
|
15852
|
+
pt.x += delta.dx;
|
|
15853
|
+
pt.y += delta.dy;
|
|
15854
|
+
}
|
|
15464
15855
|
}
|
|
15465
15856
|
}
|
|
15466
15857
|
function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
15467
15858
|
if (computed.nodes.length === 0) {
|
|
15468
|
-
return { nodes: [], edges: [], groups: [], options: {}, width: 0, height: 0 };
|
|
15859
|
+
return { nodes: [], edges: [], groups: [], options: {}, direction: computed.direction, width: 0, height: 0 };
|
|
15469
15860
|
}
|
|
15861
|
+
const isLR = computed.direction !== "TB";
|
|
15470
15862
|
const g = new dagre7.graphlib.Graph();
|
|
15471
15863
|
g.setGraph({
|
|
15472
15864
|
rankdir: computed.direction === "TB" ? "TB" : "LR",
|
|
15473
|
-
nodesep:
|
|
15474
|
-
ranksep:
|
|
15475
|
-
edgesep:
|
|
15865
|
+
nodesep: isLR ? 70 : 60,
|
|
15866
|
+
ranksep: isLR ? 150 : 120,
|
|
15867
|
+
edgesep: 30
|
|
15476
15868
|
});
|
|
15477
15869
|
g.setDefaultEdgeLabel(() => ({}));
|
|
15478
15870
|
const groupedNodeIds = /* @__PURE__ */ new Set();
|
|
@@ -15480,7 +15872,6 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
15480
15872
|
if (node.groupId) groupedNodeIds.add(node.id);
|
|
15481
15873
|
}
|
|
15482
15874
|
const GROUP_INFLATE = GROUP_PADDING3 * 2 + GROUP_HEADER_HEIGHT;
|
|
15483
|
-
const isLR = computed.direction !== "TB";
|
|
15484
15875
|
const widthMap = /* @__PURE__ */ new Map();
|
|
15485
15876
|
const heightMap = /* @__PURE__ */ new Map();
|
|
15486
15877
|
for (const node of computed.nodes) {
|
|
@@ -15615,7 +16006,8 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
15615
16006
|
lineNumber: group.lineNumber
|
|
15616
16007
|
};
|
|
15617
16008
|
});
|
|
15618
|
-
separateGroups(layoutGroups, layoutNodes, isLR);
|
|
16009
|
+
const groupDeltas = separateGroups(layoutGroups, layoutNodes, isLR);
|
|
16010
|
+
fixEdgeWaypoints(layoutEdges, layoutNodes, groupDeltas);
|
|
15619
16011
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
15620
16012
|
for (const node of layoutNodes) {
|
|
15621
16013
|
const left = node.x - node.width / 2;
|
|
@@ -15673,6 +16065,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
15673
16065
|
edges: layoutEdges,
|
|
15674
16066
|
groups: layoutGroups,
|
|
15675
16067
|
options: computed.options,
|
|
16068
|
+
direction: computed.direction,
|
|
15676
16069
|
width: totalWidth,
|
|
15677
16070
|
height: totalHeight
|
|
15678
16071
|
};
|
|
@@ -15714,23 +16107,23 @@ var init_layout8 = __esm({
|
|
|
15714
16107
|
]);
|
|
15715
16108
|
DISPLAY_NAMES = {
|
|
15716
16109
|
"cache-hit": "cache hit",
|
|
15717
|
-
"firewall-block": "
|
|
16110
|
+
"firewall-block": "firewall block",
|
|
15718
16111
|
"ratelimit-rps": "rate limit RPS",
|
|
15719
16112
|
"latency-ms": "latency",
|
|
15720
16113
|
"uptime": "uptime",
|
|
15721
16114
|
"instances": "instances",
|
|
15722
16115
|
"max-rps": "max RPS",
|
|
15723
|
-
"cb-error-threshold": "CB error",
|
|
15724
|
-
"cb-latency-threshold-ms": "CB latency",
|
|
16116
|
+
"cb-error-threshold": "CB error threshold",
|
|
16117
|
+
"cb-latency-threshold-ms": "CB latency threshold",
|
|
15725
16118
|
"concurrency": "concurrency",
|
|
15726
16119
|
"duration-ms": "duration",
|
|
15727
16120
|
"cold-start-ms": "cold start",
|
|
15728
16121
|
"buffer": "buffer",
|
|
15729
|
-
"drain-rate": "drain",
|
|
16122
|
+
"drain-rate": "drain rate",
|
|
15730
16123
|
"retention-hours": "retention",
|
|
15731
16124
|
"partitions": "partitions"
|
|
15732
16125
|
};
|
|
15733
|
-
GROUP_GAP =
|
|
16126
|
+
GROUP_GAP = GROUP_PADDING3 * 2 + GROUP_HEADER_HEIGHT;
|
|
15734
16127
|
}
|
|
15735
16128
|
});
|
|
15736
16129
|
|
|
@@ -15805,6 +16198,236 @@ function resolveNodeSlo(node, diagramOptions) {
|
|
|
15805
16198
|
if (availThreshold == null && latencyP90 == null) return null;
|
|
15806
16199
|
return { availThreshold, latencyP90, warningMargin };
|
|
15807
16200
|
}
|
|
16201
|
+
function buildPathD(pts, direction) {
|
|
16202
|
+
const gen = d3Shape7.line().x((d) => d.x).y((d) => d.y);
|
|
16203
|
+
if (pts.length <= 2) {
|
|
16204
|
+
gen.curve(direction === "TB" ? d3Shape7.curveBumpY : d3Shape7.curveBumpX);
|
|
16205
|
+
} else {
|
|
16206
|
+
gen.curve(d3Shape7.curveCatmullRom.alpha(0.5));
|
|
16207
|
+
}
|
|
16208
|
+
return gen(pts) ?? "";
|
|
16209
|
+
}
|
|
16210
|
+
function computePortPts(edges, nodeMap, direction) {
|
|
16211
|
+
const srcPts = /* @__PURE__ */ new Map();
|
|
16212
|
+
const tgtPts = /* @__PURE__ */ new Map();
|
|
16213
|
+
const PAD = 0.1;
|
|
16214
|
+
const activeEdges = edges.filter((e) => e.points.length > 0);
|
|
16215
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
16216
|
+
for (const e of activeEdges) {
|
|
16217
|
+
if (!bySource.has(e.sourceId)) bySource.set(e.sourceId, []);
|
|
16218
|
+
bySource.get(e.sourceId).push(e);
|
|
16219
|
+
}
|
|
16220
|
+
for (const [sourceId, es] of bySource) {
|
|
16221
|
+
if (es.length < 2) continue;
|
|
16222
|
+
const source = nodeMap.get(sourceId);
|
|
16223
|
+
if (!source) continue;
|
|
16224
|
+
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);
|
|
16225
|
+
const n = sorted.length;
|
|
16226
|
+
for (let i = 0; i < n; i++) {
|
|
16227
|
+
const frac = n === 1 ? 0.5 : PAD + (1 - 2 * PAD) * i / (n - 1);
|
|
16228
|
+
const { e, t } = sorted[i];
|
|
16229
|
+
const isBackward = direction === "LR" ? t.x < source.x : t.y < source.y;
|
|
16230
|
+
if (direction === "LR") {
|
|
16231
|
+
srcPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16232
|
+
x: isBackward ? source.x - source.width / 2 : source.x + source.width / 2,
|
|
16233
|
+
y: source.y - source.height / 2 + frac * source.height
|
|
16234
|
+
});
|
|
16235
|
+
} else {
|
|
16236
|
+
srcPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16237
|
+
x: source.x - source.width / 2 + frac * source.width,
|
|
16238
|
+
y: isBackward ? source.y - source.height / 2 : source.y + source.height / 2
|
|
16239
|
+
});
|
|
16240
|
+
}
|
|
16241
|
+
}
|
|
16242
|
+
}
|
|
16243
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
16244
|
+
for (const e of activeEdges) {
|
|
16245
|
+
if (!byTarget.has(e.targetId)) byTarget.set(e.targetId, []);
|
|
16246
|
+
byTarget.get(e.targetId).push(e);
|
|
16247
|
+
}
|
|
16248
|
+
for (const [targetId, es] of byTarget) {
|
|
16249
|
+
if (es.length < 2) continue;
|
|
16250
|
+
const target = nodeMap.get(targetId);
|
|
16251
|
+
if (!target) continue;
|
|
16252
|
+
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);
|
|
16253
|
+
const n = sorted.length;
|
|
16254
|
+
for (let i = 0; i < n; i++) {
|
|
16255
|
+
const frac = n === 1 ? 0.5 : PAD + (1 - 2 * PAD) * i / (n - 1);
|
|
16256
|
+
const { e, s } = sorted[i];
|
|
16257
|
+
const isBackward = direction === "LR" ? target.x < s.x : target.y < s.y;
|
|
16258
|
+
if (direction === "LR") {
|
|
16259
|
+
tgtPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16260
|
+
x: isBackward ? target.x + target.width / 2 : target.x - target.width / 2,
|
|
16261
|
+
y: target.y - target.height / 2 + frac * target.height
|
|
16262
|
+
});
|
|
16263
|
+
} else {
|
|
16264
|
+
tgtPts.set(`${e.sourceId}:${e.targetId}`, {
|
|
16265
|
+
x: target.x - target.width / 2 + frac * target.width,
|
|
16266
|
+
y: isBackward ? target.y + target.height / 2 : target.y - target.height / 2
|
|
16267
|
+
});
|
|
16268
|
+
}
|
|
16269
|
+
}
|
|
16270
|
+
}
|
|
16271
|
+
return { srcPts, tgtPts };
|
|
16272
|
+
}
|
|
16273
|
+
function findRoutingLane(blocking, targetY, margin) {
|
|
16274
|
+
const MERGE_SLOP = 4;
|
|
16275
|
+
const sorted = [...blocking].sort((a, b) => a.y + a.height / 2 - (b.y + b.height / 2));
|
|
16276
|
+
const merged = [];
|
|
16277
|
+
for (const r of sorted) {
|
|
16278
|
+
const lo = r.y - MERGE_SLOP;
|
|
16279
|
+
const hi = r.y + r.height + MERGE_SLOP;
|
|
16280
|
+
if (merged.length && lo <= merged[merged.length - 1][1]) {
|
|
16281
|
+
merged[merged.length - 1][1] = Math.max(merged[merged.length - 1][1], hi);
|
|
16282
|
+
} else {
|
|
16283
|
+
merged.push([lo, hi]);
|
|
16284
|
+
}
|
|
16285
|
+
}
|
|
16286
|
+
if (merged.length === 0) return targetY;
|
|
16287
|
+
const MIN_GAP = 10;
|
|
16288
|
+
const candidates = [
|
|
16289
|
+
merged[0][0] - margin,
|
|
16290
|
+
// above all blocking rects
|
|
16291
|
+
merged[merged.length - 1][1] + margin
|
|
16292
|
+
// below all blocking rects
|
|
16293
|
+
];
|
|
16294
|
+
for (let i = 0; i < merged.length - 1; i++) {
|
|
16295
|
+
const gapLo = merged[i][1];
|
|
16296
|
+
const gapHi = merged[i + 1][0];
|
|
16297
|
+
if (gapHi - gapLo >= MIN_GAP) {
|
|
16298
|
+
candidates.push((gapLo + gapHi) / 2);
|
|
16299
|
+
}
|
|
16300
|
+
}
|
|
16301
|
+
return candidates.reduce(
|
|
16302
|
+
(best, c) => Math.abs(c - targetY) < Math.abs(best - targetY) ? c : best,
|
|
16303
|
+
candidates[0]
|
|
16304
|
+
);
|
|
16305
|
+
}
|
|
16306
|
+
function segmentIntersectsRect(p1, p2, rect) {
|
|
16307
|
+
const { x: rx, y: ry, width: rw, height: rh } = rect;
|
|
16308
|
+
const rr = rx + rw;
|
|
16309
|
+
const rb = ry + rh;
|
|
16310
|
+
const inRect = (p) => p.x >= rx && p.x <= rr && p.y >= ry && p.y <= rb;
|
|
16311
|
+
if (inRect(p1) || inRect(p2)) return true;
|
|
16312
|
+
if (Math.max(p1.x, p2.x) < rx || Math.min(p1.x, p2.x) > rr) return false;
|
|
16313
|
+
if (Math.max(p1.y, p2.y) < ry || Math.min(p1.y, p2.y) > rb) return false;
|
|
16314
|
+
const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
|
|
16315
|
+
const crosses = (a, b) => {
|
|
16316
|
+
const d1 = cross(a, b, p1);
|
|
16317
|
+
const d2 = cross(a, b, p2);
|
|
16318
|
+
const d3 = cross(p1, p2, a);
|
|
16319
|
+
const d4 = cross(p1, p2, b);
|
|
16320
|
+
return (d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d3 > 0 && d4 < 0 || d3 < 0 && d4 > 0);
|
|
16321
|
+
};
|
|
16322
|
+
const tl = { x: rx, y: ry };
|
|
16323
|
+
const tr = { x: rr, y: ry };
|
|
16324
|
+
const br = { x: rr, y: rb };
|
|
16325
|
+
const bl = { x: rx, y: rb };
|
|
16326
|
+
return crosses(tl, tr) || crosses(tr, br) || crosses(br, bl) || crosses(bl, tl);
|
|
16327
|
+
}
|
|
16328
|
+
function curveIntersectsRect(sc, tc, rect, direction) {
|
|
16329
|
+
if (direction === "LR") {
|
|
16330
|
+
const midX = (sc.x + tc.x) / 2;
|
|
16331
|
+
const m1 = { x: midX, y: sc.y };
|
|
16332
|
+
const m2 = { x: midX, y: tc.y };
|
|
16333
|
+
return segmentIntersectsRect(sc, m1, rect) || segmentIntersectsRect(m1, m2, rect) || segmentIntersectsRect(m2, tc, rect);
|
|
16334
|
+
} else {
|
|
16335
|
+
const midY = (sc.y + tc.y) / 2;
|
|
16336
|
+
const m1 = { x: sc.x, y: midY };
|
|
16337
|
+
const m2 = { x: tc.x, y: midY };
|
|
16338
|
+
return segmentIntersectsRect(sc, m1, rect) || segmentIntersectsRect(m1, m2, rect) || segmentIntersectsRect(m2, tc, rect);
|
|
16339
|
+
}
|
|
16340
|
+
}
|
|
16341
|
+
function edgeWaypoints(source, target, groups, nodes, direction, margin = 30, srcExitPt, tgtEnterPt) {
|
|
16342
|
+
const sc = { x: source.x, y: source.y };
|
|
16343
|
+
const tc = { x: target.x, y: target.y };
|
|
16344
|
+
const isBackward = direction === "LR" ? tc.x < sc.x : tc.y < sc.y;
|
|
16345
|
+
if (isBackward) {
|
|
16346
|
+
if (direction === "LR") {
|
|
16347
|
+
const xBandObs = [];
|
|
16348
|
+
for (const g of groups) {
|
|
16349
|
+
if (g.x + g.width < tc.x - margin || g.x > sc.x + margin) continue;
|
|
16350
|
+
xBandObs.push({ x: g.x, y: g.y, width: g.width, height: g.height });
|
|
16351
|
+
}
|
|
16352
|
+
for (const n of nodes) {
|
|
16353
|
+
if (n.id === source.id || n.id === target.id) continue;
|
|
16354
|
+
const nLeft = n.x - n.width / 2;
|
|
16355
|
+
const nRight = n.x + n.width / 2;
|
|
16356
|
+
if (nRight < tc.x - margin || nLeft > sc.x + margin) continue;
|
|
16357
|
+
xBandObs.push({ x: nLeft, y: n.y - n.height / 2, width: n.width, height: n.height });
|
|
16358
|
+
}
|
|
16359
|
+
const midY = (sc.y + tc.y) / 2;
|
|
16360
|
+
const routeY2 = xBandObs.length > 0 ? findRoutingLane(xBandObs, midY, margin) : midY;
|
|
16361
|
+
const exitBorder = srcExitPt ?? nodeBorderPoint(source, { x: sc.x, y: routeY2 });
|
|
16362
|
+
const exitPt2 = { x: exitBorder.x, y: routeY2 };
|
|
16363
|
+
const enterPt2 = { x: tc.x, y: routeY2 };
|
|
16364
|
+
const tp2 = tgtEnterPt ?? nodeBorderPoint(target, enterPt2);
|
|
16365
|
+
return srcExitPt ? [srcExitPt, exitPt2, enterPt2, tp2] : [exitBorder, exitPt2, enterPt2, tp2];
|
|
16366
|
+
} else {
|
|
16367
|
+
const yBandObs = [];
|
|
16368
|
+
for (const g of groups) {
|
|
16369
|
+
if (g.y + g.height < tc.y - margin || g.y > sc.y + margin) continue;
|
|
16370
|
+
yBandObs.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 nTop = n.y - n.height / 2;
|
|
16375
|
+
const nBot = n.y + n.height / 2;
|
|
16376
|
+
if (nBot < tc.y - margin || nTop > sc.y + margin) continue;
|
|
16377
|
+
yBandObs.push({ x: n.x - n.width / 2, y: nTop, width: n.width, height: n.height });
|
|
16378
|
+
}
|
|
16379
|
+
const rotated = yBandObs.map((r) => ({ x: r.y, y: r.x, width: r.height, height: r.width }));
|
|
16380
|
+
const midX = (sc.x + tc.x) / 2;
|
|
16381
|
+
const routeX = rotated.length > 0 ? findRoutingLane(rotated, midX, margin) : midX;
|
|
16382
|
+
const exitPt2 = srcExitPt ?? { x: routeX, y: sc.y };
|
|
16383
|
+
const enterPt2 = { x: routeX, y: tc.y };
|
|
16384
|
+
return [
|
|
16385
|
+
srcExitPt ?? nodeBorderPoint(source, exitPt2),
|
|
16386
|
+
exitPt2,
|
|
16387
|
+
enterPt2,
|
|
16388
|
+
tgtEnterPt ?? nodeBorderPoint(target, enterPt2)
|
|
16389
|
+
];
|
|
16390
|
+
}
|
|
16391
|
+
}
|
|
16392
|
+
const blocking = [];
|
|
16393
|
+
const blockingGroupIds = /* @__PURE__ */ new Set();
|
|
16394
|
+
const pathSrc = srcExitPt ?? sc;
|
|
16395
|
+
const pathTgt = tgtEnterPt ?? tc;
|
|
16396
|
+
for (const g of groups) {
|
|
16397
|
+
if (g.id === source.groupId || g.id === target.groupId) continue;
|
|
16398
|
+
const gRect = { x: g.x, y: g.y, width: g.width, height: g.height };
|
|
16399
|
+
if (curveIntersectsRect(pathSrc, pathTgt, gRect, direction)) {
|
|
16400
|
+
blocking.push(gRect);
|
|
16401
|
+
blockingGroupIds.add(g.id);
|
|
16402
|
+
}
|
|
16403
|
+
}
|
|
16404
|
+
for (const n of nodes) {
|
|
16405
|
+
if (n.id === source.id || n.id === target.id) continue;
|
|
16406
|
+
if (n.groupId && (n.groupId === source.groupId || n.groupId === target.groupId)) continue;
|
|
16407
|
+
if (n.groupId && blockingGroupIds.has(n.groupId)) continue;
|
|
16408
|
+
const nodeRect = { x: n.x - n.width / 2, y: n.y - n.height / 2, width: n.width, height: n.height };
|
|
16409
|
+
if (curveIntersectsRect(pathSrc, pathTgt, nodeRect, direction)) {
|
|
16410
|
+
blocking.push(nodeRect);
|
|
16411
|
+
}
|
|
16412
|
+
}
|
|
16413
|
+
if (blocking.length === 0) {
|
|
16414
|
+
const sp = srcExitPt ?? nodeBorderPoint(source, tc);
|
|
16415
|
+
const tp2 = tgtEnterPt ?? nodeBorderPoint(target, sp);
|
|
16416
|
+
return [sp, tp2];
|
|
16417
|
+
}
|
|
16418
|
+
const obsLeft = Math.min(...blocking.map((o) => o.x));
|
|
16419
|
+
const obsRight = Math.max(...blocking.map((o) => o.x + o.width));
|
|
16420
|
+
const routeY = findRoutingLane(blocking, tc.y, margin);
|
|
16421
|
+
const exitX = direction === "LR" ? Math.max(sc.x, obsLeft - margin) : obsLeft - margin;
|
|
16422
|
+
const enterX = direction === "LR" ? Math.min(tc.x, obsRight + margin) : obsRight + margin;
|
|
16423
|
+
const exitPt = { x: exitX, y: routeY };
|
|
16424
|
+
const enterPt = { x: enterX, y: routeY };
|
|
16425
|
+
const tp = tgtEnterPt ?? nodeBorderPoint(target, enterPt);
|
|
16426
|
+
if (srcExitPt) {
|
|
16427
|
+
return [srcExitPt, exitPt, enterPt, tp];
|
|
16428
|
+
}
|
|
16429
|
+
return [nodeBorderPoint(source, exitPt), exitPt, enterPt, tp];
|
|
16430
|
+
}
|
|
15808
16431
|
function nodeBorderPoint(node, target) {
|
|
15809
16432
|
const hw = node.width / 2;
|
|
15810
16433
|
const hh = node.height / 2;
|
|
@@ -16088,33 +16711,29 @@ function renderGroups(svg, groups, palette, isDark) {
|
|
|
16088
16711
|
}
|
|
16089
16712
|
}
|
|
16090
16713
|
}
|
|
16091
|
-
function renderEdgePaths(svg, edges, nodes, palette, isDark, animate) {
|
|
16714
|
+
function renderEdgePaths(svg, edges, nodes, groups, palette, isDark, animate, direction) {
|
|
16092
16715
|
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
|
|
16093
16716
|
const maxRps = Math.max(...edges.map((e) => e.computedRps), 1);
|
|
16717
|
+
const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
|
|
16094
16718
|
for (const edge of edges) {
|
|
16095
16719
|
if (edge.points.length === 0) continue;
|
|
16096
16720
|
const targetNode = nodeMap.get(edge.targetId);
|
|
16097
16721
|
const sourceNode = nodeMap.get(edge.sourceId);
|
|
16098
16722
|
const color = edgeColor(edge, palette);
|
|
16099
16723
|
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) ?? "";
|
|
16724
|
+
if (!sourceNode || !targetNode) continue;
|
|
16725
|
+
const key = `${edge.sourceId}:${edge.targetId}`;
|
|
16726
|
+
const pts = edgeWaypoints(
|
|
16727
|
+
sourceNode,
|
|
16728
|
+
targetNode,
|
|
16729
|
+
groups,
|
|
16730
|
+
nodes,
|
|
16731
|
+
direction,
|
|
16732
|
+
30,
|
|
16733
|
+
srcPts.get(key),
|
|
16734
|
+
tgtPts.get(key)
|
|
16735
|
+
);
|
|
16736
|
+
const pathD = buildPathD(pts, direction);
|
|
16118
16737
|
const edgeG = svg.append("g").attr("class", "infra-edge").attr("data-line-number", edge.lineNumber);
|
|
16119
16738
|
edgeG.append("path").attr("d", pathD).attr("fill", "none").attr("stroke", color).attr("stroke-width", strokeW);
|
|
16120
16739
|
if (animate && edge.computedRps > 0) {
|
|
@@ -16129,19 +16748,34 @@ function renderEdgePaths(svg, edges, nodes, palette, isDark, animate) {
|
|
|
16129
16748
|
}
|
|
16130
16749
|
}
|
|
16131
16750
|
}
|
|
16132
|
-
function renderEdgeLabels(svg, edges, palette, isDark, animate) {
|
|
16751
|
+
function renderEdgeLabels(svg, edges, nodes, groups, palette, isDark, animate, direction) {
|
|
16752
|
+
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
|
|
16753
|
+
const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
|
|
16133
16754
|
for (const edge of edges) {
|
|
16134
16755
|
if (edge.points.length === 0) continue;
|
|
16135
16756
|
if (!edge.label) continue;
|
|
16136
|
-
const
|
|
16137
|
-
const
|
|
16757
|
+
const sourceNode = nodeMap.get(edge.sourceId);
|
|
16758
|
+
const targetNode = nodeMap.get(edge.targetId);
|
|
16759
|
+
if (!sourceNode || !targetNode) continue;
|
|
16760
|
+
const key = `${edge.sourceId}:${edge.targetId}`;
|
|
16761
|
+
const wps = edgeWaypoints(
|
|
16762
|
+
sourceNode,
|
|
16763
|
+
targetNode,
|
|
16764
|
+
groups,
|
|
16765
|
+
nodes,
|
|
16766
|
+
direction,
|
|
16767
|
+
30,
|
|
16768
|
+
srcPts.get(key),
|
|
16769
|
+
tgtPts.get(key)
|
|
16770
|
+
);
|
|
16771
|
+
const midPt = wps[Math.floor(wps.length / 2)];
|
|
16138
16772
|
const labelText = edge.label;
|
|
16139
16773
|
const g = svg.append("g").attr("class", animate ? "infra-edge-label" : "");
|
|
16140
16774
|
const textWidth = labelText.length * 6.5 + 8;
|
|
16141
16775
|
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
16776
|
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
16777
|
if (animate) {
|
|
16144
|
-
const pathD =
|
|
16778
|
+
const pathD = buildPathD(wps, direction);
|
|
16145
16779
|
g.insert("path", ":first-child").attr("d", pathD).attr("fill", "none").attr("stroke", "transparent").attr("stroke-width", 20);
|
|
16146
16780
|
}
|
|
16147
16781
|
}
|
|
@@ -16551,7 +17185,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
16551
17185
|
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
17186
|
}
|
|
16553
17187
|
renderGroups(svg, layout.groups, palette, isDark);
|
|
16554
|
-
renderEdgePaths(svg, layout.edges, layout.nodes, palette, isDark, shouldAnimate);
|
|
17188
|
+
renderEdgePaths(svg, layout.edges, layout.nodes, layout.groups, palette, isDark, shouldAnimate, layout.direction);
|
|
16555
17189
|
const fanoutSourceIds = collectFanoutSourceIds(layout.edges);
|
|
16556
17190
|
const scaledGroupIds = new Set(
|
|
16557
17191
|
layout.groups.filter((g) => {
|
|
@@ -16563,7 +17197,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
16563
17197
|
if (shouldAnimate) {
|
|
16564
17198
|
renderRejectParticles(svg, layout.nodes);
|
|
16565
17199
|
}
|
|
16566
|
-
renderEdgeLabels(svg, layout.edges, palette, isDark, shouldAnimate);
|
|
17200
|
+
renderEdgeLabels(svg, layout.edges, layout.nodes, layout.groups, palette, isDark, shouldAnimate, layout.direction);
|
|
16567
17201
|
if (hasLegend) {
|
|
16568
17202
|
if (fixedLegend) {
|
|
16569
17203
|
const containerWidth = container.clientWidth || totalWidth;
|
|
@@ -16581,7 +17215,7 @@ function parseAndLayoutInfra(content) {
|
|
|
16581
17215
|
const layout = layoutInfra(computed);
|
|
16582
17216
|
return { parsed, computed, layout };
|
|
16583
17217
|
}
|
|
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,
|
|
17218
|
+
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
17219
|
var init_renderer8 = __esm({
|
|
16586
17220
|
"src/infra/renderer.ts"() {
|
|
16587
17221
|
"use strict";
|
|
@@ -16625,7 +17259,6 @@ var init_renderer8 = __esm({
|
|
|
16625
17259
|
REJECT_DURATION_MAX = 3;
|
|
16626
17260
|
REJECT_COUNT_MIN = 1;
|
|
16627
17261
|
REJECT_COUNT_MAX = 3;
|
|
16628
|
-
lineGenerator7 = d3Shape7.line().x((d) => d.x).y((d) => d.y).curve(d3Shape7.curveBasis);
|
|
16629
17262
|
PROP_DISPLAY = {
|
|
16630
17263
|
"cache-hit": "cache hit",
|
|
16631
17264
|
"firewall-block": "firewall block",
|
|
@@ -16810,7 +17443,7 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
|
|
|
16810
17443
|
}
|
|
16811
17444
|
}
|
|
16812
17445
|
} else if (edge.points.length >= 2) {
|
|
16813
|
-
const pathD =
|
|
17446
|
+
const pathD = lineGenerator7(edge.points);
|
|
16814
17447
|
if (pathD) {
|
|
16815
17448
|
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
17449
|
}
|
|
@@ -16874,7 +17507,7 @@ function renderStateForExport(content, theme, palette) {
|
|
|
16874
17507
|
document.body.removeChild(container);
|
|
16875
17508
|
}
|
|
16876
17509
|
}
|
|
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,
|
|
17510
|
+
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
17511
|
var init_state_renderer = __esm({
|
|
16879
17512
|
"src/graph/state-renderer.ts"() {
|
|
16880
17513
|
"use strict";
|
|
@@ -16894,7 +17527,7 @@ var init_state_renderer = __esm({
|
|
|
16894
17527
|
PSEUDOSTATE_RADIUS = 10;
|
|
16895
17528
|
STATE_CORNER_RADIUS = 10;
|
|
16896
17529
|
GROUP_EXTRA_PADDING2 = 12;
|
|
16897
|
-
|
|
17530
|
+
lineGenerator7 = d3Shape8.line().x((d) => d.x).y((d) => d.y).curve(d3Shape8.curveBasis);
|
|
16898
17531
|
}
|
|
16899
17532
|
});
|
|
16900
17533
|
|