I have a simple D3 treemap.
When a user clicks the treemap, I'd like to show a subset of the data. My goal is to have each of the cells in the update resize, so that all the blue cells fill the original blue cell area, the red cells fill the original red cell area, and so forth.
I thought d3.treemapResquarify would magically take care of this, but I'm clearly missing something!
var data;
var width = 600,
height = 500;
var svg = d3.select('svg')
.attr('width', width)
.attr('height', height)
var fader = color => d3.interpolateRgb(color, '#fff')(0.2),
color = d3.scaleOrdinal(d3.schemeCategory20.map(fader)),
format = d3.format(',d');
var treemap = d3.treemap()
.tile(d3.treemapResquarify)
.size([width, height])
.round(true)
.paddingInner(1);
var url = 'https://raw.githubusercontent.com/d3/d3-hierarchy/master/test/data/flare.json';
d3.json(url, function(error, json) {
data = json;
var root = getTreeRoot(data);
treemap(root);
draw(root);
});
function draw(root) {
var leaves = root.leaves()
var cell = svg.selectAll('g').data(leaves, d => d.id)
cell.exit().remove()
var g = cell.enter()
.append('g')
.attr('transform', d => 'translate(' + d.x0 + ',' + d.y0 + ')')
g.append('rect')
.attr('width', d => d.x1 - d.x0)
.attr('height', d => d.y1 - d.y0)
.attr('fill', d => color(d.parent.data.id));
g.append('text')
.attr('clip-path', d => 'url(#clip-' + d.data.id + ')')
.selectAll('tspan')
.data(d => d.data.name.split(/(?=[A-Z][^A-Z])/g))
.enter().append('tspan')
.attr('x', 4)
.attr('y', (d, i) => 13 + i * 10)
.text(d => d)
}
function getTreeRoot(data) {
return d3.hierarchy(data)
.eachBefore(d => {d.data.id = (d.parent ? d.parent.data.id + '.' : '') + d.data.name })
.sum(d => d.value)
.sort((a, b) => b.height - a.height || b.value - a.value)
}
/**
* Transitions
**/
window.addEventListener('click', () => {
var newData = JSON.parse(JSON.stringify(data));
mutateChildren(newData);
var root = getTreeRoot(newData);
treemap(root);
draw(root);
})
function mutateChildren(data) {
data.children = data.children.filter(c => {
if (c.children && c.children.length) mutateChildren(c);
return Math.random() > 0.5;
});
}
text { font-size: 9px; font-family: 'courier' }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg>
When updating the display, I suppose I could find the parent nodes of each group, find their sizes and offsets, then build new treemaps for each of those groups to make the children fill that parent container. But this can't possibly be the right way forward...
Does anyone know how I can resize the cells so as to fill their parent group? Any pointers others can offer on this question would be super appreciated!