如何获取相对于持有 onclick 监听器的 SVG 元素的点击坐标?
Posted
技术标签:
【中文标题】如何获取相对于持有 onclick 监听器的 SVG 元素的点击坐标?【英文标题】:How to get the click coordinates relative to SVG element holding the onclick listener? 【发布时间】:2015-05-29 10:57:38 【问题描述】:我无法计算相对于触发事件的元素的点击坐标(x 和 y)。我没有在网上找到一个简单的例子。
我在 html 页面中有一个简单的svg
(左边距为 100 像素)。它包含一个group
(翻译为30px 30px),它附加了一个onclick
监听器。在 group
里面,我有一个 rect
,宽度和高度为 50px。
单击group
元素的任何部分后,我得到一个事件对象,其坐标相对于HTML 页面(evt.clientX
和evt.clientY
)。
我需要知道用户在 group
元素(持有 onclick 侦听器的元素)中点击的确切位置。
如何将clientX
和clientY
坐标转换为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" >
<g transform="translate(30 30)" onclick="clicked(evt)">
<rect x="0" y="0" fill="red"/>
</g>
</svg>
</div>
</body>
</html>
【问题讨论】:
【参考方案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 脚本相同的值。但是如果你有一个像<svg width="100px" height="100" viewBox="0 0 200 200">
这样的SVG,那么只有这个版本会给你正确的结果。
【讨论】:
亚历山大所说的完全正确!我的解决方案特定于发布的示例,其中您是默认视口。 注意svg
是对 svg 元素的引用。如果使用 react,可以通过添加 ref=(ref) => 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>
【讨论】:
以上是关于如何获取相对于持有 onclick 监听器的 SVG 元素的点击坐标?的主要内容,如果未能解决你的问题,请参考以下文章
onClick() 事件适用于一个 div,但不适用于另一个。为啥?
使用 Onclick 侦听器将选定的 ChipGroup 芯片文本放入剪贴板