我有一个看似简单的d3.js
问题。我正在从一组json数据创建一个树。树由包含一些文本的矩形容器组成的标签组成。我想根据文本的长度更改矩形的宽度。我知道我应该做this one之类的事情,但我很难理解如何。
这是我的JS代码(删除了大多数不必要的装饰):
var rectW = 140, rectH = 40;
// Declare the nodes.
var node = draw.selectAll('g.node')
.data(nodes, function(d) { return d.id; });
// Enter the nodes.
var nodeLabel = node.enter().append('g')
.attr('transform', function(d) { return 'translate(' + source.x0 + ',' + source.y0 + ')'; });
var nodeRect = nodeLabel.append('rect')
.attr('width', rectW)
.attr('height', rectH);
var nodeText = nodeLabel.append('text')
.attr('x', rectW / 2)
.attr('y', rectH / 2)
.text(function (d) { return d.name; });
如您所见,我创建了一个SVG组,我将容器矩形和包含的文本都附加到该组。
现在,我想检索每个文本元素的长度,并使用它来更改相应矩形元素的宽度。我怎样才能做到这一点?我尝试了我能想到的D3
指令的所有可能组合,但是我对图书馆的了解并不足以满足我的目的。
更新 感谢Geraldo Furtado's回答,我设法通过添加以下内容来解决此问题:
// This arranges the width of the rectangles
nodeRect.attr("width", function() {
return this.nextSibling.getComputedTextLength() + 20;
})
// This repositions texts to be at the center of the rectangle
nodeText.attr('x', function() {
return (this.getComputedTextLength() + 20) /2;
})
答案 0 :(得分:2)
这是节点的当前结构:
<g>
<rect></rect>
<text></text>
</g>
在这种情况下,文本是矩形的nextSibling
。因此,获取文本长度所需的只是在矩形选择中使用nextSibling
:
nodeRect.attr("width", function() {
return this.nextSibling.getComputedTextLength() + rectW
})
我在这里添加rectW
以保持左右相同的填充,因为您要将文本从rectW / 2
开始。
如果您不确定文本和矩形(谁是第一个孩子,谁是最后一个孩子......)之间的关系,您可以上去,选择组元素,然后选择文本在里面:
nodeRect.attr("width", function() {
return d3.select(this.parentNode).select("text").node().getComputedTextLength() + rectW
})
这是一个基本演示:
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() {
return this.nextSibling.getComputedTextLength() + rectW
})
&#13;
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="300"></svg>
&#13;
为了存储计算出的宽度并在以后使用它,您可以设置另一个属性。例如:
nodeRect.attr("width", function(d) {
return d.rectWidth = this.nextSibling.getComputedTextLength() + rectW
});
这是演示,请看控制台:
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)
})
&#13;
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="300"></svg>
&#13;
答案 1 :(得分:0)
在设置文本后,您可以在脚本末尾添加以下行:
nodeRect
.transition()
.attr("width",function(){
return Math.max(rectW,nodeText.node().getComputedTextLength())
}).delay(0).duration(500)
我使用Math.max将其设置为rectW,如果它足够大或必要时展开。你可以改编那部分。