Reputation: 931
Is there a way in d3's packing layout to set the radius of a child node manually, with a size relative to the parent radius, and then have the other children set their radius' based on the remaining space and using the existing "size by number of children"?
What I would like to do is: 1. for each node add a node to the children array with the same name as the parent 2. set the radius of this extra child to have a significant enough radius to contain text and ensure no overlap from its neighbors 3. set fill and stroke to none on this extra node 4. set the click interaction via css to none on this extra node 5. use only these extra nodes to display "their" names (aka their parent's names)
The result would be a packed circle with a specially designated space for its labels. This does not work without a manual setting of the extra child node's radius because it's size is automatically determined based on the number of children. (adding children unfilled/unstroked nodes to compensate is extremely inefficient. The second hack for the first hack just wouldn't be worth it I don't think)
Upvotes: 2
Views: 1083
Reputation: 931
This answer is the solution I am using for now, and builds upon the solution Ganesh provided.
Summary of Ganesh's solution:
Remaining Issues for my use of Ganesh's solution:
Solution and key findings:
The final version of my value function, based on Ganesh's solution is provided below:
var pack = d3.layout.pack()
.value(function(d){
if(d.isExtra){ //the property added to injected label nodes
d.value = d.parent.treeSize*100 //treeSize = size of subTree
return d.value;
}
else{
d.value = d.treeSize*100;
return d.value;
}
})
.size([width, height -100 ])
It is important to note here that while I am introducing a new node with a value equal to it's parent node times 100, this does not mean that it takes 100 times the space of the circle. This is because a parent's value is ultimately the sum of it's children's values, which means that any node that had a child, will see an increase in total value. Multiplying the treeSize for label nodes by significantly higher numbers only provides a logarithmic increase in corresponding circle size, while introducing a larger and larger gap between leaf node size (100) and the rest of the circles.
Upvotes: 0
Reputation: 1599
Please check if this helps you.The circles with red background with with class 'extra' is the extra circles with parent's name.
var root = {
"name": "flare",
"children": [
{
"name": "analytics",
"children": [
{
"name": "cluster",
"children": [
{"name": "AgglomerativeCluster", "size": 3938},
{"name": "CommunityStructure", "size": 3812},
{"name": "HierarchicalCluster", "size": 6714},
{"name": "MergeEdge", "size": 743}
]
},
{
"name": "graph",
"children": [
{"name": "BetweennessCentrality", "size": 3534},
{"name": "LinkDistance", "size": 5731},
{"name": "MaxFlowMinCut", "size": 7840},
{"name": "ShortestPaths", "size": 5914},
{"name": "SpanningTree", "size": 3416}
]
},
{
"name": "optimization",
"children": [
{"name": "AspectRatioBanker", "size": 7074}
]
}
]
},
{
"name": "animate",
"children": [
{"name": "Easing", "size": 17010},
{"name": "FunctionSequence", "size": 5842},
{
"name": "interpolate",
"children": [
{"name": "ArrayInterpolator", "size": 1983},
{"name": "ColorInterpolator", "size": 2047},
{"name": "DateInterpolator", "size": 1375},
{"name": "Interpolator", "size": 8746},
{"name": "MatrixInterpolator", "size": 2202},
{"name": "NumberInterpolator", "size": 1382},
{"name": "ObjectInterpolator", "size": 1629},
{"name": "PointInterpolator", "size": 1675},
{"name": "RectangleInterpolator", "size": 2042}
]
},
{"name": "ISchedulable", "size": 1041},
{"name": "Parallel", "size": 5176},
{"name": "Pause", "size": 449},
{"name": "Scheduler", "size": 5593},
{"name": "Sequence", "size": 5534},
{"name": "Transition", "size": 9201},
{"name": "Transitioner", "size": 19975},
{"name": "TransitionEvent", "size": 1116},
{"name": "Tween", "size": 6006}
]
},
]
};
var addExtraNode = function(item, percentSize){
var percentSizeOfNode = percentSize || 60; //if not given it will occupy 60 percent of the space
if(!item.children){
return;
}
var totalChildSize = 0;
item.children.forEach(function(citm, index){
totalChildSize = totalChildSize + citm.size;
})
var nodeSize = (percentSizeOfNode / 50) * totalChildSize;
var name = 'NAME: '+item.name;
item.children.push({
'name': name,
'size': nodeSize,
'isextra':true
})
item.children.forEach(function(citm, index){
if(citm.children){
addExtraNode(citm, percentSize);
}
})
};
addExtraNode(root, 55);
var diameter = 500,
format = d3.format(",d");
var pack = d3.layout.pack()
.size([diameter - 4, diameter - 4])
.value(function(d) { return d.size; });
var svg = d3.select("body").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.append("g")
.attr("transform", "translate(2,2)");
var node = svg.datum(root).selectAll(".node")
.data(pack.nodes)
.enter().append("g")
.attr("class", function(d) {
if(d.isextra){
return 'extra';
}
return d.children ? "node" : "leaf node"; })
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node.append("title")
.text(function(d) { return d.name + (d.children ? "" : ": " + format(d.size)); });
node.append("circle")
.attr("r", function(d) { return d.r; });
node.filter(function(d) { return !d.children; }).append("text")
.attr("dy", ".3em")
.style("text-anchor", "middle")
.text(function(d) { return d.name.substring(0, d.r / 3); });
circle {
fill: rgb(31, 119, 180);
fill-opacity: .25;
stroke: rgb(31, 119, 180);
stroke-width: 1px;
}
.leaf circle {
fill: #ff7f0e;
fill-opacity: 1;
}
text {
font: 10px sans-serif;
}
.extra circle{
fill:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Upvotes: 1