繁体   English   中英

OnClick 在使用嵌套在其他 SVG 中的空 SVG 时不会被触发

[英]OnClick not being triggered when using empty SVG nested inside of other SVG

我有 2 个 svg 元素,一个在另一个内部是空的,当我单击它时,我需要在我的事件目标中获取内部 svg 元素,但我无法使其工作。 我注意到的第一个问题是,当使用 Chrome 时,内部 svg 显示为 0 高度和 0 宽度,这在 Firefox 中不会发生。第二个问题是,在我为内部 svg 创建 onclick 侦听器后,事件永远不会触发器。

我也试过:

  • 在我的外部 svg 中设置一个 onclick 侦听器并获取事件目标。 它总是返回外部 svg 而从不返回内部 svg。只有当我有一个 rect,circle,path,(...) inside 时才有效。
  • 将指针事件设置为我内部 svg 中的所有事件,而外部事件中则没有。 不触发点击事件。

我不能做什么:

  • 获取我外部 svg 的第一个 ElementChild,我将有更多嵌套的 svg,我需要确切地知道我点击了哪个。

例子:

<div>
    <svg id="0" x="0" y="0" height="100%" width="100%" viewBox="0 0 1000 1000">
        <svg id="1" x="0" y="0" height="1000" width="1000" viewBox="0 0 1000 1000"></svg>
    </svg>
</div>

这里的 jsfiddle 示例

看起来 SVG 不支持点击监听器。 但是您是否尝试在每个 SVG 周围放置另一个 div 并将点击侦听器添加到该 div?

<div>
  <div id="svg1">
    <svg id="0" x="0" y="0" height="100%" width="100%" viewBox="0 0 1000 1000">
        <svg id="1" x="0" y="0" height="100%" width="100%" viewBox="0 0 1000 1000"></svg>
    </svg>
  </div>
</div>
document.getElementById("svg1").addEventListener("click", yourFunc)

我也有同样的问题。
以下是我的调查结果。
当我们单击嵌套 svg 内的任何 svg 元素时,将触发嵌套 svg 上的单击事件。 我用了两个圆圈来测试它。
如果我们单击 svg 的边界矩形的空白区域,则不会触发该事件。
Chrome 和 Firefox 中的行为相同。
我最终在最外面的 svg 上设置了事件处理程序。 为了获得相对于内部 svg 的鼠标坐标,我使用来自 d3.js 的实用程序 function,指针(事件:任意,目标?:任意)。

@Michael Mullany 建议根本不要嵌套 svgs。 我不同意这一点。 我有复杂的图形编辑器,有几个绘图区域和两种类型的 svg 嵌套 - 有 viewBox 和没有它。 所以,到目前为止它工作正常。 绝对比拥有像隐形矩形这样的技巧更好。

我唯一遇到的另一个小问题是 Chrome 调试器中 svg 的边界矩形被可视化,左上角不在其给定的 position 处。 坐标原点是正确的。 因此,该问题仅影响调试。

严格来说,没有在空白空间上触发事件的问题取决于对 svg 区域的定义。 我们可以将区域定义为所有内容元素的联合。 然后,我们观察到的行为是绝对正确的。

我遇到了同样的问题,@alehro 的描述是完全正确的。

问题原来是浏览器不认为内部svg中的空白是它的一部分。 内部svg的空部分被视为外部svg的一部分。 所以解决方法很简单:加一个透明的矩形覆盖整个内部的svg就可以了。 做这样的事情:

innersvg
    .append("rect")
    .attr("x", 0)
    .attr("y", 0)
    .attr("width", innerSvgWidth)
    .attr("height", innerSvgHeight)
    .attr("fill-opacity", 0)
    .attr("fill", "white");

注意:不要将fill设置为none ,因为未填充的矩形只有 4 行但没有内部部分。

这实际上是预期的行为:

外部/父 svg 是一个 HTML DOM 节点 - 因此它将应用 css styles 像宽度,高度或背景颜色。

内部/嵌套的 svg 是 SVG DOM 的一部分。

一个空的嵌套<svg> (以及 aa <g> )元素将有一个 0 x 0 像素的边界框。

尽管 firefox 在检查嵌套的 svg 时显示了宽度和高度值——它也返回 0x0px 使用

let bb = nestedSvg.getBBox();
console.log(bb)

通过 javaScript helper 添加透明矩形

附加透明背景矩形根本不是 hack。

设置一个fill="transparent" - 这样,您就可以为点击/指针事件获得一个实心/填充区域。 (否则就像敲一扇打开的窗户)。

您可以像这样轻松地应用辅助方法:

 let svgOuter = document.getElementById("svg0"); // add transparent rectangles let nestedSvgs = svgOuter.querySelectorAll("svg, g"); nestedSvgs.forEach((nestedSvg) => { let rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); rect.setAttribute("x", "0"); rect.setAttribute("y", "0"); rect.setAttribute("width", "100%"); rect.setAttribute("height", "100%"); rect.setAttribute("fill", "transparent"); nestedSvg.insertBefore(rect, nestedSvg.children[0]); // add click event nestedSvg.addEventListener("click", (e) => { let id = e.currentTarget.id; console.log("current id:", id); }); });
 *{ box-sizing:border-box } svg{ border:1px solid #ccc; }.svgInner{ background:red; stroke:red; stroke-width:1px; }
 <svg class="svgOuter" id="svg0" x="0" y="0" height="100%" width="100%" viewBox="0 0 1000 1000"> <svg class="svgInner" id="svg1" x="0" y="0" height="100%" width="33.333%" viewBox="0 0 333 1000"> </svg> <svg class="svgInner" id="svg2" x="33.333%" y="0" height="100%" width="33.333%" viewBox="0 0 333 1000"> </svg> <g transform="translate(666.67 0)" id="testGroup"></g> </svg>

最好使用e.currentTarget ,因为e.target将返回<rect>元素。

替代元素交叉检查: Document.elementFromPoint()Document.elementsFromPoint()

您仍然需要填充背景区域,但您也可以获得document.elementsFromPoint()多个重叠元素- 在某些情况下可能会很方便。

 let svgOuter = document.getElementById("svg0"); /** * alternative: Document.elementFromPoint() * https://developer.mozilla.org/en-US/docs/Web/API/Document/elementFromPoint */ svgOuter.addEventListener("click", (e) => { let el = document.elementFromPoint(e.clientX, e.clientY); let els = document.elementsFromPoint(e.clientX, e.clientY); let ids = els.map(el=>{return el.id? el.id: el.nodeName}); let parentSVG = el.closest("svg"); console.log('current element', parentSVG.id); console.log('all elements', ids); }); // add transparent rectangles let nestedSvgs = svgOuter.querySelectorAll("svg, g"); nestedSvgs.forEach((nestedSvg, i) => { let rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); rect.id= 'rect'+i; rect.setAttribute("x", "0"); rect.setAttribute("y", "0"); rect.setAttribute("width", "100%"); rect.setAttribute("height", "100%"); rect.setAttribute("fill", "transparent"); nestedSvg.insertBefore(rect, nestedSvg.children[0]); // add click event nestedSvg.addEventListener("click", (e) => { let id = e.currentTarget.id; console.log("current id:", id); }); });
 *{ box-sizing:border-box } svg{ border:1px solid #ccc; }.svgOuter{ background:#ccc; }.svgInner{ background:red; stroke:red; stroke-width:1px; }
 <svg class="svgOuter" id="svg0" x="0" y="0" height="100%" width="100%" viewBox="0 0 1000 1000"> <svg class="svgInner" id="svg1" x="0" y="0" height="100%" width="33.333%" viewBox="0 0 333 1000"> </svg> <svg class="svgInner" id="svg2" x="33.333%" y="0" height="100%" width="33.333%" viewBox="0 0 333 1000"> </svg> <g transform="translate(666.67 0)" id="testGroup"></g> </svg>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM