Reputation: 3427
I'm making a tree diagram where the node is a rectangle instead of a circle, and need the rectangle to show up at the right place with varying sizes - showing an 80x60 rectangle where type is 'tall box' in data, and 80x20 rectangle for all other nodes. This is the code.
var treeData = {
"name": "Top Level",
"children": [{
"name": "Level 2: A",
"type": "tall box",
"children": [{
"name": "long txt next line long txt",
"type": "tall box",
},
{
"name": "short txt"
}
]
},
{
"name": "Level 2: B"
}
]
};
// set the dimensions and margins of the diagram
var margin = {
top: 20,
right: 90,
bottom: 30,
left: 90
},
width = 860 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// declares a tree layout and assigns the size
var treemap = d3.tree()
.size([height, width]);
// assigns the data to a hierarchy using parent-child relationships
var nodes = d3.hierarchy(treeData, function(d) {
return d.children;
});
// maps the node data to the tree layout
nodes = treemap(nodes);
// append the svg object to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom),
g = svg.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// adds the links between the nodes
var link = g.selectAll(".link")
.data(nodes.descendants().slice(1))
.enter().append("path")
.attr("class", "link")
.attr("d", function(d) {
return "M" + d.y + "," + d.x +
"C" + (d.y + d.parent.y) / 2 + "," + d.x +
" " + (d.y + d.parent.y) / 2 + "," + d.parent.x +
" " + d.parent.y + "," + d.parent.x;
});
// adds each node as a group
var node = g.selectAll(".node")
.data(nodes.descendants())
.enter().append("g")
.attr("class", function(d) {
return "node" +
(d.children ? " node--internal" : " node--leaf");
})
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
});
// adds the circle to the node
node.append("rect")
.attr("class", "node")
.attr("width", 80)
.attr("height", 20)
.attr("rx", 10)
.attr("ry", 10)
.style("fill", "lightgrey");
// adds the text to the node
node.append("text")
.attr("dy", ".35em")
.attr("x", function(d) {
return d.children ? -13 : 13;
})
.style("text-anchor", "start")
.text(function(d) {
return d.data.name;
});
If I use conditional logic to vary the size, the rectangle isn't starting at the right place. How can I shift the starting position of the rectangle such that all the rectangles have the same center as the original circular node, or have the rectangles' heights accommodate varying text length? Thanks.
Upvotes: 0
Views: 1144
Reputation: 36
if you know the width exactly such as 80 * 20 and 80 * 60. you can do it like this
// adds the circle to the node
node.append("rect")
.attr("class", "node")
.attr("width", 80 )
.attr("height", d => d.data.type === 'tall box' ? 60 : 20)
.attr("rx", 10)
.attr("ry", 10)
.style('transform', d => d.data.type === 'tall box' ? 'translateY(-30px)' :
'translateY(-10px)')
.style("fill", "lightgrey");
or you wanna get a suitable-size you need to get the width and height of text
by getBBox()
.
sorry my english is poor and i hope it's helpful for you
Upvotes: 1