D3.js Change Width Of Container After It Is Drawn
Solution 1:
This is the current structure of your nodes:
<g><rect></rect><text></text></g>
That being the case, the texts are the nextSibling
s of the rectangles. Therefore, all you need to get the length of the texts is using nextSibling
in the rectangle selection:
nodeRect.attr("width", function() {
returnthis.nextSibling.getComputedTextLength() + rectW
})
Here I'm adding rectW
to keep the same padding on the left and right, since you're putting the texts to start at rectW / 2
.
If you're not sure about the relationship between the texts and rectangles (who is the first child, who is the last child...), you can go up, select the group element and then select the text inside it:
nodeRect.attr("width", function() {
return d3.select(this.parentNode).select("text").node().getComputedTextLength() + rectW
})
Here is a basic demo:
var data = [{
name: "some text",
x: 10,
y: 10
},
{
name: "A very very very long text here",
x: 100,
y: 50
},
{
name: "Another text, this time longer than the previous one",
x: 25,
y: 100
},
{
name: "some short text here",
x: 220,
y: 150
}
];
var svg = d3.select("svg");
var rectW = 140,
rectH = 30;
var node = svg.selectAll(null)
.data(data);
var nodeLabel = node.enter().append('g')
.attr('transform', function(d) {
return'translate(' + d.x + ',' + d.y + ')';
});
var nodeRect = nodeLabel.append('rect')
.attr('width', rectW)
.attr('height', rectH)
.style("fill", "none")
.style("stroke", "gray")
var nodeText = nodeLabel.append('text')
.attr('x', rectW / 2)
.attr('y', rectH / 2)
.style("dominant-baseline", "central")
.text(function(d) {
return d.name;
});
nodeRect.attr("width", function() {
returnthis.nextSibling.getComputedTextLength() + rectW
})
<scriptsrc="https://d3js.org/d3.v5.min.js"></script><svgwidth="500"height="300"></svg>
For storing the computed width and using it later on, you can set another property. For instance:
nodeRect.attr("width", function(d) {
return d.rectWidth = this.nextSibling.getComputedTextLength() + rectW
});
Here is the demo, look at the console:
var data = [{
name: "some text",
x: 10,
y: 10
},
{
name: "A very very very long text here",
x: 100,
y: 50
},
{
name: "Another text, this time longer than the previous one",
x: 25,
y: 100
},
{
name: "some short text here",
x: 220,
y: 150
}
];
var svg = d3.select("svg");
var rectW = 140,
rectH = 30;
var node = svg.selectAll(null)
.data(data);
var nodeLabel = node.enter().append('g')
.attr('transform', function(d) {
return'translate(' + d.x + ',' + d.y + ')';
});
var nodeRect = nodeLabel.append('rect')
.attr('width', rectW)
.attr('height', rectH)
.style("fill", "none")
.style("stroke", "gray")
var nodeText = nodeLabel.append('text')
.attr('x', rectW / 2)
.attr('y', rectH / 2)
.style("dominant-baseline", "central")
.text(function(d) {
return d.name;
});
nodeRect.attr("width", function(d) {
return d.rectWidth = this.nextSibling.getComputedTextLength() + rectW
});
nodeLabel.each(function(d) {
console.log(d)
})
<scriptsrc="https://d3js.org/d3.v5.min.js"></script><svgwidth="500"height="300"></svg>
Solution 2:
You can add the following line at the end of your script, after the text has been set:
nodeRect
.transition()
.attr("width",function(){
return Math.max(rectW,nodeText.node().getComputedTextLength())
}).delay(0).duration(500)
I used Math.max to set it to rectW if its large enough or expand if necessary. You can perhaps adapt that part.
Post a Comment for "D3.js Change Width Of Container After It Is Drawn"