chart = {
const root = partition(data);
let focus = root;
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("font", "10px sans-serif");
yield svg.node();
const cell = svg
.selectAll("g")
.data(root.descendants())
.join("g")
.attr("transform", d => `translate(${d.x0},${d.y0})`);
const rect = cell.append("rect")
.attr("height", d => d.y1 - d.y0 - 1)
.attr("width", d => rectWidth(d))
.attr("fill-opacity", 0.6)
.attr("fill", d => {
if (!d.depth) return "#ccc";
while (d.depth > 1) d = d.parent;
return color(d.data.name);
})
.style("cursor", "pointer")
.on("click", clicked);
const textPadding = 4;
const text = cell.append("text")
.style("user-select", "none")
.attr("pointer-events", "none")
.attr("x", textPadding)
.attr("y", 13)
.text(d => `${d.data.name} ${format(d.value)}`)
.attr("fill-opacity", function(d) { return +labelVisible(d, this) });
cell.append("title")
.text(d => `${d.ancestors().map(d => d.data.name).reverse().join("/")}\n${format(d.value)}`);
function clicked(event, p) {
focus = focus === p ? p = p.parent : p;
root.each(d => d.target = {
y0: d.y0 - p.y0,
y1: d.y1 - p.y0,
x0: (d.x0 - p.x0) / (p.x1 - p.x0) * width,
x1: (d.x1 - p.x0) / (p.x1 - p.x0) * width
});
const t = cell.transition().duration(750)
.attr("transform", d => `translate(${d.target.x0},${d.target.y0})`);
rect.transition(t).attr("width", d => rectWidth(d.target));
text.transition(t).attr("fill-opacity", function(d) { return +labelVisible(d.target, this) });
}
function rectWidth(d) {
return d.x1 - d.x0 - Math.min(1, (d.x1 - d.x0) / 2);
}
function labelVisible(d, label) {
return (
d.x1 <= width &&
d.x0 >= 0 &&
d.x1 - d.x0 - 2 * textPadding > label.getComputedTextLength()
);
}
return svg.node();
}