D3文本换行使用text-anchor:middle

时间:2018-01-24 18:10:13

标签: d3.js textwrapping

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

1 个答案:

答案 0 :(得分:3)

从{{3>} for text-anchor middle将产生以下结果:

  

对齐渲染的字符,使文本字符串的中间位于当前文本位置

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

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

    tspan.attr("x", 50)
    

    这是一个代码片段:

    &#13;
    &#13;
    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);
          }
        }
      });
    }
    &#13;
    #container {
      height: 200px;
      width: 100px;
      border: 1px solid red;
    }
    &#13;
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    <div id="container"></div>
    &#13;
    &#13;
    &#13;

  2. 另一种方法是应用&#39;转换&#39;属性如下:

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

    以下是使用此方法的代码段:

    &#13;
    &#13;
    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);
          }
        }
      });
    }
    &#13;
    #container {
      height: 200px;
      width: 100px;
      border: 1px solid red;
    }
    &#13;
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    <div id="container"></div>
    &#13;
    &#13;
    &#13;

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

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

    希望这会有所帮助。 :)