【问题标题】:D3 text wrap with text-anchor: middleD3 使用文本锚的文本换行:中间
【发布时间】:2018-01-24 18:10:13
【问题描述】:

在 D3 中,我想包装具有中间文本锚点的文本。我查看了this example from Mike Bostok,但无法完全理解这些设置。

我希望文本位于红色框的中心(水平和垂直)。

var plot = d3.select(container)
  .insert("svg")
  .attr('width', 100)
  .attr('height', 200);

plot.append("text")
  .attr("x", 50)
  .attr("y", 100)
  .attr("text-anchor", "middle")
  .attr("alignment-baseline", "alphabetic")
  .text("The brown fox jumps!")
  .call(wrap, 100);


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 = 1,
      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);
      }
    }
  });
}

鉴于来自Shashank 的指针,我现在可以使用 translate 方法将文本定位在中心位置。只是设置文本的 y 似乎并没有改变任何东西。我还添加了一个 yTrack 变量,以便能够在包裹的文本下方继续绘图。

let yTrack = 100,
  plot = d3.select(container)
  .insert("svg")
  .attr('width', 100)
  .attr('height', 200);

plot.append("text")
  .attr("x", 50)
  .attr("y", yTrack)
  .attr("text-anchor", "middle")
  .attr("font-family", "sans-serif")
  .text("The quick brown fox jumps over the lazy dog.")
  .call(wrap, 100);

let height = parseInt(plot.select('text').node().getBoundingClientRect().height);

plot.select("text").attr('transform', 'translate(0, ' + (-height / 2) + ')');

//plot.select("text").attr('y', 0);

yTrack += (parseInt(height / 2) + 10);

plot.append('rect')
  .attr("x", 0)
  .attr("y", yTrack)
  .attr("width", 100)
  .attr("height", 10)
  .style('fill', '#999');

function wrap(text, width) {
  text.each(function() {
    let text = d3.select(this),
      words = text.text().split(/\s+/).reverse(),
      word,
      line = [],
      lineNumber = 0,
      lineHeight = 1.1, // ems
      x = text.attr("x"),
      y = text.attr("y"),
      dy = 1.1,
      tspan = text.text(null).append("tspan").attr("x", x).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", x).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
      }
    }
  });
}
#container {
  height: 200px;
  width: 100px;
  border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="container"></div>

【问题讨论】:

  • Regulär svg 文本无法轻松重新定位。您可能会考虑将文本放入 中。然后你可以使用css和html

标签: d3.js word-wrap


【解决方案1】:

text-anchordocsmiddle 将产生以下结果:

对齐呈现的字符,使得文本字符串的中间位于当前文本位置

在您的情况下,当您将文本分解为 tspans 时,x 等于 0 - 当前文本位置 将是 svg 的开始(即在点 0)。此外,应用于text 元素的x:50 根本不重要。

  1. 一种方法是将中心值(即 50)应用于tspans:

    tspan.attr("x", 50)
    

    这是一个 sn-p 这样做的:

    var plot = d3.select(container)
      .insert("svg")
      .attr('width', 100)
      .attr('height', 200);
    
    plot.append("text")
      .attr("text-anchor", "middle")
      .attr("alignment-baseline", "alphabetic")
      .text("The brown fox jumps!")
      .call(wrap, 100);
    
    var height = plot.select('text').node().getBoundingClientRect().height;
    plot.select('text').attr('y', 100-height/2);
    
    function wrap(text, width) {
      text.each(function() {
        var text = d3.select(this),
          words = text.text().split(/\s+/).reverse(),
          word,
          line = [],
          lineNumber = 0,
          lineHeight = 0.1, // ems
          y = text.attr("y"),
          dy = 1,
          tspan = text.text(null).append("tspan").attr("x", 50).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", 50).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
          }
        }
      });
    }
    #container {
      height: 200px;
      width: 100px;
      border: 1px solid red;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    <div id="container"></div>
  2. 另一种方法是通过以下方式将“转换”属性应用于文本:

    plot.select('text').attr('transform', 'translate(50, ' + (100-height/2)+')');
    

    这是一个使用此方法的 sn-p:

    var plot = d3.select(container)
      .insert("svg")
      .attr('width', 100)
      .attr('height', 200);
    
    plot.append("text")
      .attr("text-anchor", "middle")
      .attr("alignment-baseline", "alphabetic")
      .text("The brown fox jumps!")
      .call(wrap, 100);
    
    var height = plot.select('text').node().getBoundingClientRect().height;
    plot.select('text').attr('transform', 'translate(50, ' + (100-height/2)+')');
    
    function wrap(text, width) {
      text.each(function() {
        var text = d3.select(this),
          words = text.text().split(/\s+/).reverse(),
          word,
          line = [],
          lineNumber = 0,
          lineHeight = 0.1, // ems
          y = text.attr("y"),
          dy = 1,
          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);
          }
        }
      });
    }
    #container {
      height: 200px;
      width: 100px;
      border: 1px solid red;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    <div id="container"></div>

在上述两种方法中,我都没有使用 y 中心值,即 100,而是使用 getBoundingClientRect() 函数根据文本高度计算中点.

var height = plot.select('text').node().getBoundingClientRect().height;
plot.select('text').attr('y', 100-height/2);

希望这会有所帮助。 :)

【讨论】:

  • 天才...非常感谢。方法 2(翻译)正是我需要的,所以我会继续这样做。知道为什么即使我使用 plot.select("text").attr('y', 0);绘制的文本的 y 位置根本没有改变?也许我错过了更新声明。我自己对 D3 很陌生。
  • 很高兴我能帮上忙。这是因为文本被翻译成(100-height/2),它定义了新的起点,即如果y 设置为0,它将不再从矩形的中心移动。尝试将y 设置为10,您将看到文本如何偏移。如果您使用translate 并且想要将文本放在顶部,只需使用translate(50, height/2)
猜你喜欢
  • 2012-11-05
  • 1970-01-01
  • 1970-01-01
  • 2015-09-28
  • 1970-01-01
  • 1970-01-01
  • 2017-11-03
  • 2023-03-14
  • 1970-01-01
相关资源
最近更新 更多