即使在3个像素的距离处检测单击SVG线
以下是我检测 SVG 行点击的方法:
window.onmousedown = (e) => {
if (e.target.tagName == 'line') {
alert(); // do something with e.target
}
}
svg line:hover { cursor: pointer; }
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" id="svg">
<line x1="320" y1="160" x2="140" y2="00" stroke="black" stroke-width="2"></line>
<line x1="140" y1="00" x2="180" y2="360" stroke="black" stroke-width="2"></line>
<line x1="180" y1="360" x2="400" y2="260" stroke="black" stroke-width="2"></line>
<line x1="00" y1="140" x2="280" y2="60" stroke="black" stroke-width="2"></line>
</svg>
只有当鼠标光标精确地在线上时它才起作用,这并不容易,因此这是一个糟糕的用户体验。
如何从 Javascript 检测 SVG 线上的点击,即使不是完全在线上,但距离 <= 3 像素?
Here is how I detect clicks on SVG lines:
window.onmousedown = (e) => {
if (e.target.tagName == 'line') {
alert(); // do something with e.target
}
}
svg line:hover { cursor: pointer; }
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" id="svg">
<line x1="320" y1="160" x2="140" y2="00" stroke="black" stroke-width="2"></line>
<line x1="140" y1="00" x2="180" y2="360" stroke="black" stroke-width="2"></line>
<line x1="180" y1="360" x2="400" y2="260" stroke="black" stroke-width="2"></line>
<line x1="00" y1="140" x2="280" y2="60" stroke="black" stroke-width="2"></line>
</svg>
It only works if the mouse cursor is precisely on the line, which is not easy, so it's a bad UX.
How to detect a click on a SVG line from Javascript, even if not perfectly on the line, but at a distance of <= 3 pixels?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
有点棘手的解决方案,但要完成工作:
A bit tricky solution, but does the job:
我们可以使用现有的Web API
document.ElementFrompoint(x,y)
。它在给定点返回最高元素。单击用户单击点,我们可以沿每个轴行驶,并使用该方法找到第一个
&lt; line&gt;
元素。当我们获得线路或达到最大搜索距离时,我们会停止搜索。在以下演示中,没有创建额外的元素。变量
接近
控制着从行的最大距离以考虑选择。奖励功能:突出显示到鼠标指针的最接近线。因此,用户可以轻松单击所需的线,而无需任何麻烦。
这只是一个演示代码,您可以摆脱不需要的东西。如果您不想在接近中显示何时显示
onmousemove
并将逻辑移至onclick
method。Only
过滤器:Drop-shadow(...)
可以突出显示非平方形形状。否则,您可以更改线宽度或颜色等。We can use existing Web API
document.elementFromPoint(x, y)
. It returns topmost element at given point.Form user click point we can travel along each axis and find first
<line>
element using the method. We stop the search when we get a line or we reach maximum search distance.In following demo no extra elements have been created. The variable
proximity
controls the max distance from a line to consider it for selection.Bonus feature: the nearest line to the mouse pointer is highlighted. So user can easily click on desired line without any hassle.
This is just a demo code you can get rid of unwanted stuff. If you don't want hand to show when in proximity then delete
onmousemove
and move the logic toonclick
method.Only
filter: drop-shadow(...)
can highlight non-square shapes. Otherwise, you can change line width or color etc.只是做数学...
这可能是过分的,但是这三个像素的确切性使我感到困扰,所以这是“关于数学的全部”解决方案。
getLineNrange(Point,Mindist,SVG)
将返回Mindist
的所有行。当前,它正在使用mousemove
将类应用于所有线路。单击显示所有线路的数组范围内的数组,该数组首先具有最接近的线。一个警告,这将在SVG的“执行任何内部缩放或偏移定位”的地方无法使用。更新:现在不在乎任何SVG突变,例如缩放和偏移。
更新2 已经提出了速度问题,因此我决定证明其实际计算的速度。计算机擅长的一件事是处理数字。唯一真正的放缓是,当它将掉落阴影应用于150多行时,这是渲染而不是数学的限制,而不是微小的修改,您只能将效果应用于最接近的行。现在,您可以添加多达1000行进行测试。
Just do the maths...
This is probably overkill, but the exactness of those 3 pixels bothered me so here's an "all about the math's" solution.
getLinesInRange(point, minDist,svg)
will return ALL lines in range of theminDist
. It is currently applying a class to all lines in range withmousemove
. Click shows an array of all lines in range sorted by distance having the closest line first.One caveat, this will not work in svg's where any internal scaling or offset positioning is being performed.UPDATE: Now doesn't care about any SVG mutations like scaling and offset.
UPDATE 2 The question of speed has been brought up so I've decided to demonstrate how quickly it actual does calculations. One thing computers are good at is crunching numbers. The only real slowdown is when it's applying a drop-shadow to 150+ lines, however, this is a limitation of the render and not the maths, with a small modification you can just apply the effect to the closest line only. Now you can add up to 1000 lines to test.
使用多个元素
通常 ,您可以使用SVG组(
'g'
元素),并包括两个元素,其中一个较大,一个不透明度为0或pranse>透明
的填充< /代码>。
使用具有相同坐标的两个元素自动执行此操作
有点冗余。实际上,您可能想从动态数据(尤其是在执行数据驱动图形的情况下)构造元素,或者可以通过编程方式迭代所有现有行,然后用组元素替换它们。
我将展示第二个,因为这似乎是问题:
Using multiple elements
In general, you can use an svg group (
'g'
element), and include two elements, with one bigger and an opacity of 0 or a stroke/fill oftransparent
.Automatically doing this
Using two elements with the same coordinates is a bit redundant. In practice, probably you'd want to construct elements based from dynamic data (particularly if you're doing data-driven graphics), or you can programmatically iterate through all of the existing lines and then replace them with group elements.
I'll show the second, since that's what the question seems to be asking:
将其包装在本机 Web 组件 (JSWC) 中
所有浏览器都支持。因此,您可以在任何您想要的地方重复使用它,
wrapping it in a Native Web Component (JSWC)
<svg-lines>
Supported in all Browsers. So you can reuse it anywhere you want
制作该行的两个副本,将它们分组在一起,并在CSS中增加第二行的描边宽度,还设置描边:透明以隐藏第二行,现在您将获得更宽的可点击区域。我希望您发现这是最好的方法。
Make two copies of the line, group them together, and increase the stroke width of the second line in CSS also set stroke: transparent to hide second line, now you will get clickable area wider. I hope you find this is the best method.