How do you transform event coordinates to SVG coordinates despite bogus getBoundingClientRect()?

后端 未结 2 1926
迷失自我
迷失自我 2021-02-10 16:53

I\'m experimenting with dynamically drawing things on an SVG element based on the position of the mouse. Unfortunately, I\'m having difficulty translating the mouse coordinates

相关标签:
2条回答
  • 2021-02-10 17:11

    Don't use getBoundingClientRect(). Instead, transform the point from screen space into global SVG space by using getScreenCTM():

    var pt = demo.createSVGPoint(); // demo is an SVGElement
    demo.addEventListener('mousemove',function(evt) {
      pt.x = evt.clientX;
      pt.y = evt.clientY;
      var svgGlobal = pt.matrixTransform(demo.getScreenCTM().inverse());
      // svgGlobal.x and svgGlobal.y are now in SVG coordinates
    },false);
    

    Fixed Demo: http://jsfiddle.net/7kvkq/3/

    If you need to transform from screen space into the local transform for an element, use getTransformToElement() to transform the point further:

    var elTransform = demo.getTransformToElement(someElement);
    var elLocal     = svgGlobal.matrixTransform(elTransform );
    

    Demo of getTransformToElement(): http://jsfiddle.net/7kvkq/4/

    For better performance, instead of transforming the point twice and creating an intermediary point, combine the matrices into one and use that to transform your coordinates:

    var demo = document.querySelector('svg'),
        pt   = demo.createSVGPoint(),
        g    = demo.querySelector('#myGroup');
    
    // Assumes that the group does not move with respect to the SVG;
    // if so, re-calculate this as appropriate.
    var groupXForm = demo.getTransformToElement(g);
    demo.addEventListener('mousemove',function(evt) {
        pt.x = evt.clientX;
        pt.y = evt.clientY;
        var xform = groupXForm.multiply(demo.getScreenCTM().inverse());
        var localPoint = pt.matrixTransform(xform);
        // localPoint.x/localPoint.y are the equivalent of your mouse position
    },false);
    

    You can see a demo using these techniques on my site:
    http://phrogz.net/svg/drag_under_transformation.xhtml

    0 讨论(0)
  • 2021-02-10 17:20

    The event target may or may not be the SVG container. See the MDN Documentation. If you want to get the container's bounding box, call getBoundingClientRect directly on the container. I've forked your fiddle here:

    http://jsfiddle.net/4RF75/1/

    Also, if can be sure the SVG element won't change size, it's probably a good idea to cache the bounding box, as (especially on WebKit browsers) getBoundingClientRect will trigger a layout, which may be too expensive to do in an event handler.

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