问题
I want to wrap long text elements to a width. The example here is taken from Bostock's wrap function, but seems to have 2 problems: firstly the result of wrap has not inherited the element's x value (texts are shifted left); secondly it's wrapping on the same line, and lineHeight
argument has no effect.
Grateful for suggestions. http://jsfiddle.net/geotheory/bk87ja3g/
var svg = d3.select("body").append("svg")
.attr("width", 300)
.attr("height", 300)
.style("background-color", '#ddd');
dat = ["Ukip has peaked, but no one wants to admit it - Nigel Farage now resembles every other politician",
"Ashley Judd isn't alone: most women who talk about sport on Twitter face abuse",
"I'm on list to be a Mars One astronaut - but I won't see the red planet"];
svg.selectAll("text").data(dat).enter().append("text")
.attr('x', 25)
.attr('y', function(d, i){ return 30 + i * 90; })
.text(function(d){ return d; })
.call(wrap, 250);
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 1,
lineHeight = 1.2, // 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", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
回答1:
Bostock's original function assumes that the text
element has an initial dy
set. It also drops any x
attribute on the text
. Finally, you changed the wrap
function to start at lineNumber = 1
, that needs to be 0
.
Refactoring a bit:
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0, //<-- 0!
lineHeight = 1.2, // ems
x = text.attr("x"), //<-- include the x!
y = text.attr("y"),
dy = text.attr("dy") ? text.attr("dy") : 0; //<-- null check
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);
}
}
});
}
Updated fiddle.
回答2:
The problem is this line:
dy = parseFloat(text.attr("dy"))
In the example you've linked to, dy
is set on the text
elements, but not in your case. So you're getting NaN
there which in turn causes the dy
for the tspan
to be NaN
. Fix by assigning 0 to dy
if NaN
:
dy = parseFloat(text.attr("dy")) || 0
Complete demo here.
来源:https://stackoverflow.com/questions/29144678/wrapping-long-text-in-d3-js