Wrapping Text in D3

How to wrap text in SVG vertically in D3.js?

From this bl.ocks.org you can use the wrap function with little modification:

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) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", lineHeight + "em").text(word);
}
}
});
}

here is a working snippet:

let graph = {

"nodes": [{

"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porta consequat felis, eget varius mi volutpat sit amet. Nullam lobortis vehicula felis, in tempor dui. Sed scelerisque purus ac nisl auctor finibus sit amet nec massa. Duis erat sem, suscipit non molestie vitae, accumsan nec tortor. Nulla sed facilisis ligula, nec interdum elit. Nam tortor lectus, sodales ut nulla ac, feugiat ultrices velit. Vestibulum nec ultricies nisi. Donec leo nibh, fringilla eget pretium nec, condimentum in nulla."

}]

}

let svg = d3.select("body")

.append("svg")

.attr("width", 700)

.attr("height", 800);

let nodes = svg.selectAll("circle")

.data(graph.nodes)

.enter()

.append("circle")

.attr("r", 20)

.attr("cx", function(d) {

return 20;

})

.attr("cy", function(d) {

return 20;

})

.style("fill", "red");

let tip;

nodes.on("click", function(d) {

if (tip) {

tip.remove()

};

tip = svg.append("g")

.attr("id", "tip")

.attr("transform", "translate(" + (d3.event.pageX - 10) + "," + (d3.event.pageY - 35) + ")");

let rect = tip.append("rect")

.style("fill", "white")

.style("stroke", "steelblue");

tip.append("text")

.text(d.description)

.attr("dy", "1em")

.attr("x", 5)

.call(wrap, 300)

let bbox = tip.node().getBBox();

rect.attr("width", bbox.width + 5)

.attr("height", bbox.height + 50)

});

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) {

line.pop();

tspan.text(line.join(" "));

line = [word];

tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", lineHeight + "em").text(word);

}

}

});

}
<p>

click the node to show description

</p>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.12.2/d3.js"></script>

Text-Wrapping in D3

You need to use svg:foreignObject with an HTML div or similar to make this work. SVG itself won't wrap the text.

Wrapping and vertically centering text using D3.js

I realized I was using the number of lines - 1 instead of just the number of lines. Removing the -1 solved the issue.

if (lineNumber > 0) {
const startDy = -(lineNumber * (lineHeight / 2)); // here was the issue
text
.selectAll("tspan")
.attr("dy", (d, i) => startDy + lineHeight * i + "em");
}


Related Topics



Leave a reply



Submit