【问题标题】:How to get the click coordinates relative to SVG element holding the onclick listener?如何获取相对于持有 onclick 监听器的 SVG 元素的点击坐标?
【发布时间】:2015-05-29 10:57:38
【问题描述】:

我无法计算相对于触发事件的元素的点击坐标(x 和 y)。我没有在网上找到一个简单的例子。

我在 HTML 页面中有一个简单的svg(左边距为 100 像素)。它包含一个group(翻译为30px 30px),它附加了一个onclick 监听器。在 group 里面,我有一个 rect,宽度和高度为 50px。

单击group 元素的任何部分后,我得到一个事件对象,其坐标相对于HTML 页面(evt.clientXevt.clientY)。

我需要知道用户在 group 元素(持有 onclick 侦听器的元素)中点击的确切位置。

如何将clientXclientY 坐标转换为group 元素坐标。所以说,如果我点击rect 的最左上部分,它应该给我 x=0 和 y=0。

这是我目前拥有的:

<!DOCTYPE html>
<html>
    <head>
        <style>
            body{
                background:black;
            }
            svg{
                fill:white;
                background:white;
                position: absolute;
                top:100px;
                left:100px;
            }
            
        </style>
        <script>
            function clicked(evt){
                alert("x: "+evt.clientX+" y:"+evt.clientY);
            }
        </script>
    </head>
    <body>
        <div>
            <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
                <g transform="translate(30 30)" onclick="clicked(evt)">
                    <rect x="0" y="0" width="50" height="50" fill="red"/>
                </g>
            </svg>      
        </div>
    </body>
</html>

【问题讨论】:

    标签: javascript html svg


    【解决方案1】:

    尝试使用getBoundingClientRect()http://jsfiddle.net/fLo4uatw/

    function clicked(evt){
        var e = evt.target;
        var dim = e.getBoundingClientRect();
        var x = evt.clientX - dim.left;
        var y = evt.clientY - dim.top;
        alert("x: "+x+" y:"+y);
    }  
    

    【讨论】:

    • 请注意,如果您的 viewBox 与默认值 (viewBox="0 0 width height") 不同,此脚本将不起作用。我发布了一个替代答案,它适用于任何 viewBox。
    【解决方案2】:

    Tolokoban 的解决方案有一个限制,即如果您的 viewBox 偏离默认值,即它与viewBox="0 0 width height" 不同,它就不起作用。将 viewBox 考虑在内的更好解决方案是:

    var pt = svg.createSVGPoint();  // Created once for document
    
    function alert_coords(evt) {
        pt.x = evt.clientX;
        pt.y = evt.clientY;
    
        // The cursor point, translated into svg coordinates
        var cursorpt =  pt.matrixTransform(svg.getScreenCTM().inverse());
        console.log("(" + cursorpt.x + ", " + cursorpt.y + ")");
    }
    

    (感谢 Smerk,posted the code

    如果 viewBox 未设置或设置为默认值,此脚本将返回与 Tolokoban 脚本相同的值。但是如果你有一个像&lt;svg width="100px" height="100" viewBox="0 0 200 200"&gt; 这样的SVG,那么只有这个版本会给你正确的结果。

    【讨论】:

    • 亚历山大所说的完全正确!我的解决方案特定于发布的示例,其中您是默认视口。
    • 注意 svg 是对 svg 元素的引用。如果使用 react,可以通过添加 ref={(ref) =&gt; this.svg = ref} 属性来获取引用。
    • 据我所知,所有支持SVG的浏览器都支持它。根据Microsoft的说法,方法SVGSVGElement.createSVGPoint()是从IE9开始支持的,这也是一般开始支持SVG的时候。 Mozilla 提供了对SVGSVGElement 的支持表,并且由于createSVGPoint() 没有作为单独的功能列出,我认为它属于“基本支持”——这意味着它被所有支持 SVG 的浏览器所支持。跨度>
    • 我关于浏览器支持的陈述可能是错误的。 getScreenCTM()SVGGraphicsElement 的一种方法,根据Mozilla 的说法,IE 不支持它,尽管Microsoft 在他们的网站上提到了它。只需使用支持 SVG 的每个浏览器的最早版本进行测试即可确定。
    【解决方案3】:

    经过多次研究后添加注释(但失败了!)。

    对于css翻译的svg,获取点击点的坐标进行绘制。

    在我的例子中,使用鼠标滚轮事件来翻译 X,所以实际渲染取决于屏幕大小和实际翻译值。

    我建议您为您的用例绘制如下所示的小图,这将有助于弄清楚发生了什么。

    假设我的 svg 有 id:shoke 要获得总计算宽度,以像素为单位:

    shoke.getBoundingClientRect()["width"]
    

    需要知道实际的 translateX 值。 (从右边开始,所以是负数,在这种情况下)

    shoke.style.transform.substr(11).slice(0,-3)
    

    注意它返回的是字符串而不是整数,所以:

    +shoke.style.transform.substr(11).slice(0,-3)
    

    现在获取鼠标的坐标,与屏幕的像素 x0 相关

    let pt = document.querySelector('svg').createSVGPoint();
    pt.matrixTransform(shoke.getScreenCTM().inverse())["x"]
    

    所以,最后,要获得精确的 x 点:

    svg_width - (svg_width + translated) + from_pixel x0 of the screen_click
    

    是这样的:

    shoke.getBoundingClientRect()["width"]  - (shoke.getBoundingClientRect()["width"] + +shoke.style.transform.substr(11).slice(0,-3)) + pt.matrixTransform(shoke.getScreenCTM().inverse())["x"]
    

    【讨论】:

      【解决方案4】:

      建议的解决方案很棒,但并非在所有情况下都有效。

      OP的帖子标题

      如何获取相对于 SVG 元素的点击坐标 按住 onclick 监听器

      因此,如果您将 onclick 侦听器放在根 svg 元素上,则无论何时单击其任何子元素,getBoundingClientRect 都会为您提供子元素的 Rect,您将无法获得相对于根svg

      这是我的情况,因为我始终需要相对于根的坐标,而对我有用的解决方案是使用 e.target.farthestViewportElement。这是我的(JSX)代码的摘录:

      const onClickSvg = e => {
        const { farthestViewportElement: svgRoot } = e.target;
        const dim = svgRoot.getBoundingClientRect();
        const x = e.clientX - dim.left;
        const y = e.clientY - dim.top;
        console.log(`x: ${x}, y: ${y}`);
      };
      
      <svg onClick={onClickSvg}>...</svg>
      

      【讨论】:

        猜你喜欢
        • 2014-04-08
        • 2013-10-09
        • 1970-01-01
        • 2012-09-23
        • 2022-01-07
        • 2021-11-21
        • 1970-01-01
        • 2013-07-07
        • 1970-01-01
        相关资源
        最近更新 更多