score:8
So the following approach can give different levels of the layout different "heights". You have to take care that with a radial layout you risk not having enough spread for small circles to fan your text without overlaps, but let's ignore that for now.
The key is to realize that the tree layout simply maps things to an arbitrary space of width and height and that the diagonal projection maps width (x) to angle and height (y) to radius. Moreover the radius is a simple function of the depth of the tree.
So here is a way to reassign the depths based on the text lengths:
First of all, I use the following (jQuery) to compute maximum text sizes for:
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};
}
Now I will recursively build an array with an array of strings per level:
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);
And then compute the maximum text length per level.
var maxLevelSizes = [];
allStrings.forEach(function(d, i) {
maxLevelSizes.push(computeMaxTextSize(allStrings[i], '10', 'sans-serif'));
});
Then I compute the total text width for all the levels (adding spacing for the little circle icons and some padding to make it look nice). This will be the radius of the final layout. Note that I will use this same padding amount again later on.
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; });
Now we can call the layout as usual. There is one last piece: to figure out the radius for the different levels we will need a cumulative sum of the radii of the previous levels. Once we have that we simply assign the new radii to the computed nodes.
// 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];
});
Eh voila! This is maybe not the cleanest solution, and perhaps does not address every concern, but it should get you started. Have fun!
Source: stackoverflow.com
Related Query
- How to avoid the overlapping of text elements on the TreeMap when child elements are opened in D3.js?
- d3.js - How can I set the cursor to hand when mouseover these elements on SVG container?
- How to update elements of D3 force layout when the underlying data changes
- Why do the mouseenter/mouseleave events fire when entering/leaving child elements in an SVG?
- When running a D3 update/enter/exit, how to ignore already exiting elements during the new exit?
- How to place text on the circle when using D3.js force layout?
- How do I hide the text labels in d3 when the nodes are too small?
- How to update child elements when changing data?
- d3v4 Zoomable Treemap - how to avoid overlay of child rects?
- How to get the same text of each elements in heat map as the y axis label?
- Button with text label: How do I keep the hover color even when over text label?
- How to simultaneously update the color of elements in a SVG when I mouseover elements of a second SVG using D3
- How Can I highlight the parents names and the connection lines when I hover on their child in family tree
- How to avoid the line overlapping on node and reroute the line in d3js
- How to Show all the child nodes when there are many
- How can I add text to SVG elements in D3 using the example below
- How can I get the bounding box values of all the text elements in a selection?
- D3 - How can I show/hide a text element when hovering a circle element created from different attributes of the same data entry?
- D3: How to stop child nodes from being attracted towards the center when parent is dragged in force-directed tree?
- How to avoid overlapping and stack long text legends in D3 graph?
- How to add text on top the heatmap to properly show value for each rectangle when using D3.js?
- How can I toggle the value of an svg text element with D3.js when user clicks the text?
- d3: Optionally add child elements based on node content in force layout - when filter is not the solution
- How to show full text when zoom in & truncate it when zoom out
- D3 grouped bar chart: How to rotate the text of x axis ticks?
- How to update the fill color on existing svg elements with d3.js?
- How to change text elements in d3?
- How to avoid labels overlapping in a D3.js pie chart?
- How to show and hides nodes when you move the mouse over a node in D3 Javascript
- D3, SVG and textPath: How to move the text down?
More Query from same tag
- Ajax not working when get data based on input for D3
- How to append text to SVG
- d3.zoom unexpected behavior: what am I missing?
- Remove column space in table created with d3
- on ("click") not working with d3 circle
- vanilla javascript to Reactjs component?
- d3.js - v3 and v4 - Enter and Update differences
- How to get striped grey background resembling 100% to the barchart?
- d3 zoom - how to set initial transform
- Angular data issue- not sure how to troubleshoot
- How to use Meteor and D3 to draw circles?
- D3 (with Bootstrap grid layout) - tooltip placement is off
- How to change text elements in d3?
- Is there a way to get a subset/section of a path in d3.js?
- Cross Hairs component throws error, dataset specific?
- trying to understand javascript code
- d3 graph - How do I make the JS get the JSON from PHP script and then select axes and plot?
- Animation is smooth in Chrome, but not in Firefox
- js timeseries/waterfall graph within table
- Compose two rotations in D3 geo projection?
- Unable to deploy a Rails 6 app using d3. Runs locally but Heroku build breaks: ModuleNotFoundError: Module not found: Error: Can't resolve 'd3'
- D3 Invert Selection From Event Listener (this)
- d3 mouseover event wont fire if I append svg to a div
- D3 transitions - pause and resume
- How to draw an ellipse from degree and coordinates
- Replace svg element with icon
- Trouble creating a hover tooltip
- Select an element in contained DOM tree using d3.js
- D3.js - Autoresize of y axis labels
- Prevent D3 adding duplicates on update