Reputation: 4988
I am tring to wrap text in d3, I have read about it and I understand that the way to do it in d3 is to separate the long text into substrings which are inserted in tspan
elmenets or by adding the text to the foreignObject
element.
I am trying to adapt this function using the tspan
method
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"),
x = text.attr("x"),
dy = text.attr("dy"),
dx = text.attr("dx"),
tspan = text
.text(null)
.append("tspan")
.attr("x", x)
.attr("y", y)
.attr("dx", dx)
.attr("dy", dy);
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("dx", dx)
.attr("dy", ++lineNumber * lineHeight + Math.abs(dy) + "em")
.text(word);
}
}
});
}
This function works properly but the coordinates defined in dx
anddy
of the text element are lost, so that the text appears in incorrect positions within the graphic.
I have identified that by replacing the .attr("dy", ++lineNumber * lineHeight + Math.abs(dy) +" em ")
line with .attr("dy", dy)
the text is placed in the desired position but the tspan
elements overlap.
Getting this
I am new to the concepts of d3 and I appreciate your comments
Update 1: Distribution of tspan elements once called the function wrap
<g class="category">
<circle r="15" cx="112.58330249197704" cy="64.99999999999997"></circle>
<text x="112.58330249197704" y="64.99999999999997" dx="20" dy="10" text-anchor="start">
<tspan x="112.58330249197704" y="64.99999999999997" dx="20" dy="10"></tspan>
<tspan x="112.58330249197704" y="64.99999999999997" dx="20" dy="11">Third</tspan>
<tspan x="112.58330249197704" y="64.99999999999997" dx="20" dy="11">Bit</tspan>
<tspan x="112.58330249197704" y="64.99999999999997" dx="20" dy="11">Category</tspan>
</text>
</g>
Update 2: Graph state after applying updated function, text distribution detail
Upvotes: 0
Views: 141
Reputation: 1384
I have been using this function for a while now, might work for you as well (maybe with slight adjustments):
function wrap(text, width) {
text.each(function () {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1,
y = text.attr("y"),
x = text.attr("x"),
dy = 0,
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", lineHeight + "em").text(word);
lineHeight++;
}
}
});
}
UPDATE: It looks like I copied the wrong function, I have multiple versions of it across my projects. I believe this one should work properly.
Your function has same issue as the first function that I shared had - we both were not increasing lineHeight
(in your case it is called lineNumber
) in the loop.
Upvotes: 1