I have a D3.js Treemap with some labels inside. The problem is that some of the texts are too long to fit inside the boxes so I have to wrap them. I took the function provided in this answer and the wrapping works fine. However, the text is not vertically centered when the label has more than one line.
So far my solution is to start the first line with a negative value (that corresponds for half line height times the numbers of lines) for the dy
attribute instead of it being 0
. Although it moves the text a little bit towards the top of the box, it is still not vertically centered.
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);
}
}
// this is my custom solution
if (lineNumber > 0) {
const startDy = -((lineNumber - 1) * (lineHeight / 2));
text
.selectAll("tspan")
.attr("dy", (d, i) => startDy + lineHeight * i + "em");
}
});
}
Already saw a similar question but the vertical centering provided in the answer does not fit my use case.