Reputation: 6635
I am trying to add a line break to the y-axis labels on my D3 graph, which displays bandwidth moved. At the moment it displays inline 5 GB
, I would like it to display like so,
5
GB
So, since there is no easy way of adding a line break to a svg text element, I opted for selecting all of the text elements after they have been rendered, I split them at the space and positioned them in <tspan>
elements inside of the text element, with the GB
positioned slightly lower than the value, which seemed to work, except for the labels not displaying at all, even though they did exist on the page.
Here is a snippet of the code,
function init(svg,data,width,height,margin){
var x = d3.scale.linear()
.domain([0,data[0].length-1])
.range([margin.left, width-margin.right]),
y = d3.scale.linear()
.domain([0,d3.max(data[0])])
.range([height-margin.bottom, margin.top]),
/* Define stock x and y axis */
xAxis = d3.svg
.axis()
.ticks(data[0].length)
.tickFormat(function(d) { return d+1; })
.scale(x)
.orient('bottom'),
yAxis = d3.svg
.axis()
.scale(y)
.tickFormat(function(d) { return bytesToSize(d,0); })
.orient('right'),
/* line path generator */
line = d3.svg.line().interpolate('monotone')
.x(function(d,i) { return x(i); })
.y(function(d) { return y(d); }),
/* area path generator */
area = d3.svg.area().interpolate('monotone')
.x(line.x())
.y1(line.y())
.y0(y(0)),
/* add the groups */
groups = svg.selectAll("g")
.data(data)
.enter()
.append("g");
/* add the circles */
svg.select("g")
.selectAll("circle")
.data(data[0])
.enter()
.append("circle")
.attr("class","dot")
.attr("cx", line.x())
.attr("cy", line.y())
.attr("r", 3.5)
.style("fill","#008cc2")
.style("stroke","#008cc2")
.style("stroke-width","1.5px");
/* add the axes */
svg.append('g')
.attr("class", "x axis")
.attr("transform", "translate(0,"+(height - 20)+")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.3em")
.attr("dy", "-.3em")
.attr("transform", function(d) {
return "rotate(-90)"
});
svg.append('g')
.attr("class", "y axis")
.call(yAxis);
/* add the areas */
area = groups.append("path")
.attr("class", "area")
.attr("d",area)
.style("opacity",0.3)
.style("fill", function(d,i) {
return (i == 0 ? "#008cc2" : "#7500c6" );
});
/* add the lines */
groups.append("path")
.attr("class", "line")
.attr("d", line)
.style("fill","none")
.style("stroke-width", "1.5px")
.style("stroke", function(d,i) {
return (i == 0 ? "#008cc2" : "#7500c6" );
});
var insertLinebreaks = function (d) {
var el = $(d3.select(this).node());
var sections = bytesToSize(d,0);
console.log(sections[0]);
console.log(sections[1]);
el.text('');
el.append('<tspan>'+sections[0]+'</tspan>');
el.append('<tspan x="0" dy="3">'+sections[1]+'</tspan>');
};
svg.selectAll('g.y.axis g text').each(insertLinebreaks);
}
function bytesToSize(bytes, precision)
{
var kilobyte = 1024;
var megabyte = kilobyte * 1024;
var gigabyte = megabyte * 1024;
var terabyte = gigabyte * 1024;
if ((bytes >= 0) && (bytes < kilobyte)) {
return [bytes,'B'];
}
else if ((bytes >= kilobyte) && (bytes < megabyte))
{
return [(bytes / kilobyte).toFixed(precision),'KB'];
}
else if ((bytes >= megabyte) && (bytes < gigabyte))
{
return [(bytes / megabyte).toFixed(precision),'MB'];
}
else if ((bytes >= gigabyte) && (bytes < terabyte))
{
return [(bytes / gigabyte).toFixed(precision),'GB'];
}
else if (bytes >= terabyte)
{
return [(bytes / terabyte).toFixed(precision),'TB'];
}
else
{
return [bytes,'B'];
}
}
Basically I would like to add a line break to a svg text element. I've tried a few methods, but to no avail.
Upvotes: 4
Views: 2700
Reputation: 109232
The problem is that you're adding the tspan
elements as text without a namespace. This way they get interpreted as HTML. If you add them using D3 or explicitly create the elements with a namespace, it should work, i.e.
el.text('');
d3.select(el).append("tspan").text(sections[0]);
...
Upvotes: 4