簡體   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