user2891996
user2891996

Reputation: 59

Text does not stay wrapped on d3 tree nodes

complete d3 newbie here. I have this d3 tree that I'm using (here's the working jsfiddle https://jsfiddle.net/Joe123/vq4jpr1s/16/) and I have it so that the text for each node wraps to the size of the node. However, upon multiple clicks on the same node as you'll see, the text reverts back to being unwrapped and I cannot figure out why. Does anyone have any ideas? any help would be greatly appreciated.

Here is the wrap function:

    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,
      y = text.attr("y"),
      dy = parseFloat(text.attr("dy")),
      tspan = text.text(null).append("tspan").attr("x", 5).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", 5).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
      }
    }
    d3.select(this.parentNode.children[0]).attr("height", 20 * (lineNumber+1));


  });
}

wrap(d3.selectAll('text'),150);

And below is the click function, I tried calling the wrap function from here but no luck.

function click(d) {

  if (d.children) {
    d._children = d.children;
    d.children = null;

  } else {
    d.children = d._children;

  }
  update(d);
}

Upvotes: 3

Views: 182

Answers (2)

Gerardo Furtado
Gerardo Furtado

Reputation: 102194

The problem is that you are using wrap again and again in the same text. This is what I did:

First, I changed the class of any new text to newText:

  nodeEnter.append("text")
    .attr("x", function(d) {
      return d._children ? -0 : 8;
    })
    .attr("y", 3)
    .attr("dy", "0em")
    .attr("text-anchor", "middle")
    .attr("class", "newText")
    .text(function(d) {
      return d.name;
    })

  wrap(d3.selectAll('.newText'),150);

And then, in the function click, I changed the class of all texts:

    function click(d) {

  if (d.children) {
    d._children = d.children;
    d.children = null;

  } else {
    d.children = d._children;

  }
  d3.selectAll("text").attr("class", "text");
  update(d);
}

Upvotes: 1

Cyril Cherian
Cyril Cherian

Reputation: 32327

The problem is that the text is already devoid of space when you try to a split on the basis of whitespace (for second time on-wards).

So instead of doing

words = text.text().split(/\s+/).reverse(),

do it this way

words = d3.select(this).data()[0].name.split(/\s+/).reverse(),

working example here

Upvotes: 4

Related Questions