在缩放后获取SVG坐标中的鼠标位置

4
使用 D3 v4、SVG 和缩放行为,在鼠标移动时,我想在 SVG 坐标系统中显示鼠标坐标。但是,mousemove 事件似乎只提供客户端/屏幕坐标。如何将这些坐标转换为反映当前缩放/平移等变换的 SVG 坐标?我可以看到使用轴/比例尺等的示例,但我没有创建图表,也没有使用轴/等-我正在使用 D3.js 进行交互式图解。我尝试了 crateSVGPoint/getScreenCTM 方法,但 (a) 我不太理解它,因此不确定如何将其应用到我的代码中,而且 (b) 当我缩放/平移时它似乎不起作用-我只得到客户端/屏幕坐标。例如:下面是我的 mousemove 事件中用于转换为 SVG 坐标的代码。
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组元素。缩放工作正常;我可以看到平移/缩放应用于组上。
我尝试修改上述内容,对已经被转换的组元素调用createSVGPoint(),但会出现有关createSVGPoint()不是函数的错误;我猜这仅适用于来自DOM的SVG元素...
我正在使用的SVG元素还设置了viewBox,如果有区别的话。
肯定有一种简单的方法来进行转换,对吧?
1个回答

6
为了将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>

当然,您必须确保d3.mouse和d3.zoom引用的是同一个物体,在本例中是矩形。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接