I\'ve run into this problem a lot with D3. A lot of the time I like to overlay HTML objects over my SVG.
My current strategy is creating an empty DIV next to the SV
The problem is with getBoundingClientRect, which doesn't account for scroll position or the element's container position relative to the document. It will only report back that item's exact position relative to the document top and left coordinates.
I've created a d3 method which will report back the position of the element. It works by looping through parent elements until it finds the container SVG, then considers that item's position in the calculations. It returns what you would normally receive from getBoundingClientRect.
Here's the method:
d3.selection.prototype.position = function() {
var el = this.node();
var elPos = el.getBoundingClientRect();
var vpPos = getVpPos(el);
function getVpPos(el) {
if(el.parentElement.tagName === 'svg') {
return el.parentElement.getBoundingClientRect();
}
return getVpPos(el.parentElement);
}
return {
top: elPos.top - vpPos.top,
left: elPos.left - vpPos.left,
width: elPos.width,
bottom: elPos.bottom - vpPos.top,
height: elPos.height,
right: elPos.right - vpPos.left
};
};
And you can use this like so:
d3.select(element).position()
Note that I haven't actually added the code here to consider the scroll position.