This commit is contained in:
seb
2026-07-31 05:21:28 +02:00
parent 142e73a171
commit 806d077d57
2 changed files with 60 additions and 5 deletions

View File

@@ -711,6 +711,61 @@ function countSvgCrossings(svg) {
return n;
}
/**
* Graphviz self-edges from a lower FK row to id:e dip southeast. Rebuild the
* spline so it bulges east + north (up) while keeping start/end ports.
* In this SVG, more-negative y is visually higher.
*/
function fixSelfLoopSvg(svg) {
return svg.replace(
/<g id="(edge\d+)" class="edge">\s*<title>(\w+):e&#45;&gt;\2:e<\/title>\s*<g id="(a_edge\d+)"><a ([^>]+)>\s*<path([^>]*) d="([^"]+)"\/>\s*<polygon([^>]*) points="([^"]+)"\/>\s*<\/a>\s*<\/g>\s*<\/g>/g,
(match, edgeId, _table, aId, aAttrs, pathAttrs, d, polyAttrs) => {
const pts = [...d.matchAll(/([-\d.]+)[,\s]+([-\d.]+)/g)].map((m) => [
Number(m[1]),
Number(m[2]),
]);
if (pts.length < 2) return match;
const [x0, y0] = pts[0];
const [x1, y1] = pts[pts.length - 1];
const east = Math.max(x0, x1) + 36;
const north = Math.min(y0, y1) - 28;
// Cubic end tangent is P3-P2; orient arrow along that arrival direction.
const tx = x1 - east;
const ty = y1 - north;
const len = Math.hypot(tx, ty) || 1;
const dx = tx / len;
const dy = ty / len;
const arrowLen = 9;
const arrowHalf = 3.5;
const baseX = x1 - dx * arrowLen;
const baseY = y1 - dy * arrowLen;
const px = -dy * arrowHalf;
const py = dx * arrowHalf;
const fmt = (n) => (Math.round(n * 100) / 100).toString();
const newDFmt = `M${fmt(x0)},${fmt(y0)}C${fmt(east)},${fmt(y0)} ${fmt(east)},${fmt(north)} ${fmt(baseX)},${fmt(baseY)}`;
const newPointsFmt =
`${fmt(x1)},${fmt(y1)} ` +
`${fmt(baseX + px)},${fmt(baseY + py)} ` +
`${fmt(baseX - px)},${fmt(baseY - py)} ` +
`${fmt(x1)},${fmt(y1)}`;
return (
`<g id="${edgeId}" class="edge">\n` +
`<title>${_table}:e&#45;&gt;${_table}:e</title>\n` +
`<g id="${aId}"><a ${aAttrs}>\n` +
`<path${pathAttrs} d="${newDFmt}"/>\n` +
`<polygon${polyAttrs} points="${newPointsFmt}"/>\n` +
`</a>\n` +
`</g>\n` +
`</g>`
);
}
);
}
const schemaSource = readFileSync(schemaPath, 'utf8');
const { tables, edges } = parseSchema(schemaSource);
@@ -742,7 +797,7 @@ for (let pass = 0; pass < 2; pass++) {
const dot = buildDot(tables, edges, positions);
writeFileSync(dotOutputPath, dot, 'utf8');
const svg = graphviz.layout(dot, 'svg', 'dot');
const svg = fixSelfLoopSvg(graphviz.layout(dot, 'svg', 'dot'));
writeFileSync(outputPath, svg, 'utf8');
const dim = svg.match(/width="([\d.]+)pt" height="([\d.]+)pt"/);