带文本锚点的D3文本换行:中 [英] D3 text wrap with text-anchor: middle

查看:43
本文介绍了带文本锚点的D3文本换行:中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在D3中,我想包装带有中间文本锚点的文本.我查看了来自Mike Bostok的示例,但我无法完全理解设置.

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

  var plot = d3.select(容器).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(棕狐跳!").call(wrap,100);函数wrap(文本,宽度){text.each(function(){var text = d3.select(this),单词= text.text().split(/\ s +/).reverse(),单词,行= [],lineNumber = 0,lineHeight = 1.1,//emsy = text.attr("y"),dy = 1tspan = 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("));如果(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(单词);}}});} 

给出来自 Shashank 的指针,现在我可以使用翻译方法将文本放置在中央.仅仅设置文本的y似乎并没有改变任何东西.我还添加了yTrack变量,以便能够继续在已包装的文本下方进行绘制.

 让yTrack = 100,情节= d3.select(容器).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(快速的棕色狐狸跳过那只懒狗.").call(wrap,100);让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');函数wrap(文本,宽度){text.each(function(){让text = d3.select(this),单词= text.text().split(/\ s +/).reverse(),单词,行= [],lineNumber = 0,lineHeight = 1.1,//emsx = 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("));如果(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(单词);}}});}  

  #container {高度:200px;宽度:100px;边框:1px纯红色;}  

 < script src ="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js></script>< div id ="container"></div>  

解决方案

来自文档用于文本锚中间将导致以下结果:

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

在您的情况下,当您将文本分解为 x 等于 0 tspan s时-当前文本位置将是svg的开始位置(即,在点0处).另外,应用于 text 元素的 x:50 完全无关紧要.

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

      tspan.attr("x",50) 

    这是一个摘要:

      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(棕狐跳!").call(wrap,100);var height = plot.select('text').node().getBoundingClientRect().height;plot.select('text').attr('y',100-height/2);函数wrap(文本,宽度){text.each(function(){var text = d3.select(this),单词= text.text().split(/\ s +/).reverse(),单词,行= [],lineNumber = 0,lineHeight = 0.1,//emsy = text.attr("y"),dy = 1tspan = 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("));如果(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(单词);}}});}  

      #container {高度:200px;宽度:100px;边框:1px纯红色;}  

     < script src ="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js></script>< div id ="container"></div>  

  2. 另一种方法是通过以下方式将'transform'属性应用于文本:

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

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

      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(棕狐跳!").call(wrap,100);var height = plot.select('text').node().getBoundingClientRect().height;plot.select('text').attr('transform','translate(50,'+(100-height/2)+')');函数wrap(文本,宽度){text.each(function(){var text = d3.select(this),单词= text.text().split(/\ s +/).reverse(),单词,行= [],lineNumber = 0,lineHeight = 0.1,//emsy = text.attr("y"),dy = 1tspan = 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("));如果(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(单词);}}});}  

      #container {高度:200px;宽度:100px;边框:1px纯红色;}  

     < script src ="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js></script>< div id ="container"></div>  

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

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

希望这会有所帮助.:)

In D3 I would like to wrap texts which have a middle text anchor. I looked at this example from Mike Bostok but I cannot wrap my head around the settings.

I would like to see the text to be in the center (horizontal and vertical) of the red box.

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

Given the pointers from Shashank I was now able to position the text central with the translate method. Just setting the y of the text didn't seem to change anything. I also added a yTrack variable to be able to continue drawing below the wrapped text.

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>

解决方案

From the docs for text-anchor, middle will result in the following:

The rendered characters are aligned such that the middle of the text string is at the current text position.

and in your case, as you are breaking down the text into tspans with x equal to 0 -- the current text position would be the start of the svg (i.e. at point 0). Also, the x:50 applied to the text element wouldn't matter at all.

  1. One approach would be to apply the center value i.e. 50 to the tspans:

    tspan.attr("x", 50)
    

    Here's a snippet doing that:

    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. Another approach would be to apply 'transform' property to the text in the following way:

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

    Here's a snippet with this method:

    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>

In both of the above approaches, I'm not using the y-center value i.e. 100 instead I'm calculating the mid-point based on the text height as well using getBoundingClientRect() function.

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

Hope this helps. :)

这篇关于带文本锚点的D3文本换行:中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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