I read plenty of other implementations on how to do this, but didn't care for any of them so here is my take on a drop-in solution for svg text wrapping.
// set up your "text box" element however you want (without any text yet):
var textX = 150;
var textEl = techtree.treeSVG.append('text')
.attr('x',textX)
.attr('y',200)
.attr('font-size',14)
.attr('fill', 'rgb(100,100,100)');
// additional things we need like the paragraph text and the desired width of the box:
var myText = "This is a long string of text that definitely won't fit into one line but I'm not sure how to break it up into tspans because the width could be variable and what if I later want to change the font or font-size or even this string OMG WHAT AM I GOING TO DO?";
var textW = 200;
// add the auto-generated tspan lines:
addTextLines(textEl, myText, txtW, textX);
Copypasta this where ever you want it so you can use addTextLines.
addTextLines = function(element, txt, width, txt_x){
// adds lines of given "width" with text from "txt" to "element"
var words = txt.split(' ');
var lstr = words[0]; // line string
// add the first line with the 1st word
var line = text.append('tspan')
.attr('dx', 0)
.attr('dy', txt_H)
.text(lstr);
for (var i = 1; i < words.length; i++) { // for the rest of the words
lstr+=' '+words[i];
line.text(lstr);
if (line.node().getComputedTextLength() < txtW){
continue;
} else { // over line size limit
// remove offending word from last line
var lstr = lstr.substring(0, lstr.lastIndexOf(" "));
line.text(lstr);
// start new line with word
lstr = words[i];
line = text.append('tspan')
.attr('x',txt_x)
.attr('dy', txt_H)
.text(lstr);
}
}
};
Now that I'm looking at it, this function has a few more vars that need to be fixed. Right now I'm working on something else, but please comment to show interest and I'll fix it posthaste.