chart = {
let root = partition(data);
let focus = root;
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("font", "10px sans-serif");
const cell = svg
.selectAll("g")
.data(root.descendants())
.attr('class','main')
.join("g")
.attr("transform", d => `translate(${d.y0},${d.x0})`);
const rect = cell.append("rect")
.attr("width", d => d.y1 - d.y0 - 1)
.attr("height", d => rectHeight(d))
.attr("fill-opacity", (d) => {
if ('value' in d.data && d.data.value[dataType] == 0) return 0.2;
return 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 text = cell.append("text")
.style("user-select", "none")
.attr("pointer-events", "none")
.attr("x", 4)
.attr("y", 13)
.attr("fill-opacity", d => +labelVisible(d));
text.append("tspan")
.style('font-weight','bold')
.text(d => {
const count = d.children ? " (" + d.children.length + ")" : ''
if (d.data.name != 'unknown') return d.data.name + count
return "Unknown (hover for details)"
});
const tspan = text.append("tspan")
.attr("x",0)
.attr("dy","1.2em")
.attr("fill-opacity", d => labelVisible(d, true) * 0.7)
.text(d => {
if (d.hasOwnProperty('children')) {
return ` ${format(d.data.sum)} / ${format(calcTotalWithUnknowns(d))}`
}
return ` ${format(d.data.value[dataType])}`
});
cell.append("title")
.text(d => {
let data = d.data
let lineage = d.ancestors().map(d => d.data.name).reverse().join("/");
if (data.name != 'unknown') {
if ('children' in data) {
let c = data.children
.filter(d => d.sum || ('value' in d ? d.value[dataType] : 0))
.map((d) => {
return `\t${d.name} - ${format(d.sum || d.value[dataType])}`
}).join("\n")
return `${lineage}\n${c}\n${format(calcTotalWithUnknowns(d))}`
}
return `${lineage}\n${format(d.value)}`
}
let unknownItems = data.unknown.sort().map(d => " - " + d).join("\n")
return `${lineage}\n${unknownItems}\n${format(data.value[dataType])}`
});
function clicked(p) {
focus = focus === p ? p = p.parent : p;
root.each(d => d.target = {
x0: (d.x0 - p.x0) / (p.x1 - p.x0) * height,
x1: (d.x1 - p.x0) / (p.x1 - p.x0) * height,
y0: d.y0 - p.y0,
y1: d.y1 - p.y0
});
const t = cell.transition().duration(750)
.attr("transform", d => `translate(${d.target.y0},${d.target.x0})`);
rect.transition(t).attr("height", d => rectHeight(d.target));
text.transition(t).attr("fill-opacity", d => +labelVisible(d.target));
tspan.transition(t).attr("fill-opacity", d => labelVisible(d.target, true) * 0.7);
}
function rectHeight(d) {
return d.x1 - d.x0 - Math.min(1, (d.x1 - d.x0) / 2);
}
function labelVisible(d, override) {
if (override) return d.y1 <= width && d.y0 >= 0 && d.x1 - d.x0 > 28;
return d.y1 <= width && d.y0 >= 0 && d.x1 - d.x0 > 16;
}
return svg.node();
}