问题描述
使用D3 v4,SVG和缩放行为,在mousemove上,我想在SVG坐标系中显示鼠标坐标.
Using D3 v4, SVG, and the zoom behaviour, on mousemove, I want to display the mouse co-ordinates in SVG's co-ordinate system.
mousemove事件仅显示提供客户端/屏幕坐标.
The mousemove event only appears to provide client/screen co-ordinates.
如何将这些坐标转换为反映当前Zooom/pan/etc转换的SVG坐标?
How do I convert these co-ordinates into SVG co-ordinates that reflect the current zooom/pan/etc transform?
我可以使用axis/scales/etc看到这样的示例,但是我没有创建图形,也没有使用axis/etc-我使用D3.js绘制交互式图表.
I can see examples of this using axis/scales/etc but I'm not creating a graph and am not using axis/etc- I'm using D3.js for an interactive diagram.
我尝试了crateSVGPoint/getScreenCTM方法,但是(a)不太了解它,因此不确定如何将其应用于代码;(b)缩放/平移时似乎不起作用-我只得到客户/屏幕坐标. EG:这是我的mousemove事件中转换为SVG坐标的代码:
I've tried the crateSVGPoint/getScreenCTM approach but (a) don't really understand it and am therefore unsure how to apply it to my code, and (b) it doesn't appear to work when I zoom/pan - I just get the client/screen co-ordinates. EG: here's the code in my mousemove event to convert to SVG co-ords:
var theSvg = document.getElementById('svgItem');
var pt = theSvg.createSVGPoint();
var cursorPoint = function(evt){
pt.x = evt.clientX; pt.y = evt.clientY;
return pt.matrixTransform(theSvg.getScreenCTM().inverse());
}
var loc = cursorPoint(d3.event);
//the pair of co-ordinates should be different on zoom, but aren't
d3.select(".statusBarText").text("move (" + d3.event.x + "," + d3.event.y + ") (" + loc.x + "," + loc.y + ")");
对于其价值,缩放行为将应用于SVG元素的SVG组元素.缩放效果很好;我可以看到平移/缩放应用于该组.
For what it's worth, the zoom behaviour is applied to an SVG group element of the SVG element. Zooming works fine; I can see the translate/scale being applied to the group.
我试图修改上面的内容,以对已转换的group元素调用createSVGPoint(),但会收到有关createSVGPoint()不是函数的错误;我想这只能与DOM中的SVG元素一起使用...
I've tried to modify the above to call createSVGPoint() on the group element which has been transformed but get errors about createSVGPoint() not being a function; I guess this only works with the SVG element from the DOM...
我正在使用的SVG元素上还有一个viewBox设置,如果有区别的话.
There's also a viewBox set on the SVG element I'm using, if that makes a difference.
肯定有一种简单的转换方法吗?
Surely there's got to be an easy way to do the conversion?
推荐答案
要将d3.mouse返回的坐标转换为d3.zoom使用的坐标系,除了坐标外,还需要进行缩放转换由d3.mouse返回.我将在这里重点介绍一种方法.
In order to convert the coordinate returned by d3.mouse to the coordinate system used by d3.zoom, you need to get the zoom transform in addition to the coordinates returned by d3.mouse. I'll highlight one method here.
您可以使用以下方法获取当前的缩放变换:
You can get the current zoom transform with:
d3.zoomTransform(selection.node());
其中选择是d3选择,其中调用了缩放.尽管d3.mouse()为我们提供了鼠标相对于容器的屏幕坐标,但我们可以使用它和转换来给我们提供缩放的和平移坐标,其transform.invert()
为一个点,并返回缩放后的坐标:
Where selection is the d3 selection the zoom is called on. While d3.mouse() gives us the screen coordinates of the mouse relative to the container, we can use that and the transform to give us the scaled and translated coordinates with transform.invert()
, which takes a point and will return the zoomed coordinates:
var xy = d3.mouse(this); // relative to specified container
var transform = d3.zoomTransform(selection.node());
var xy1 = transform.invert(xy); // relative to zoom
这是一个快速示例,显示与鼠标坐标相比,缩放坐标的提取.轴只是为了大致了解缩放坐标系(它们显示缩放坐标),但是如果没有它们,功能将保持不变:
Here's a quick example showing extraction of the zoomed coordinates as compared with the mouse coordinates. The axes are just to give a rough idea of what the zoom coordinate system is (they show zoom coordinates), but the functionality remains the same without them:
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 300)
.attr("fill","#eee");
var g = svg.append("g")
.attr("transform","translate(50,50)");
var rect = g.append("rect")
.attr("width",400)
.attr("height",200)
.attr("fill","#eee");
var x = d3.scaleLinear().domain([0,400]).range([0,400]);
var y = d3.scaleLinear().domain([0,200]).range([0,200]);
var axisX = d3.axisTop().scale(x).tickSize(-200)
var axisY = d3.axisLeft().scale(y).tickSize(-400);
var gX = g.append("g").call(axisX)
var gY = g.append("g").call(axisY)
var zoom = d3.zoom()
.scaleExtent([1, 8])
.on("zoom",zoomed);
rect.call(zoom);
rect.on("click", function() {
var xy = d3.mouse(this);
var transform = d3.zoomTransform(rect.node());
var xy1 = transform.invert(xy);
console.log("Mouse:[", xy[0], xy[1], "] Zoomed:[",xy1[0],xy1[1],"]")
})
function zoomed() {
gX.call(axisX.scale(d3.event.transform.rescaleX(x)));
gY.call(axisY.scale(d3.event.transform.rescaleY(y)));
}
rect {
cursor: pointer;
}
.tick line {
stroke: #ccc;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
当然,您必须确保d3.mouse和d3.zoom引用相同的对象,在本例中为矩形.
Of course you must ensure that d3.mouse and d3.zoom are referencing the same thing, in this case the rectangle.
这篇关于缩放后获取鼠标在SVG坐标中的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!