如何根据点击位置查找嵌套和转换的 SVG 元素(例如圆/路径/...)
How to find nested and transformed SVG element (e.g. circle / path / ...) based on click position
我是网络开发和 svg 相关主题的初学者。
我认为这对 svg 专家来说应该很容易,但我现在为此苦苦挣扎了一段时间。我在这个主题上找到的所有资源似乎都无法实现我相当简单的目标。
我的应用程序应该 运行 在 Chrome 浏览器中。
DOM 结构如下:
<div>
<svg>
<g>
<circle></circle>
</g>
<svg>
</div>
虽然里面可能有更多的 svg 标签或嵌套的 svg 元素,但这是一般设置。
目标:
我想点击某处并找到我点击位置的svg子元素(例如圆圈)。我想到的基本功能是:
document.elementFromPoint(x, y)
问题:
1) 所有元素都可以应用变换,例如平移、缩放和旋转,这使事情变得复杂。
2) 我只希望能够单击元素,这些元素是 svg 节点的子节点。
我的一些尝试:
https://jsfiddle.net/a6uLn9cn/3/
我试图将 "pointer-events:none" 放在 DIV 和/或 SVG 节点上。这样,我就可以避免这些是 "clickable"。不过这里有两个问题:我需要 SVG 节点上的指针事件,因为它需要缩放和平移,还有点击事件,例如"bubbles" 到 DIV 不知何故。
确保 svg 节点只有子节点 "clickable" 的另一种方法是检查 element.ownerSVGDocument 以查找找到的元素。如果它为空或未定义,我知道找到的元素不是 svg 子元素。
为了解决实际单击已转换元素(通过其本身或通过其父元素)的问题,我尝试使用 element.getBoundingClientRect() ,它为我提供了元素的周围矩形。有了这个,我做了一个函数来确定点击是否在矩形周围的元素内部:
e是点击事件,elem是document.elementFromPoint()
收到的找到的元素
function clickIsInside(e, elem){
var clickX = e.clientX;
var clickY = e.clientY;
var boxLeft = elem.getBoundingClientRect().left;
var boxRight = elem.getBoundingClientRect().right;
var boxTop = elem.getBoundingClientRect().top;
var boxBottom = elem.getBoundingClientRect().bottom;
if(clickX >= boxLeft && clickX <= boxRight && clickY >= boxTop && clickY <= boxBottom){
return true;
} else {
return false;
}
}
但是在我的 jsfiddle 中,您将无法 "click" 例如在其 boundingClientRect 最右侧的路径,如果您想象 boundingClientRect 在哪里,这对我来说毫无意义。
此外,如果我在添加圆圈后将路径添加到 DOM,我将无法再单击圆圈,只能单击路径。我完全理解为什么,但是如果我需要同时单击两个怎么办?
我不确定我是否能够在这里解决我的问题,但我将非常感谢你们可能给我的任何意见。非常感谢。
我发现我在问题中所做的大部分事情只是让事情复杂化。解决方案只是检查找到的元素是否有任何 ownerSVGDElement,如果没有,则不发送点击事件。对元素应用变换似乎没有任何问题,因为 document.elementFromPoint() 足够强大以找到变换后的元素。这个问题现在看来毫无用处,所以我回答并关闭了它只是为了任何人都会遇到或尝试过像我这样无脑的事情的罕见情况。
编辑:看来我只能在 2 天内接受这个作为答案。
我是网络开发和 svg 相关主题的初学者。
我认为这对 svg 专家来说应该很容易,但我现在为此苦苦挣扎了一段时间。我在这个主题上找到的所有资源似乎都无法实现我相当简单的目标。
我的应用程序应该 运行 在 Chrome 浏览器中。
DOM 结构如下:
<div>
<svg>
<g>
<circle></circle>
</g>
<svg>
</div>
虽然里面可能有更多的 svg 标签或嵌套的 svg 元素,但这是一般设置。
目标:
我想点击某处并找到我点击位置的svg子元素(例如圆圈)。我想到的基本功能是:
document.elementFromPoint(x, y)
问题:
1) 所有元素都可以应用变换,例如平移、缩放和旋转,这使事情变得复杂。
2) 我只希望能够单击元素,这些元素是 svg 节点的子节点。
我的一些尝试:
https://jsfiddle.net/a6uLn9cn/3/
我试图将 "pointer-events:none" 放在 DIV 和/或 SVG 节点上。这样,我就可以避免这些是 "clickable"。不过这里有两个问题:我需要 SVG 节点上的指针事件,因为它需要缩放和平移,还有点击事件,例如"bubbles" 到 DIV 不知何故。
确保 svg 节点只有子节点 "clickable" 的另一种方法是检查 element.ownerSVGDocument 以查找找到的元素。如果它为空或未定义,我知道找到的元素不是 svg 子元素。
为了解决实际单击已转换元素(通过其本身或通过其父元素)的问题,我尝试使用 element.getBoundingClientRect() ,它为我提供了元素的周围矩形。有了这个,我做了一个函数来确定点击是否在矩形周围的元素内部:
e是点击事件,elem是document.elementFromPoint()
收到的找到的元素function clickIsInside(e, elem){
var clickX = e.clientX;
var clickY = e.clientY;
var boxLeft = elem.getBoundingClientRect().left;
var boxRight = elem.getBoundingClientRect().right;
var boxTop = elem.getBoundingClientRect().top;
var boxBottom = elem.getBoundingClientRect().bottom;
if(clickX >= boxLeft && clickX <= boxRight && clickY >= boxTop && clickY <= boxBottom){
return true;
} else {
return false;
}
}
但是在我的 jsfiddle 中,您将无法 "click" 例如在其 boundingClientRect 最右侧的路径,如果您想象 boundingClientRect 在哪里,这对我来说毫无意义。
此外,如果我在添加圆圈后将路径添加到 DOM,我将无法再单击圆圈,只能单击路径。我完全理解为什么,但是如果我需要同时单击两个怎么办?
我不确定我是否能够在这里解决我的问题,但我将非常感谢你们可能给我的任何意见。非常感谢。
我发现我在问题中所做的大部分事情只是让事情复杂化。解决方案只是检查找到的元素是否有任何 ownerSVGDElement,如果没有,则不发送点击事件。对元素应用变换似乎没有任何问题,因为 document.elementFromPoint() 足够强大以找到变换后的元素。这个问题现在看来毫无用处,所以我回答并关闭了它只是为了任何人都会遇到或尝试过像我这样无脑的事情的罕见情况。
编辑:看来我只能在 2 天内接受这个作为答案。