[英]adding attributes in selected an SVG inside an <object> tag when mouseenter triggered
[英]OnClick not being triggered when using empty SVG nested inside of other SVG
我有 2 个 svg 元素,一个在另一个内部是空的,当我单击它时,我需要在我的事件目标中获取内部 svg 元素,但我无法使其工作。 我注意到的第一个问题是,当使用 Chrome 时,内部 svg 显示为 0 高度和 0 宽度,这在 Firefox 中不会发生。第二个问题是,在我为内部 svg 创建 onclick 侦听器后,事件永远不会触发器。
我也试过:
我不能做什么:
例子:
<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>
看起来 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.