I would like to get the text to wrap on the following D3 tree so that instead of
Foo is not a long word
each line is wrapped to
You can modify Mike Bostock's "Wrapping Long Labels" example to add elements to your nodes. There are two major changes required to add wrapped text to your nodes. I didn't delve into having the text update its position during transitions, but it shouldn't be too hard to add.
The first is to add a function wrap, based off of the function in the above example. wrap will take care of adding elements to make your text fit within a certain 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
x = text.attr("x"),
y = text.attr("y"),
dy = 0, //parseFloat(text.attr("dy")),
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);
}
}
});
}
The second change is that instead of setting the text of each node, you need to call wrap for each node:
// Add entering nodes in the parent’s old position.
node.enter().append("text")
.attr("class", "node")
.attr("x", function (d) { return d.parent.px; })
.attr("y", function (d) { return d.parent.py; })
.text("Foo is not a long word")
.call(wrap, 30); // wrap the text in <= 30 pixels