如何获取相对于持有onclick侦听器的SVG元素的单击坐标?

oab*_*rca 27 html javascript svg

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

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

单击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>
Run Code Online (Sandbox Code Playgroud)

Ale*_*ank 51

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 + ")");
}
Run Code Online (Sandbox Code Playgroud)

(信用证发给了Smerk,他发布了代码)

如果未将viewBox设置或设置为默认值,则此脚本将返回与Tolokoban脚本相同的值.但是如果你有类似的SVG <svg width="100px" height="100" viewBox="0 0 200 200">,只有这个版本会给你正确的结果.

  • 注意`svg`是对svg元素的引用.如果使用react,你可以通过添加`ref = {(ref)=> this.svg = ref}`prop来获得引用. (5认同)
  • 随着 SVGPoint 的弃用,这个答案可能应该更新为使用 DOMPoint 代替。它的工作原理相同,但可以使用 new DOMPoint(x, y) 来构造。 (5认同)
  • 亚历山大所说的是完全正确的!我的解决方案特定于发布的示例,其中您是默认的viewPort. (3认同)

Tol*_*ban 29

尝试使用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);
}  
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果viewBox与默认视图不同(`viewBox ="0 0 width height"`),则此脚本不起作用.我发布了一个替代答案,适用于任何viewBox. (3认同)

小智 5

所提出的解决方案很棒,但它们并不适用于所有场景。

OP 的帖子标题是

如何获取相对于持有 onclick 监听器的SVG 元素的点击坐标?

因此,如果您将 onclick 侦听器放在根svg元素上,则每当您单击其任何子元素时,getBoundingClientRect都会为您提供子元素Rect,并且您不会获得相对于 root 的单击坐标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>
Run Code Online (Sandbox Code Playgroud)