Marty
Marty

Reputation: 312

How to wrap or break long text in a fixed width on D3.js chart library - Javascript

I've used this Example for creating the organization chart. >> d3.js v3 (old version)

Need help with the "position" content, this is the code line for the position content:

nodeGroup.append("text")
      .attr("x", dynamic.nodeTextLeftMargin)
      .attr("y", dynamic.nodePositionNameTopMargin)
      .attr('class', 'emp-position-name')
      .attr("dy", ".35em")
      .attr("text-anchor", "left")
      .text(function(d) {
         var position =  d.positionName.substring(0,27);
      if(position.length<d.positionName.length){
        position = position.substring(0,24)+'...'
      }
        return position;
      });

<text x="75.14285714285714" y="32.5" class="emp-position-name" dy=".35em" text-anchor="left">Business Development Manager</text>

I don't want to display text like Business Development Man...

So, either I want to add a tooltip on hover (Business Development Man...) or make it happens to wrap or break long text/word in a fixed width.

I tried to modify the below CSS but no helps.

.node-group .emp-position-name {
  fill: black;
  font-size: 11px;
  word-wrap: break-word;
}

Would appreciate some guidance on how I can resolve this.

Upvotes: 0

Views: 578

Answers (2)

Raffael Meier
Raffael Meier

Reputation: 309

This is an optimized version, which

  • centers the text vertically (lines are added below, but text ist shifted upwards, so text block ends up centered)
  • solves the problem, that line heights are increasing from line to line (math not correct in the example above: dy has to be equal for all additional nodes and not rising)

Codes looks like this now:

function wrap(text, width) {
                                text.each(function() {
                                    var text = d3.select(this),
                                        words = text.text().split(/\s+/).reverse(),
                                        word,
                                        line = [],
                                        lineNumber = 0,
                                        lineHeight = 0.9, // ems
                                        y = text.attr("y"),
                                        dy = parseFloat(text.attr("dy")),
                                        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) // this part plays big role
                                    {
                                        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);
                                        tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", lineHeight + dy + "em").text(word);
                                        ++lineNumber;
                                    }
                                    }
                                    text.attr("y", -(((lineNumber-1)/2)*lineHeight) + "em");
                                });
                                }

Call for example like this:

node.append("text")
      .attr("dy", "0em")
      .attr("class", "shadow")
      .style("text-anchor", "middle")
      .style("font-size", "16px")
      .text(function(d) { return d.className; })
      .call(wrap, 200 );

or last line according to example:

.call(wrap, x.rangeBand()); // from example

Upvotes: 0

Marty
Marty

Reputation: 312

I have looked into it, found its common question and resolved using Wrapping Long Labels example.

nodeGroup.append("text")
      .attr("x", dynamic.nodeTextLeftMargin)
      .attr("y", dynamic.nodePositionNameTopMargin)
      .attr('class', 'emp-position-name')
      .attr("dy", ".35em")
      .attr("text-anchor", "left")
      .text(function(d) {
         var position =  d.positionName
         return position;
      })
      .call(wrap, x.rangeBand()); // from example
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")),
        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) // this part plays big role
      {
        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);
      }
    }
  });
}

Thanks!

Upvotes: 1

Related Questions