[英]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.