D3:如何找到文本标签的最大长度?

时间:2015-12-05 20:40:45

标签: d3.js

如何找到文字标签的最大长度?我的代码返回93.8495px,但我可以看到最大的是246.8128px?

// Append legend labels.
var labels = svg.selectAll("text")
.data(pie(dataset))
.enter()
.append("text")
.text(function(d) {
  return d.data[0];
})

var maxTextWidth = d3.max(labels, function() {
  return labels.node().getComputedTextLength();
});
console.log(maxTextWidth);

labels.attr("font-family", "open-sans")
.attr("font-size", 16)
.attr("fill", "#333")
.attr("x", labelLeftMargin)
.attr("y", function(d, i) {
  return (i * labelHeight) - ((labelHeight * dataset.length) / 2) + keyRadius;
})

4 个答案:

答案 0 :(得分:4)

更新2017-08-09

事实证明,D3 v4 会让事情变得更容易。我添加了简化的解决方案,它应该是新版本的首选解决方案。尽管如此,我仍会保留原始答案作为仍然在v3上的人的参考。另外,请查看帖子末尾的旁注,这对两个版本都有效。

D3 v4

OP的使用d3.max(array[, accessor])在v4方面仍然不正确,如果出于其他原因而不是之前。选择lables现在是plain JavaScript object,而不是像v3中那样的数组数组。另一方面,d3.max()将处理数组,而不是对象。但是,与v3不同,v4通过selection.nodes()方法提供了对选择节点的轻松访问,该方法返回其包含的节点的平面数组。 d3.max()

可以轻松访问此数组
var maxTextWidth = d3.max(labels.nodes(), n => n.getComputedTextLength());

工作片段:

var labels = d3.selectAll("text");
var maxTextWidth = d3.max(labels.nodes(), n => n.getComputedTextLength());

console.log(maxTextWidth);
<script src="https://d3js.org/d3.v4.js"></script>

<svg width="400" height="400">
  <text x="50" y="100" font-family="monospace">IIIIIIIIIII</text>
  <text x="50" y="130" font-family="monospace">MMMMMMMMM</text>
  <text x="50" y="200" font-family="open-sans">IIIIIIIIIII</text>
  <text x="50" y="230" font-family="open-sans">MMMMMMMMM</text>
</svg>

D3 v3

您对d3.max(array[, accessor])的使用不正确:该函数将返回给定数组中的最大值。虽然您的labels选择是一个数组,但事情有点复杂。选择实际上是 array of arrays ,这就是为什么你的方法不会抛出错误但也不会返回有意义的结果。

此外,在你应该为数组的每个元素执行的回调中,你正在调用labels.node(),它将始终返回选择的第一个节点,这显然不是你想要的。

虽然Mark的answer速度更快,但他的代码在分组选择上运行时会有一些限制。据我所知,在您的代码中并非如此,但获得最大文本宽度的更通用,更健壮的方法将是这样的:

function getMaxTextWidth() {
  var maxTextWidth = 0;
  labels.each(function() {
    maxTextWidth = Math.max(maxTextWidth, this.getComputedTextLength());
  });
  return maxTextWidth;
}

受到马克关于偏好d3.max()超过selection.each()的评论的启发,我一直在思考,并想出了另一种利用D3自己的方法获得最大文字宽度的优雅方法:

function getMaxTextWidth2() {
  return d3.max(d3.merge(labels), function(d) {
    return d.getComputedTextLength();
  });
}

这使用d3.merge()展平数组,它构成了选择,将其移至d3.max(),避免selection.each()完成显式循环。虽然我从未在选择中看到d3.merge()的使用,但它对原始选择没有任何影响,并且对于这些不关心分组的操作非常方便,只需要包含所有元素的平面数组选择中。

旁注(两者,v3和v4)

我想到的另一件事是,在获取文字宽度后,您正在操纵标签的属性font-familyfont-size 。这些更改显然会对最大文本宽度产生影响。从您提供的片段判断,目前尚不清楚这是否是故意的。

var labels = d3.selectAll("text");

function getMaxTextWidth() {
  var maxTextWidth = 0;
  labels.each(function() {
    maxTextWidth = Math.max(maxTextWidth, this.getComputedTextLength());
  });
  return maxTextWidth;
}
console.log(getMaxTextWidth());
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<svg width="400" height="400">
  <text x="50" y="100" font-family="monospace">IIIIIIIIIII</text>
  <text x="50" y="130" font-family="monospace">MMMMMMMMM</text>
  <text x="50" y="200" font-family="open-sans">IIIIIIIIIII</text>
  <text x="50" y="230" font-family="open-sans">MMMMMMMMM</text>
</svg>

答案 1 :(得分:1)

d3.max来电是不正确的。它始终会返回标签选择中第一个text的长度。相反,尝试:

var maxTextWidth = d3.max(labels[0], function(d) {
  return d.getComputedTextLength();
});

完整的工作代码:

&#13;
&#13;
<!DOCTYPE html>
<html>

  <head>
    <script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
  </head>

  <body>
    <svg>
      <text>;kladjflk;asdjflkjasdflkjasdfkl</text>
      <text>adkljfalskdjflk;asdfjkldddddddddddddasdjrrrrrr</text>
      <text>akl;dfjladksjf</text>
    </svg>
    <script>
      var labels = d3.selectAll('text');
      var maxTextWidth = d3.max(labels[0], function(d) {
        return d.getComputedTextLength();
      });
      console.log(maxTextWidth)
      
    </script>
  </body>

</html>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

如上所述,该解决方案仅在您刚刚加入数据时才有效。但是,如果您要访问以前配置的元素,例如通过

var labels = svg.selectAll("text");

所描述的解决方案不起作用,因为标签[0]将是未定义的。在这种情况下,一种解决方案是添加nodes()函数以获取所需的数组,然后省略d3.max调用中的数组索引说明符。

var labels = svg.selectAll("text").nodes();
.data();
var maxTextWidth = d3.max(labels, function(d) {
  return d.getComputedTextLength();
});

答案 3 :(得分:0)

对于某些svg中的大多数节点选择,其他答案更好。

然而,我怀疑很多人会(像我一样)专门问这个问题,以便找到图表轴上最大数字的文本长度。在这种情况下,您知道哪个项目是最大的,因为您绘制了图表。通常它将是最后一项;我们倾向于从最小数字开始绘制轴,并以最大数字结束。在这种情况下,您可以获得如下所示的最大文本长度:

const labels = yourGroovyAxis.selectAll('text')._groups[0];
const maxTextWidth = labels[labels.length - 1].getComputedTextLength();

如果您知道最大值将是第一项,则问题会更加简单。您只需使用select

即可
const maxTextWidth = yourGroovyAxis.select('text').getComputedTextLength();

同样,这只回答了OP提出的问题空间的一个子集。但是,对于那些处于我所描述的情况的人来说,这个解决方案我更直接。