【问题标题】:Get mouse position in SVG co-ordinates after zoom缩放后在 SVG 坐标中获取鼠标位置
【发布时间】:2018-10-18 23:39:22
【问题描述】:

使用 D3 v4、SVG 和缩放行为,在 mousemove 上,我想在 SVG 的坐标系中显示鼠标坐标。

mousemove 事件似乎只提供客户端/屏幕坐标。

如何将这些坐标转换为反映当前缩放/平移/等变换的 SVG 坐标?

我可以看到使用轴/刻度/等的示例,但我没有创建图表,也没有使用轴/等 - 我使用 D3.js 制作交互式图表。

我已经尝试过 crateSVGPoint/getScreenCTM 方法,但是 (a) 并不真正理解它,因此不确定如何将它应用到我的代码中,并且 (b) 当我缩放/平移时它似乎不起作用- 我只是得到客户端/屏幕坐标。 EG:这是我的 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,如果这有所不同的话。

肯定有一种简单的方法来进行转换吗?

【问题讨论】:

    标签: javascript d3.js svg zooming


    【解决方案1】:

    为了将d3.mouse返回的坐标转换为d3.zoom使用的坐标系,除了d3.mouse返回的坐标外,还需要得到缩放变换。我将在这里强调一种方法。

    您可以通过以下方式获取当前缩放变换:

    d3.zoomTransform(selection.node());
    

    其中 selection 是调用缩放的 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 引用相同的东西,在本例中是矩形。

    【讨论】:

      猜你喜欢
      • 2014-07-16
      • 1970-01-01
      • 2020-05-28
      • 2012-05-05
      • 2018-02-01
      • 2012-09-26
      • 2015-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多