如何使用D3js和textwrap.js在文本框中包装文本

时间:2016-10-15 13:37:08

标签: javascript d3.js

我找到了这个很棒的插件,textwrap.js包含了很长的svg文本行。我在d3js上使用这个插件。我能够使用d3和json对象创建我的文本框和文本。但是当我应用textwrap.js函数时,文本将按预期进行换行,但它将从文本框中重新定位文本并将文本放在浏览器屏幕的左上角;忽略我在d3 selectAll文本结构中建立的x和y定位。 Textwrap.js不会包装文本并将其保留在文本框中。我玩了几种技术来包装文本并将其保存在特定的文本框中,但我没有发现任何快乐。我附加了当前代码,将包装好的文本放在左上角。我非常感谢您解决此问题的任何帮助(将包装好的文本放在文本框中)。提前谢谢。

链接到textwrap.js文档:https://github.com/kstohr/d3textwrap

<!DOCTYPE HTML>

<meta charset = "UTF-8" />
<head>

  <title>Text Wrap Practice</title>


<link href="myCSS_Style.css" rel="stylesheet" type="text/css"> 
<script src="jquery-1.10.2.min.js "></script>
<script src="d3.min.js"></script>
<script src="textwrap.js"></script><!---->
<script src="myJS.js"></script>
</head>

<body>

    <div id="chartData"></div>

</body>

</html>

$(document).ready(function(){

var width = 960,
    height = 500;

var svg = d3.select("#chartData").append("svg")
    .attr("width", width)
    .attr("height", height)


d3.json("data.json", function(json) {
       var elem = svg.selectAll("text")
        .data(json.nodes)

    var elemEnter = elem.enter()
        .append("g")

    var circle = elemEnter.append("rect")
        .attr("x", function(d){return d.x} )
        .attr("y", function(d){return d.y} )
        .attr("width", function(d){return d.w} )
        .attr("height", function(d){return d.h} )
        .attr("stroke","black")
        .attr("fill", "white")

    elemEnter.append("text")
        .attr("class",  function(d) { return "txtElem" + d.id; })
        .attr("x", function(d){return d.x + 50} )
        .attr("y", function(d){return d.y + 40} )
        .text(function(d){return d.label});

var wrap = d3.textwrap().bounds({height: 50, width: 250}); 

        d3.selectAll('text').call(wrap);



});

数据文件,data.json:

{&#34;节&#34;:[   {&#34; id&#34;:1,&#34; x&#34;:80,&#34; y&#34;:40,&#34; w&#34;:250,&#34; h& #34;:50,&#34;标签&#34;:&#34;这是我需要用textwrap&#34;}包裹的长文本1,   {&#34; id&#34;:2,&#34; x&#34;:200,&#34; y&#34;:160,&#34; w&#34;:250,&#34; h& #34;:50,&#34;标签&#34;:&#34;长文本2我喜欢在文本框中包装&#34;},   {&#34; id&#34;:3,&#34; x&#34;:380,&#34; y&#34;:280,&#34; w&#34;:250,&#34; h& #34;:50,&#34;标签&#34;:&#34;我的长篇文章3我试图将其包装到文本框中&#34;} ]}

1 个答案:

答案 0 :(得分:0)

I can force it to work if I call it like this:

d3.selectAll("text").each(function(){
  d3.select(this).textwrap(this.previousElementSibling.getBBox());
});

Full code:

<!DOCTYPE html>
<html>

  <head>
    <meta charset="UTF-8" />
    <title>Text Wrap Practice</title>
    <script src="https://d3js.org/d3.v3.min.js"></script>
    <script src="https://rawgit.com/kstohr/d3textwrap/master/d3textwrap.v0.js"></script>
  </head>

  <body>
    <div id="chartData"></div>
    <script>
  var width = 960,
    height = 500;

  var svg = d3.select("#chartData").append("svg")
    .attr("width", width)
    .attr("height", height);

  //d3.json("data.json", function(json) {
    
    var json = {"nodes":[{"id":1,"x":80,"y":40,"w":250,"h":50,"label":"This is my long text 1 that need to be wrapped by textwrap"},{"id":2,"x":200,"y":160,"w":250,"h":50,"label":"Long Text 2 I like to wrap in the text box"},{"id":3,"x":380,"y":280,"w":250,"h":50,"label":"My Long Text 3 I'm try to wrap into the text box"}]};
    
    var elem = svg.selectAll("text")
      .data(json.nodes)

    var elemEnter = elem.enter()
      .append("g")

    var circle = elemEnter.append("rect")
      .attr("x", function(d) {
        return d.x
      })
      .attr("y", function(d) {
        return d.y
      })
      .attr("width", function(d) {
        return d.w
      })
      .attr("height", function(d) {
        return d.h
      })
      .attr("stroke", "black")
      .attr("fill", "white")

    var textElements = elemEnter.append("text")
      .attr("class", function(d) {
        return "txtElem" + d.id;
      })
      .attr("x", function(d) {
        return d.x + 50
      })
      .attr("y", function(d) {
        return d.y + 40
      })
      .text(function(d) {
        return d.label
      });

    d3.selectAll("text").each(function(){
      d3.select(this).textwrap(this.previousElementSibling.getBBox());
    })

//});

  </script>
  </body>

</html>

To be honest, though, I find the plugin to be confusing and of dubious quality. When I need to wrap text I usually follow this example.

I'd refactor your code a bit and that example and in the end my code would look like this:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>Text Wrap Practice</title>
  <script src="https://d3js.org/d3.v3.min.js"></script>
  <script src="https://rawgit.com/kstohr/d3textwrap/master/d3textwrap.v0.js"></script>
</head>

<body>
  <div id="chartData"></div>
  <script>
    var width = 960,
      height = 500;

    var svg = d3.select("#chartData").append("svg")
      .attr("width", width)
      .attr("height", height);

    //d3.json("data.json", function(json) {

    var json = {
      "nodes": [{
        "id": 1,
        "x": 80,
        "y": 40,
        "w": 250,
        "h": 50,
        "label": "This is my long text 1 that need to be wrapped by textwrap"
      }, {
        "id": 2,
        "x": 200,
        "y": 160,
        "w": 250,
        "h": 50,
        "label": "Long Text 2 I like to wrap in the text box"
      }, {
        "id": 3,
        "x": 380,
        "y": 280,
        "w": 250,
        "h": 50,
        "label": "My Long Text 3 I'm try to wrap into the text box"
      }]
    };

    var elem = svg.selectAll("text")
      .data(json.nodes)

    var elemEnter = elem.enter()
      .append("g")
      .attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
      })

    var circle = elemEnter.append("rect")
      .attr("width", function(d) {
        return d.w
      })
      .attr("height", function(d) {
        return d.h
      })
      .attr("stroke", "black")
      .attr("fill", "white")

    var textElements = elemEnter.append("text")
      .attr("class", function(d) {
        return "txtElem" + d.id;
      })
      .text(function(d) {
        return d.label
      })
      .attr("y", 12);

    d3.selectAll("text").call(wrap, function(d) {
      return this.previousElementSibling.getBBox().width;
    });

    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")) || 0,
          tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");

        width = (typeof width === "function") ? width.call(this) : width;

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

    //});
  </script>
</body>

</html>