所以下面的做法可以给不同层次的布局不同的“高度”。您必须注意,如果使用径向布局,您可能没有足够的散布来让小圆圈散开您的文本而不会重叠,但现在让我们忽略这一点。
关键是要认识到,树布局只是将事物映射到具有宽度和高度的任意空间,并且对角线投影将宽度 (x) 映射到角度,将高度 (y) 映射到半径。此外,半径是树深度的简单函数。
所以here 是一种根据文本长度重新分配深度的方法:
首先,我使用以下 (jQuery) 来计算最大文本大小:
var computeMaxTextSize = function(data, fontSize, fontName){
var maxH = 0, maxW = 0;
var div = document.createElement('div');
document.body.appendChild(div);
$(div).css({
position: 'absolute',
left: -1000,
top: -1000,
display: 'none',
margin:0,
padding:0
});
$(div).css("font", fontSize + 'px '+fontName);
data.forEach(function(d) {
$(div).html(d);
maxH = Math.max(maxH, $(div).outerHeight());
maxW = Math.max(maxW, $(div).outerWidth());
});
$(div).remove();
return {maxH: maxH, maxW: maxW};
}
现在我将递归地构建一个数组,每个级别都有一个字符串数组:
var allStrings = [[]];
var childStrings = function(level, n) {
var a = allStrings[level];
a.push(n.name);
if(n.children && n.children.length > 0) {
if(!allStrings[level+1]) {
allStrings[level+1] = [];
}
n.children.forEach(function(d) {
childStrings(level + 1, d);
});
}
};
childStrings(0, root);
然后计算每个级别的最大文本长度。
var maxLevelSizes = [];
allStrings.forEach(function(d, i) {
maxLevelSizes.push(computeMaxTextSize(allStrings[i], '10', 'sans-serif'));
});
然后我计算所有级别的总文本宽度(添加小圆圈图标的间距和一些填充以使其看起来不错)。这将是最终布局的半径。请注意,稍后我将再次使用相同的填充量。
var padding = 25; // Width of the blue circle plus some spacing
var totalRadius = d3.sum(maxLevelSizes, function(d) { return d.maxW + padding});
var diameter = totalRadius * 2; // was 960;
var tree = d3.layout.tree()
.size([360, totalRadius])
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
现在我们可以像往常一样调用布局了。最后一点:要计算出不同级别的半径,我们需要前一个级别的半径的累积和。一旦我们有了它,我们只需将新半径分配给计算节点。
// Compute cummulative sums - these will be the ring radii
var newDepths = maxLevelSizes.reduce(function(prev, curr, index) {
prev.push(prev[index] + curr.maxW + padding);
return prev;
},[0]);
var nodes = tree.nodes(root);
// Assign new radius based on depth
nodes.forEach(function(d) {
d.y = newDepths[d.depth];
});
哎呀!这可能不是最干净的解决方案,也可能无法解决所有问题,但它应该可以帮助您入门。玩得开心!