D3.js绘制容器后更改容器的宽度 [英] D3.js change width of container after it is drawn

查看:194
本文介绍了D3.js绘制容器后更改容器的宽度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个看似简单的d3.js问题.我正在从一组json数据创建一棵树.该树由标签组成,这些标签由环绕某些文本的矩形容器组成.我想根据文本的长度更改矩形的宽度.我了解我应该做类似的操作,但是我正在努力了解操作方法.

I have a seemingly simple d3.js problem. I am creating a tree from a set of json data. The tree is composed of labels that are composed of a rectangle container that wrap around some text. I would like to change the width of the rectangle according to the length of the text. I understand I should be doing something like this one, but I am struggling to understand how.

这是我的JS代码(简化了大多数不必要的装饰):

Here is my JS code (stripped down of most unnecessary frills):

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指令的所有可能组合,但是我对库的了解不足以适应我的目的.

As you can see, I create an SVG group to which I append both the container rectangle and the contained text. Now, I would like to retrieve the length of each text element, and use it to change the width of the corresponding rectangle element. How can I do that? I tried with every possible combination of D3 directives I could think of, but my knowledge of the library is not enough advanced to suit my purposes.

更新 感谢 Geraldo Furtado的答案,我设法通过添加以下内容来解决此问题:

UPDATE Thanks to Geraldo Furtado's answer, I managed to fix this issue by adding the following:

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

推荐答案

这是您节点的当前结构:

This is the current structure of your nodes:

<g>
    <rect></rect>
    <text></text>
</g>

在这种情况下,文本是矩形的nextSibling.因此,要获取文本的长度,只需在矩形选择中使用nextSibling:

That being the case, the texts are the nextSiblings 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() {
    return this.nextSibling.getComputedTextLength() + rectW
})

在这里,我要添加rectW以便在左侧和右侧保持相同的填充,因为您将文本从rectW / 2开始.

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

这是一个基本演示:

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

<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="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)
})

<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="300"></svg>

这篇关于D3.js绘制容器后更改容器的宽度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆