grow =
({
dx = 4,
dy = 144,
stroke = "#555",
strokeWidth = 1,
showText = true,
showDebug = true,
} = {}) =>
(root) =>
{
const isPrompt = (node) => node.height === 0;
const label = d => typeof d === "object" ? d.name : d;
const tree = d3.tree;
const padding = 1;
let height;
const r = 3;
let link;
const fill = "white";
const linkTarget = "_blank";
const title = (d, n) => `${n.ancestors().reverse().map(d => d.data.name).join(" » ")}`;
const halo = "#fff";
const haloWidth = 3;
;
const descendants = root.descendants();
const L = label == null ? null : descendants.map(d => label(d.data));
tree()
.nodeSize([dx, dy])
.separation((a, b) => (a.parent == b.parent ? 5:10))
(root);
let x0 = Infinity;
let x1 = -x0;
root.each(d => {
if (d.x > x1) x1 = d.x;
if (d.x < x0) x0 = d.x;
});
// Compute the default height.
if (height === undefined) height = x1 - x0 + dx * 2 + 10;
const svg = d3
.create("svg")
.attr("viewBox", [-dy * padding / 2 - 150, x0 - dx - 5, width, height])
.attr("width", width)
.attr("height", height)
.attr("style", "max-width: 100%; height: auto; height: intrinsic;")
.attr("font-family", "monospace")
.attr("font-size", 10)
;
svg
.append("g")
.attr("fill", "none")
.attr("stroke", stroke)
.attr("stroke-opacity", 1)
.attr("stroke-linecap", "round")
.attr("stroke-width", strokeWidth)
.selectAll("path")
.data(root.links())
.join("path")
.attr("d", d3.link(d3.curveBumpX).x(d => d.y).y(d => d.x))
;
const node = svg
.append("g")
.selectAll("a")
.data(root.descendants())
.join("a")
.attr("xlink:href", link == null ? null : d => link(d.data, d))
.attr("target", link == null ? null : linkTarget)
.attr("transform", d => `translate(${d.y},${d.x})`)
;
node
.append("circle")
.attr("fill", d => d.children ? stroke : d.color)
.attr("fill", d => styles[d.depth])
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth)
.attr("r", r)
;
const firstLeaf = (d, i) => d.height === 0 && d.i === 0 ? "visible" : "hidden";
if (L) {
node
.append("rect")
.attr("x", 0)
.attr("y", -2*dx)
.attr("width", 500)
.attr("height", 20)
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("fill", "none")
.attr("rx", 5)
.attr("visibility", firstLeaf)
;
node
.append("text")
.attr("visibility", firstLeaf)
.attr("x", 9)
.attr("y", -dx * 1.5)
.style("font-weight", "bold")
.text(d => d.mother)
;
node
.append("text")
.attr("y", d => d.height === 1 ? 0 * dx : 0)
.attr("dy", "0.32em")
.attr("text-anchor", d => isPrompt(d) ? "start" : "end")
.attr("fill", "black")
.attr("stroke", "white")
.attr("paint-order", "stroke")
.attr("dx", d => isPrompt(d) ? 12 : -12)
.text(text({L, showText, showDebug}))
;
}
if (title != null)
node
.append("title")
.text(d => title(d.data, d))
;
return svg.node();
}