@avodado/render 0.1.1 → 0.1.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/dist/index.js +51 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2083,13 +2083,20 @@ function renderErd(data) {
|
|
|
2083
2083
|
hidden = cols.length - rows.length;
|
|
2084
2084
|
}
|
|
2085
2085
|
const bodyRows = rows.length + (hidden > 0 ? 1 : 0);
|
|
2086
|
-
|
|
2087
|
-
|
|
2086
|
+
return {
|
|
2087
|
+
name: e.name,
|
|
2088
|
+
cols,
|
|
2089
|
+
rows,
|
|
2090
|
+
hidden,
|
|
2091
|
+
pkIdx: cols.findIndex((c) => c.pk === true),
|
|
2092
|
+
w: COL_W,
|
|
2093
|
+
h: HEAD_H + bodyRows * ROW_H + BOT_PAD
|
|
2094
|
+
};
|
|
2088
2095
|
});
|
|
2089
2096
|
const byName = new Map(boxes.map((b) => [b.name, b]));
|
|
2090
2097
|
const validRels = rels.filter((r) => byName.has(r.from) && byName.has(r.to));
|
|
2091
2098
|
const g = new To.graphlib.Graph({ multigraph: true });
|
|
2092
|
-
g.setGraph({ rankdir: "LR", nodesep:
|
|
2099
|
+
g.setGraph({ rankdir: "LR", nodesep: 38, ranksep: 96, marginx: 18, marginy: 18 });
|
|
2093
2100
|
g.setDefaultEdgeLabel(() => ({}));
|
|
2094
2101
|
for (const b of boxes) g.setNode(b.name, { width: b.w, height: b.h });
|
|
2095
2102
|
validRels.forEach((r, i) => g.setEdge(r.from, r.to, {}, `e${i}`));
|
|
@@ -2097,30 +2104,35 @@ function renderErd(data) {
|
|
|
2097
2104
|
const graph = g.graph();
|
|
2098
2105
|
const W2 = Math.ceil(graph.width ?? 0);
|
|
2099
2106
|
const H2 = Math.ceil(graph.height ?? 0);
|
|
2100
|
-
const
|
|
2107
|
+
const at2 = /* @__PURE__ */ new Map();
|
|
2101
2108
|
for (const b of boxes) {
|
|
2102
2109
|
const n = g.node(b.name);
|
|
2103
|
-
|
|
2110
|
+
at2.set(b.name, { x: n.x - b.w / 2, y: n.y - b.h / 2 });
|
|
2104
2111
|
}
|
|
2105
2112
|
let s = `<svg viewBox="0 0 ${W2} ${H2}" role="img"><title>Entity-relationship diagram</title>`;
|
|
2106
|
-
validRels.forEach((r
|
|
2107
|
-
const
|
|
2108
|
-
const
|
|
2109
|
-
|
|
2110
|
-
const
|
|
2111
|
-
|
|
2112
|
-
const
|
|
2113
|
-
|
|
2114
|
-
const
|
|
2115
|
-
|
|
2116
|
-
const
|
|
2117
|
-
|
|
2113
|
+
validRels.forEach((r) => {
|
|
2114
|
+
const src = byName.get(r.from);
|
|
2115
|
+
const tgt = byName.get(r.to);
|
|
2116
|
+
const sp = at2.get(r.from);
|
|
2117
|
+
const tp = at2.get(r.to);
|
|
2118
|
+
if (!src || !tgt || !sp || !tp) return;
|
|
2119
|
+
const fkY = rowAnchorY(src, sp.y, pickFkIndex(src.cols, tgt.name));
|
|
2120
|
+
const pkY = rowAnchorY(tgt, tp.y, tgt.pkIdx);
|
|
2121
|
+
const rightward = tp.x + tgt.w / 2 >= sp.x + src.w / 2;
|
|
2122
|
+
const sx = rightward ? sp.x + src.w : sp.x;
|
|
2123
|
+
const tx = rightward ? tp.x : tp.x + tgt.w;
|
|
2124
|
+
const lo = Math.min(sx, tx) + 10;
|
|
2125
|
+
const hi = Math.max(sx, tx) - 10;
|
|
2126
|
+
const midX = hi > lo ? clamp((sx + tx) / 2, lo, hi) : (sx + tx) / 2;
|
|
2127
|
+
s += `<path d="M${round(sx)},${round(fkY)} H${round(midX)} V${round(pkY)} H${round(tx)}" fill="none" stroke="var(--gray)" stroke-width="1.5"/><circle cx="${round(sx)}" cy="${round(fkY)}" r="2.6" fill="var(--gray)"/>` + arrowHeadH(tx, pkY, rightward);
|
|
2128
|
+
if (r.card !== void 0) {
|
|
2118
2129
|
const w2 = 30;
|
|
2119
|
-
|
|
2130
|
+
const cy = (fkY + pkY) / 2;
|
|
2131
|
+
s += `<rect x="${round(midX - w2 / 2)}" y="${round(cy - 9)}" width="${w2}" height="18" rx="9" fill="var(--white)" stroke="var(--rule)"/><text x="${round(midX)}" y="${round(cy + 3)}" class="edge-label">${escapeHtml(r.card)}</text>`;
|
|
2120
2132
|
}
|
|
2121
2133
|
});
|
|
2122
2134
|
for (const b of boxes) {
|
|
2123
|
-
const p2 =
|
|
2135
|
+
const p2 = at2.get(b.name);
|
|
2124
2136
|
if (!p2) continue;
|
|
2125
2137
|
const { x: x2, y } = p2;
|
|
2126
2138
|
s += `<rect x="${round(x2)}" y="${round(y)}" width="${b.w}" height="${b.h}" rx="5" fill="var(--white)" stroke="var(--navy)"/><path d="M${round(x2)},${round(y + HEAD_H)} v${ -27} a5,5 0 0 1 5,-5 h${b.w - 10} a5,5 0 0 1 5,5 v${HEAD_H - 5} z" fill="var(--navy)"/><text x="${round(x2 + b.w / 2)}" y="${round(y + 21)}" class="er-head-text">${escapeHtml(b.name)}</text>`;
|
|
@@ -2152,16 +2164,27 @@ function renderErd(data) {
|
|
|
2152
2164
|
};
|
|
2153
2165
|
return diagramFrame(opts, s);
|
|
2154
2166
|
}
|
|
2155
|
-
function
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
const
|
|
2161
|
-
const
|
|
2162
|
-
|
|
2163
|
-
|
|
2167
|
+
function rowAnchorY(box, topY, idx) {
|
|
2168
|
+
if (idx >= 0 && idx < box.rows.length) return topY + HEAD_H + idx * ROW_H + ROW_H / 2;
|
|
2169
|
+
return topY + box.h / 2;
|
|
2170
|
+
}
|
|
2171
|
+
function pickFkIndex(columns, toName) {
|
|
2172
|
+
const fks = columns.map((c, i) => ({ c, i })).filter((x2) => x2.c.fk === true);
|
|
2173
|
+
const first = fks[0];
|
|
2174
|
+
if (first === void 0) return -1;
|
|
2175
|
+
const t = toName.toLowerCase();
|
|
2176
|
+
const singular = t.replace(/s$/, "");
|
|
2177
|
+
const match = fks.find((x2) => {
|
|
2178
|
+
const n = x2.c.name.toLowerCase();
|
|
2179
|
+
return n.includes(t) || n.includes(singular);
|
|
2180
|
+
});
|
|
2181
|
+
return (match ?? first).i;
|
|
2182
|
+
}
|
|
2183
|
+
function arrowHeadH(x2, y, pointRight) {
|
|
2184
|
+
const dx = pointRight ? -10 : 10;
|
|
2185
|
+
return `<path d="M${round(x2 + dx)},${round(y - 5)} L${round(x2)},${round(y)} L${round(x2 + dx)},${round(y + 5)}" fill="none" stroke="var(--navy)" stroke-width="1.6" stroke-linejoin="round" stroke-linecap="round"/>`;
|
|
2164
2186
|
}
|
|
2187
|
+
var clamp = (n, lo, hi) => Math.max(lo, Math.min(hi, n));
|
|
2165
2188
|
var round = (n) => Math.round(n * 10) / 10;
|
|
2166
2189
|
|
|
2167
2190
|
// src/blocks/kanban.ts
|