I'm using this implementation of a D3 tree layout:
http://bl.ocks.org/robschmuecker/7880033
I've got my tree responding to outside events, and for that, I'd like to know if a certain node is currently invisible (outside of svg container), so that I could for example recenter it.
After some research I found this SO answer which looked exactly what I needed:
Getting Screen Positions of D3 Nodes After Transform
When dragging a node in the upper left corner and clicking on it, I would expect the coordinates to be [0,0]. But for some reason the x coordinate is always wrong by a pretty large offset. Made a fiddle about it here:
https://jsfiddle.net/syberyan/yd8L4v0q/
I modified the click() function so that it prints the coordinates of the target node.
function getElementCoords(element, coords) {
var ctm = element.getCTM(),
x = ctm.e + coords.x*ctm.a + coords.y*ctm.c,
y = ctm.f + coords.x*ctm.b + coords.y*ctm.d;
return {x: x, y: y};
};
function click(d) {
if (d3.event.defaultPrevented) return; // click suppressed
d3.selectAll('.node').each(function (node, i) {
if (d === node) {
let coords = getElementCoords(this, node);
console.log(coords.x, coords.y); // shows coords relative to my svg container
}
});
}
I'm a D3 newbie so I probably did something wrong, but what? Or maybe there's a better way of doing this?
I didn't look too closely at the linked question or your current calculations. Instead, I think the calculations can be simplified to:
function getElementCoords(element) {
// translate on node
var trans = d3.transform(d3.select(element).attr('transform')).translate,
// transform on parent "zoom" container
transFormParent = d3.transform(d3.select(element.parentNode).attr('transform')),
// translate on zoom container
transParent = transFormParent.translate,
// scale on zoom container
scaleParent = transFormParent.scale,
// final position of node
pos = {
x: trans[0] + transParent[0]/scaleParent[0],
y: trans[1] + transParent[1]/scaleParent[1]
};
return pos;
}
Call it as:
function click(d) {
console.log(getElementCoords(this));
}
Updated fiddle.
EDITS
@Christian pointed out in the comments, my math was off, should have been:
function getElementCoords(element) {
// translate on node
var trans = d3.transform(d3.select(element).attr('transform')).translate,
// transform on parent "zoom" container
transFormParent = d3.transform(d3.select(element.parentNode).attr('transform')),
// translate on zoom container
transParent = transFormParent.translate,
// scale on zoom container
scaleParent = transFormParent.scale,
// final position of node
pos = {
x: trans[0] * scaleParent[0] + transParent[0],
y: trans[1] * scaleParent[1] + transParent[1]
};
return pos;
}