使用D3 v4,SVG和缩放行为,在mousemove上,我想在SVG的坐标系统中显示鼠标坐标。
只有mousemove事件才会显示客户端/屏幕坐标。
如何将这些坐标转换为反映当前zooom / pan / etc变换的SVG坐标?
我可以使用axis / scales / etc看到这个例子,但我没有创建图表而且没有使用axis / etc-我正在使用D3.js作为交互图。
我尝试过crateSVGPoint / getScreenCTM方法,但是(a)并不真正理解它,因此我不确定如何将它应用于我的代码,并且(b)当我缩放/平移时它似乎不起作用 - 我只是得到客户/屏幕坐标。 EG:这是我的mousemove事件中转换为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组元素。缩放工作正常;我可以看到翻译/比例应用于小组。
我试图修改上面的内容,在已经转换的group元素上调用createSVGPoint()但是得到的createSVGPoint()错误不是函数;我想这只适用于DOM的SVG元素...
我正在使用的SVG元素上还有一个viewBox设置,如果这有所不同。
肯定有一种简单的方法可以进行转换吗?
答案 0 :(得分:2)
为了将d3.mouse返回的坐标转换为d3.zoom使用的坐标系,除了d3.mouse返回的坐标外,还需要获得缩放变换。我会在这里强调一种方法。
您可以使用以下方式获取当前缩放变换:
d3.zoomTransform(selection.node());
如果选择d3选项,则调用缩放。虽然d3.mouse()为我们提供了鼠标相对于容器的屏幕坐标,但我们可以使用它和变换为我们提供带transform.invert()
的缩放和平移坐标,这需要一个点并将返回缩放坐标:
var xy = d3.mouse(this); // relative to specified container
var transform = d3.zoomTransform(selection.node());
var xy1 = transform.invert(xy); // relative to zoom
这是一个快速示例,显示了与鼠标坐标相比的缩放坐标的提取。这些轴只是为了大致了解缩放坐标系统(它们显示缩放坐标),但没有它们的功能保持不变:
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>
&#13;
当然你必须确保d3.mouse和d3.zoom引用相同的东西,在这种情况下是矩形。