我试图在d3.behavior.zoom()转换布局后获取节点的屏幕位置,但我没有太多运气。在翻译和缩放布局后,我如何才能在窗口中获取节点的实际位置?
mouseOver = function(node) {
screenX = magic(node.x); // Need a magic function to transform node
screenY = magic(node.y); // positions into screen coordinates.
};
任何指导都将不胜感激。
编辑:上面的'node'是一个强制布局节点,因此它的x和y属性由模拟设置,并在模拟停止后保持不变,无论应用何种类型的变换。
编辑:我用来转换SVG的策略来自d3的缩放行为,这里列出了SVG Geometric Zooming。
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom))
.append("g");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height);
svg.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("r", 2.5)
.attr("transform", function(d) { return "translate(" + d + ")"; });
function zoom() {
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
这很简单。 d3的缩放行为将处理器和缩放事件传递给处理程序,处理程序通过transform属性将转换应用于容器元素。
编辑:我正在通过使用鼠标坐标而不是节点坐标来解决这个问题,因为当节点悬停在鼠标指针上时,我对节点位置感兴趣。这不完全是我追求的行为,但它在很大程度上起作用,并且总比没有好。编辑:解决方案是使用element.getCTM()获取svg元素的当前变换矩阵,然后使用它将x和y坐标偏移到屏幕相对状态。见下文。
答案 0 :(得分:22)
看来原始问题的解决方案看起来像这样:
(已更新以支持旋转变换。)
// The magic function.
function getScreenCoords(x, y, ctm) {
var xn = ctm.e + x*ctm.a + y*ctm.c;
var yn = ctm.f + x*ctm.b + y*ctm.d;
return { x: xn, y: yn };
}
var circle = document.getElementById('svgCircle'),
cx = +circle.getAttribute('cx'),
cy = +circle.getAttribute('cy'),
ctm = circle.getCTM(),
coords = getScreenCoords(cx, cy, ctm);
console.log(coords.x, coords.y); // shows coords relative to my svg container
或者,也可以使用d3.event中的translate和scale属性来完成此操作(如果不需要旋转变换):
// This function is called by d3's zoom event.
function zoom() {
// The magic function - converts node positions into positions on screen.
function getScreenCoords(x, y, translate, scale) {
var xn = translate[0] + x*scale;
var yn = translate[1] + y*scale;
return { x: xn, y: yn };
}
// Get element coordinates and transform them to screen coordinates.
var circle = document.getElementById('svgCircle');
cx = +circle.getAttribute('cx'),
cy = +circle.getAttribute('cy'),
coords = getScreenCoords(cx, cy, d3.event.translate, d3.event.scale);
console.log(coords.x, coords.y); // shows coords relative to my svg container
// ...
}
编辑:我发现函数的以下形式是最有用和通用的,并且似乎在getBoundingClientRect
落下的地方站起来。更具体地说,当我试图在D3强制布局项目中获得准确的SVG节点位置时,getBoundingClientRect
会产生不准确的结果,而下面的方法会在多个浏览器中返回circle
元素的精确中心坐标。
(已更新以支持旋转变换。)
// Pass in the element and its pre-transform coords
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};
};
// Get post-transform coords from the element.
var circle = document.getElementById('svgCircle'),
x = +circle.getAttribute('cx'),
y = +circle.getAttribute('cy'),
coords = getElementCoords(circle, {x:x, y:y});
// Get post-transform coords using a 'node' object.
// Any object with x,y properties will do.
var node = ..., // some D3 node or object with x,y properties.
circle = document.getElementById('svgCircle'),
coords = getElementCoords(circle, node);
该函数的工作原理是获取DOM元素的变换矩阵,然后使用矩阵旋转,缩放和平移信息返回给定节点对象的变换后坐标。
答案 1 :(得分:7)
在应用任何node.getBBox()
后,您可以尝试transform
获取节点形状周围紧密边界框的像素位置。有关详情,请参阅此处:link。
编辑:
getBBox
不像我想象的那样有效。由于矩形是根据变换的坐标空间定义的,因此它总是相对于父<g>
,因此对于包含的形状将始终相同。
另一个名为element.getBoundingClientRect的函数似乎得到了广泛支持,并且它在相对于浏览器视图端口左上角的像素位置返回其矩形。这可能会让你更接近你想要的,而不需要直接混淆变换矩阵。