D3.js在绘制后改变容器的宽度

时间:2018-05-15 22:05:12

标签: javascript d3.js

我有一个看似简单的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;
})

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
})

这是一个基本演示:

&#13;
&#13;
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;
&#13;
&#13;

为了存储计算出的宽度并在以后使用它,您可以设置另一个属性。例如:

nodeRect.attr("width", function(d) {
    return d.rectWidth = this.nextSibling.getComputedTextLength() + rectW
});

这是演示,请看控制台:

&#13;
&#13;
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;
&#13;
&#13;

答案 1 :(得分:0)

在设置文本后,您可以在脚本末尾添加以下行:

nodeRect
.transition()
.attr("width",function(){
return Math.max(rectW,nodeText.node().getComputedTextLength())
}).delay(0).duration(500)

我使用Math.max将其设置为rectW,如果它足够大或必要时展开。你可以改编那部分。