Skip to content

Commit 388bdfd

Browse files
committed
update overview figure with resources as background boxes
1 parent 362d168 commit 388bdfd

1 file changed

Lines changed: 162 additions & 30 deletions

File tree

_includes/schema-diagram-embed.html

Lines changed: 162 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
--shadow: 0 6px 18px rgba(15, 23, 42, 0.08);
1212
--line-color: #111827;
1313
--line-width: 2.5;
14+
--legend-core-color: #d86b5f;
15+
--legend-geo-color: #2d8d9f;
1416
}
1517

1618
* {
@@ -31,7 +33,7 @@
3133
position: relative;
3234
width: var(--page-width);
3335
min-height: 420px;
34-
padding: 12px;
36+
padding: 12px 12px 44px;
3537
}
3638

3739
.diagram-loading {
@@ -256,13 +258,11 @@
256258
}
257259

258260
.legend-box {
259-
position: absolute;
260-
left: 20px;
261-
bottom: 20px;
262-
z-index: 4;
263-
margin: 0;
264-
width: 800px;
265-
max-width: calc(100% - 40px);
261+
position: relative;
262+
z-index: 2;
263+
margin: 12px auto 0;
264+
width: 100%;
265+
max-width: 100%;
266266
padding: 10px 12px;
267267
border: 1px solid #d1d5db;
268268
border-radius: 8px;
@@ -286,7 +286,9 @@
286286
display: flex;
287287
flex-wrap: wrap;
288288
align-items: center;
289-
gap: 8px 12px;
289+
justify-content: space-evenly;
290+
row-gap: 10px;
291+
column-gap: 20px;
290292
}
291293

292294
.legend-item {
@@ -354,11 +356,11 @@
354356
}
355357

356358
.legend-swatch--core {
357-
background: #d86b5f;
359+
background: var(--legend-core-color);
358360
}
359361

360362
.legend-swatch--geo {
361-
background: #2d8d9f;
363+
background: var(--legend-geo-color);
362364
}
363365

364366
@media (max-width: 1200px) {
@@ -384,9 +386,8 @@
384386
}
385387

386388
.legend-box {
387-
width: min(440px, calc(100% - 24px));
388-
left: 12px;
389-
bottom: 12px;
389+
width: 100%;
390+
max-width: 100%;
390391
}
391392
}
392393

@@ -431,10 +432,9 @@
431432
}
432433

433434
.legend-box {
434-
width: 440px !important;
435-
max-width: calc(100% - 24px) !important;
436-
left: 12px !important;
437-
bottom: 12px !important;
435+
width: 100% !important;
436+
max-width: 100% !important;
437+
margin: 12px auto 0 !important;
438438
}
439439
}
440440
</style>
@@ -451,6 +451,8 @@
451451
</div>
452452
<svg id="connector-layer" aria-hidden="true"></svg>
453453
<div id="tables-grid"></div>
454+
</section>
455+
<div class="col-md-10 col-lg-8 mx-auto">
454456
<aside id="diagram-legend" class="legend-box" aria-label="Diagram legend" aria-hidden="true">
455457
<p class="legend-title">Legend</p>
456458
<div class="legend-items">
@@ -476,17 +478,9 @@
476478
<span class="legend-arrow" aria-hidden="true"></span>
477479
<span class="legend-label">Foreign key relationship</span>
478480
</div>
479-
<div class="legend-item">
480-
<span class="legend-swatch legend-swatch--core" aria-hidden="true"></span>
481-
<span class="legend-label">Core tables</span>
482-
</div>
483-
<div class="legend-item">
484-
<span class="legend-swatch legend-swatch--geo" aria-hidden="true"></span>
485-
<span class="legend-label">GeoPressureR tables</span>
486-
</div>
487481
</div>
488482
</aside>
489-
</section>
483+
</div>
490484
</div>
491485
<script>
492486
const CONFIG = {
@@ -504,9 +498,9 @@
504498
// Array-of-arrays: each inner array is one column from top to bottom.
505499
layout: [
506500
["measurements", "observations"],
507-
["tags", "paths"],
508-
["twilights", "staps"],
509-
["pressurepaths", "edges"],
501+
["tags"],
502+
["pressurepaths", "staps", "paths"],
503+
["twilights", "edges"],
510504
],
511505
tableStyles: {
512506
tags: { accent: "#cf5b7f" },
@@ -560,6 +554,27 @@
560554
],
561555
// Manual order for vertical trunk lanes; lower value sorts first.
562556
trunkOrder: [
557+
{
558+
sourceTable: "edges",
559+
sourceField: "stap_t",
560+
targetTable: "staps",
561+
targetField: "stap_id",
562+
order: -30,
563+
},
564+
{
565+
sourceTable: "edges",
566+
sourceField: "stap_s",
567+
targetTable: "staps",
568+
targetField: "stap_id",
569+
order: -20,
570+
},
571+
{
572+
sourceTable: "edges",
573+
sourceField: "tag_id",
574+
targetTable: "staps",
575+
targetField: "tag_id",
576+
order: -10,
577+
},
563578
{
564579
sourceTable: "pressurepaths",
565580
sourceField: "tag_id",
@@ -575,6 +590,27 @@
575590
order: 10,
576591
},
577592
],
593+
// Manual trunk position between two layout columns (1-based column numbers).
594+
trunkBetweenColumns: [
595+
{
596+
sourceTable: "twilights",
597+
sourceField: "tag_id",
598+
targetTable: "tags",
599+
targetField: "tag_id",
600+
leftColumn: 3,
601+
rightColumn: 4,
602+
},
603+
],
604+
// Manual order for endpoint attachment when multiple connectors share the same field side.
605+
endpointOrder: [
606+
{
607+
sourceTable: "twilights",
608+
sourceField: "tag_id",
609+
targetTable: "tags",
610+
targetField: "tag_id",
611+
order: -10,
612+
},
613+
],
578614
connectorStyle: {
579615
// Marker size in SVG user units. Increase/decrease to tune arrow head size.
580616
arrowHeadSize: 15,
@@ -789,6 +825,37 @@
789825
return 0;
790826
}
791827

828+
function endpointOrderValue(relation) {
829+
for (const rule of CONFIG.endpointOrder || []) {
830+
if (matchRelationRule(relation, rule)) {
831+
return Number.isFinite(rule.order) ? rule.order : 0;
832+
}
833+
}
834+
return 0;
835+
}
836+
837+
function trunkBetweenColumnsX(relation, columnRects, baseRect) {
838+
for (const rule of CONFIG.trunkBetweenColumns || []) {
839+
if (!matchRelationRule(relation, rule)) {
840+
continue;
841+
}
842+
const leftIndex = Number(rule.leftColumn) - 1;
843+
const rightIndex = Number(rule.rightColumn) - 1;
844+
if (!Number.isFinite(leftIndex) || !Number.isFinite(rightIndex)) {
845+
continue;
846+
}
847+
const leftRect = columnRects[leftIndex];
848+
const rightRect = columnRects[rightIndex];
849+
if (!leftRect || !rightRect) {
850+
continue;
851+
}
852+
const leftX = leftRect.right - baseRect.left;
853+
const rightX = rightRect.left - baseRect.left;
854+
return (leftX + rightX) / 2;
855+
}
856+
return null;
857+
}
858+
792859
async function fetchSchema(file) {
793860
const url = `${CONFIG.schemaBaseUrl}/${file}`;
794861
const res = await fetch(url);
@@ -1255,6 +1322,10 @@
12551322
}
12561323

12571324
group.sort((a, b) => {
1325+
const orderDiff = endpointOrderValue(a.edge.rel) - endpointOrderValue(b.edge.rel);
1326+
if (orderDiff !== 0) {
1327+
return orderDiff;
1328+
}
12581329
const yDiff = a.peerY - b.peerY;
12591330
if (yDiff !== 0) {
12601331
return yDiff;
@@ -1281,6 +1352,9 @@
12811352
const wrapper = document.getElementById("diagram-wrapper");
12821353
const svg = document.getElementById("connector-layer");
12831354
const baseRect = wrapper.getBoundingClientRect();
1355+
const columnRects = [...document.querySelectorAll("#tables-grid .schema-column")].map((el) =>
1356+
el.getBoundingClientRect(),
1357+
);
12841358
const columnIndexByTable = getColumnIndexMap();
12851359
const lineColor =
12861360
getComputedStyle(document.documentElement).getPropertyValue("--line-color").trim() ||
@@ -1291,6 +1365,9 @@
12911365
const trunkPadding = 28;
12921366
const arrowHeadSize = Number(CONFIG.connectorStyle?.arrowHeadSize) || 3.2;
12931367
const arrowHeadPadding = Number(CONFIG.connectorStyle?.arrowHeadPadding) || 2;
1368+
const rootStyles = getComputedStyle(document.documentElement);
1369+
const coreBandColor = rootStyles.getPropertyValue("--legend-core-color").trim() || "#d86b5f";
1370+
const geoBandColor = rootStyles.getPropertyValue("--legend-geo-color").trim() || "#2d8d9f";
12941371

12951372
svg.setAttribute("viewBox", `0 0 ${Math.ceil(baseRect.width)} ${Math.ceil(baseRect.height)}`);
12961373
const defs = makeSvgElement("defs");
@@ -1317,6 +1394,55 @@
13171394
defs.appendChild(arrowHead);
13181395
svg.appendChild(defs);
13191396

1397+
const midLeftRect = columnRects[1];
1398+
const midRightRect = columnRects[2];
1399+
const splitX =
1400+
midLeftRect && midRightRect
1401+
? (midLeftRect.right + midRightRect.left) / 2 - baseRect.left
1402+
: null;
1403+
const bandTopPadding = 10;
1404+
const bandBottomLabelArea = 38;
1405+
const sharedTop = Math.min(...columnRects.map((rect) => rect.top)) - baseRect.top - bandTopPadding;
1406+
const tableBottom = Math.max(...columnRects.map((rect) => rect.bottom)) - baseRect.top;
1407+
const sharedBottom = tableBottom + bandBottomLabelArea;
1408+
const labelY = tableBottom + 27;
1409+
const columnBands = [
1410+
{ startIndex: 0, endIndex: 1, color: coreBandColor, label: "Core resources" },
1411+
{ startIndex: 2, endIndex: 3, color: geoBandColor, label: "GeoPressureR resources" },
1412+
];
1413+
for (const [bandIndex, band] of columnBands.entries()) {
1414+
const startRect = columnRects[band.startIndex];
1415+
const endRect = columnRects[band.endIndex];
1416+
if (!startRect || !endRect) {
1417+
continue;
1418+
}
1419+
const left =
1420+
splitX != null && bandIndex === 1 ? splitX : startRect.left - baseRect.left - 10;
1421+
const right =
1422+
splitX != null && bandIndex === 0 ? splitX : endRect.right - baseRect.left + 10;
1423+
svg.appendChild(
1424+
makeSvgElement("rect", {
1425+
x: String(left),
1426+
y: String(sharedTop),
1427+
width: String(Math.max(0, right - left)),
1428+
height: String(Math.max(0, sharedBottom - sharedTop)),
1429+
fill: hexToRgba(band.color, 0.12) || "rgba(0,0,0,0.06)",
1430+
"pointer-events": "none",
1431+
}),
1432+
);
1433+
svg.appendChild(
1434+
makeSvgElement("text", {
1435+
x: String((left + right) / 2),
1436+
y: String(labelY),
1437+
"text-anchor": "middle",
1438+
"font-size": "19",
1439+
"font-weight": "600",
1440+
fill: band.color,
1441+
"pointer-events": "none",
1442+
}),
1443+
).textContent = band.label;
1444+
}
1445+
13201446
const edges = [];
13211447
for (const rel of relations) {
13221448
const sourceTableSlug = slug(rel.sourceTable);
@@ -1412,6 +1538,12 @@
14121538
},
14131539
laneSpacing,
14141540
(edge, offset) => {
1541+
const fixedTrunkX = trunkBetweenColumnsX(edge.rel, columnRects, baseRect);
1542+
if (Number.isFinite(fixedTrunkX)) {
1543+
edge.trunkX = fixedTrunkX + offset;
1544+
return;
1545+
}
1546+
14151547
if (edge.sameColumn) {
14161548
if (edge.sourceSide === "right") {
14171549
const outerRight =

0 commit comments

Comments
 (0)