I have a d3 chart with a title. The title is the chart. However, on small screens the text needs to be wrap as not to over flow.
However the Bl.ocks text wrap method is not creating new lines and instead creating a new tspan for every word and then placing each text/tspan on top of one another
Here is a jsfiddle of the issue: jsfiddle here
Here is the relevant code
var chartTitle = svg.append("text")
.attr("y", -15 )
.attr("text-anchor", "start")
.text("This is a very long chart title that should be wrapped!")
.attr('class','chartTitle')
.call(wrap, width/2);
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", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
CSS
.chartTitle{
font-size:20px;
}
That wrap
function, originally written by Mike Bostock (D3 creator) for wrapping labels, uses the text dy
attribute (which is automatically created by the axis generator). That being said, the problem with your code is that there is no dy
attribute in that text element.
You can simply tweak the function or just set a zero dy
attribute. Here is a demo using the latter:
var svg = d3.select("body")
.append("svg");
var chartTitle = svg.append("text")
.attr("y", 20)
.attr("dy", 0)//set the dy attribute
.attr("text-anchor", "start")
.text("This is a very long chart title that should be wrapped!")
.attr('class', 'chartTitle')
.call(wrap, 300 / 2);
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", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>