1

我正在尝试将换行应用于 d3 条形图中沿 x 轴的长变量标签。这是我在 Observable 笔记本中的图表:https ://observablehq.com/@unfpamaldives/figure4

我试图从这个块应用一个解决方案,主要包括以下内容:

function wrap(text, width) {
  text.each(function() {
    var text = d3.select(this),
        words = text.text().split(/\s+/).reverse(),
        word,
        line = [],
        lineNumber = 0,
        lineHeight = 1.1, // ems
        y = text.attr("y"),
        dy = parseFloat(text.attr("dy")),
        tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em")
    while (word = words.pop()) {
      line.push(word)
      tspan.text(line.join(" "))
      if (tspan.node().getComputedTextLength() > width) {
        line.pop()
        tspan.text(line.join(" "))
        line = [word]
        tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", `${++lineNumber * lineHeight + dy}em`).text(word)
      }
    }
  })
}  

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", `translate(0, ${height})`)
      .call(xAxis)
    .selectAll(".tick text")
      .call(wrap, x.bandwidth())

它看起来像 什么:我想要实现的目标: 我还尝试将函数移到其他地方,在代码的前面和后面,以及尝试移动以下几行在此处输入图像描述
在此处输入图像描述wrap

.selectAll(".tick text")
  .call(wrap, x.bandwidth())

从这段代码中的某个地方工作,如下所示:

xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
  .style("font-family", "HelveticaNeueLTStd-Cn")
  .style("font-size", "9px")
.call(d3.axisBottom(x).tickSizeOuter(0))
.selectAll(".tick text")
  .call(wrap, x.bandwidth())

但这不起作用(试图适应Bostock 的解决方案)。(我之前已经在其他 d3 可视化中使用了文本换行,这是值得的。)任何人都可以根据我的 Observable notebook的一个分支演示一个可行的解决方案吗?

4

2 回答 2

1

我成功地为Gerardo Furtado的这个示例中的 x 轴条形/变量标签应用了文本环绕技术。它需要以下代码:

  svg.append("g")
      .call(yAxis);

  const axis = svg.append("g")
      .call(xAxis);  

  setTimeout(()=>{
  axis.selectAll(".tick text")
      .style("font-family", "HelveticaNeueLTStd-Cn")
      .style("font-size", "9px")
    .call(wrap, x.bandwidth());
  }, 0); 

这是工作解决方案

于 2020-02-26T20:12:55.623 回答
0

无法正常工作的原因wrap(已在评论中暗示)是由于 Observable 的单元格如何运行。根据 Observable(和 D3)创建者 Mike Bostock 的说法,

[这个问题] 在 Observable 中很常见,因为标准模式是将单元格实现为“纯”函数,您可以在其中创建分离的元素并返回它们,然后将它们插入到 DOM 中;所以在一个单元格中,你应该几乎总是使用分离的元素。(来源

因此,当您调用时tspan.node().getComputedTextLength(),DOM 中还没有任何内容,因此它返回零。

正如您发现的那样,我的解决方案只是使用setTimeout0 毫秒的时间,因此当您需要测量元素时,这些元素将位于 DOM 中。有人可能会说这是 hacky,确实如此!顺便说一句,博斯托克的解决方案就是沿着这些思路......

const foo = html`<html structure here>`;
document.body.appendChild(foo);
//get the length of foo...
foo.remove();

... 就像 hacky 一样,甚至可能更多。

于 2020-02-27T00:39:46.693 回答