Get mouse position in SVG co-ordinates after zoom

后端 未结 1 1954
长情又很酷
长情又很酷 2021-01-19 15:33

Using D3 v4, SVG, and the zoom behaviour, on mousemove, I want to display the mouse co-ordinates in SVG\'s co-ordinate system.

The mousemove event only appears to pr

相关标签:
1条回答
  • 2021-01-19 16:12

    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());
    

    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>

    Of course you must ensure that d3.mouse and d3.zoom are referencing the same thing, in this case the rectangle.

    0 讨论(0)
提交回复
热议问题