I'm having an issue positioning css web-font styled, svg text elements one after another using D3. When I first position the text elements on load they'll overlap.
However, when I position the elements moments later using the same function triggered on a delay or through a button they wont overlap.
The issue appears to be with getBBox()
and getBoundingClientRect()
neither of which return the proper width for the element at first.
Any ideas on how to get the correct width at first?
The JS is below, an example is here: http://bl.ocks.org/yanofsky/6618496 and the full code here: https://gist.github.com/yanofsky/6618496
//helper function to grab transform coordinates
function transformCoordOf(elem) {
var separator = elem.attr("transform").indexOf(",") > -1 ? "," : " ";
var trans = elem.attr("transform").split(separator);
return { x: (trans[0] ? parseFloat(trans[0].split("(")[1]) : 0), y: (trans[1] ? parseFloat(trans[1].split(")")[0] ): 0) };
}
//position the elements based on the one before it
function positionElements() {
txts.filter(function(d,i){return i != 0}) //filter out the first element
.attr("transform",function(d,i){
var prev = d3.select(txts[0][i]), //use i b/c the list shifts on filter
prevWidth = parseFloat(prev.node().getBoundingClientRect().width)
prevCoords = transformCoordOf(prev);
var cur = d3.select(this),
curWidth = parseFloat(cur.node().getBoundingClientRect().width)
curCoords = transformCoordOf(cur);
var y = prevCoords.y,
x = prevCoords.x + prevWidth + 10;
return "translate("+x+","+y+")";
})
}
var names = ["apples","oranges","bananas"]
var canvas = d3.select("#content")
.append("svg")
.attr("width","600px")
.attr("height","100px");
var txts = canvas.selectAll("text").data(names)
.enter()
.append("text")
.attr("transform","translate(10,50)")
.text(function(d){return d});
positionElements()
d3.select("button").on("click",function(){positionElements()})