簡體   English   中英

如何在svg個元素中使用z-index?

[英]How to use z-index in svg elements?

我在我的項目中使用 svg 圈子,

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 120">
    <g>
        <g id="one">
            <circle fill="green" cx="100" cy="105" r="20" />
        </g>
        <g id="two">
            <circle fill="orange" cx="100" cy="95" r="20" />
        </g>
    </g>
</svg>

我在g標簽中使用 z-index 來首先顯示元素。 在我的項目中,我只需要使用 z-index 值,但我不能將 z-index 用於我的 svg 元素。 我用谷歌搜索了很多,但我沒有找到任何相關的東西。 所以請幫我在我的 svg 中使用 z-index。

這是演示。

規格

在 SVG 規范 1.1 版中,渲染順序基於文檔順序:

first element -> "painted" first

參考SVG 1.1。 規格

3.3 渲染順序

SVG 文檔片段中的元素具有隱式繪制順序,SVG 文檔片段中的第一個元素首先“繪制” 后續元素繪制在先前繪制的元素之上。


解決方案(更清潔更快)

您應該將綠色圓圈作為要繪制的最新對象。 所以交換兩個元素。

 <svg xmlns="http://www.w3.org/2000/svg" viewBox="30 70 160 120"> <!-- First draw the orange circle --> <circle fill="orange" cx="100" cy="95" r="20"/> <!-- Then draw the green circle over the current canvas --> <circle fill="green" cx="100" cy="105" r="20"/> </svg>

這里是你的jsFiddle 的分支

解決方案(替代)

標簽use與屬性xlink:href (只是hrefSVG 2 )和作為值的元素的id。 請記住,即使結果看起來不錯,這也可能不是最佳解決方案。 有一點時間,這里是規范SVG 1.1 “使用” Element 的鏈接

目的:

避免要求作者修改引用的文檔以將 ID 添加到根元素。

 <svg xmlns="http://www.w3.org/2000/svg" viewBox="30 70 160 120"> <!-- First draw the green circle --> <circle id="one" fill="green" cx="100" cy="105" r="20" /> <!-- Then draw the orange circle over the current canvas --> <circle id="two" fill="orange" cx="100" cy="95" r="20" /> <!-- Finally draw again the green circle over the current canvas --> <use xlink:href="#one"/> </svg>


SVG 2 注釋

SVG 2 Specification是下一個主要版本,仍然支持上述功能。

3.4. 渲染順序

SVG 中的元素在三個維度上定位。 除了它們在 SVG 視口的 x 和 y 軸上的位置之外,SVG 元素還位於 z 軸上。 z 軸上的位置定義了它們的繪制順序

沿着 z 軸,元素被分組到堆疊上下文中。

3.4.1. 在 SVG 中建立堆疊上下文

...

堆疊上下文是概念性工具,用於描述渲染文檔時元素必須在另一個之上繪制的順序,......

正如這里的其他人所說,z-index 是由元素在 DOM 中出現的順序定義的。 如果手動重新排序您的 html 不是一種選擇或很困難,您可以使用 D3 重新排序 SVG 組/對象。

使用 D3 更新 DOM 順序和模仿 Z-Index 功能

使用 D3 更新 SVG 元素 Z-Index

在最基本的層面上(如果您不將 ID 用於其他任何用途),您可以使用元素 ID 作為 z-index 的替代品,並使用它們重新排序。 除此之外,您幾乎可以盡情發揮您的想象力。

代碼片段中的示例

 var circles = d3.selectAll('circle') var label = d3.select('svg').append('text') .attr('transform', 'translate(' + [5,100] + ')') var zOrders = { IDs: circles[0].map(function(cv){ return cv.id; }), xPos: circles[0].map(function(cv){ return cv.cx.baseVal.value; }), yPos: circles[0].map(function(cv){ return cv.cy.baseVal.value; }), radii: circles[0].map(function(cv){ return cv.r.baseVal.value; }), customOrder: [3, 4, 1, 2, 5] } var setOrderBy = 'IDs'; var setOrder = d3.descending; label.text(setOrderBy); circles.data(zOrders[setOrderBy]) circles.sort(setOrder);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 100"> <circle id="1" fill="green" cx="50" cy="40" r="20"/> <circle id="2" fill="orange" cx="60" cy="50" r="18"/> <circle id="3" fill="red" cx="40" cy="55" r="10"/> <circle id="4" fill="blue" cx="70" cy="20" r="30"/> <circle id="5" fill="pink" cx="35" cy="20" r="15"/> </svg>

基本思想是:

  1. 使用 D3 選擇 SVG DOM 元素。

     var circles = d3.selectAll('circle')
  2. 創建一些與 SVG 元素(要重新排序)具有 1:1 關系的 z 索引數組。 以下示例中使用的 Z-index 數組是 ID、x 和 y 位置、半徑等......

     var zOrders = { IDs: circles[0].map(function(cv){ return cv.id; }), xPos: circles[0].map(function(cv){ return cv.cx.baseVal.value; }), yPos: circles[0].map(function(cv){ return cv.cy.baseVal.value; }), radii: circles[0].map(function(cv){ return cv.r.baseVal.value; }), customOrder: [3, 4, 1, 2, 5] }
  3. 然后,使用 D3 將您的 z 索引綁定到該選擇。

     circles.data(zOrders[setOrderBy]);
  4. 最后,調用 D3.sort 根據數據對 DOM 中的元素重新排序。

     circles.sort(setOrder);

例子

在此處輸入圖片說明

  • 可以按ID堆疊

在此處輸入圖片說明

  • 最左邊的SVG在頂部

在此處輸入圖片說明

  • 頂部的最小半徑

在此處輸入圖片說明

  • 或指定一個數組以將 z-index 應用於特定排序——在我的示例代碼中,數組[3,4,1,2,5]將第三個圓圈(按原始 HTML 順序)移動/重新排序為第一個DOM,第 4 次為第 2 次,第 1 次為第 3 次,依此類推...

嘗試反轉#one#two 看看這個小提琴: http : //jsfiddle.net/hu2pk/3/

Update

在 SVG 中, z-index 由元素在文檔中出現的順序定義 如果需要,您也可以查看此頁面: https : //stackoverflow.com/a/482147/1932751

您可以使用使用

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 120">
    <g>
        <g id="one">
            <circle fill="green" cx="100" cy="105" r="20" />
        </g>
        <g id="two">
            <circle fill="orange" cx="100" cy="95" r="20" />
        </g>
    </g>
    <use xlink:href="#one" />
</svg>

綠色圓圈出現在頂部。
js小提琴

使用 D3:

如果要按順序重新插入每個選定元素,作為其父元素的最后一個子元素。

selection.raise()

如前所述,svgs 按順序呈現並且不考慮 z-index(目前)。 也許只是將特定元素發送到其父元素的底部,以便它最后呈現。

function bringToTop(targetElement){
  // put the element at the bottom of its parent
  let parent = targetElement.parentNode;
  parent.appendChild(targetElement);
}

// then just pass through the element you wish to bring to the top
bringToTop(document.getElementById("one"));

為我工作。

更新

如果您有一個包含組的嵌套 SVG,則需要將該項目從其 parentNode 中取出。

function bringToTopofSVG(targetElement){
  let parent = targetElement.ownerSVGElement;
  parent.appendChild(targetElement);
}

SVG 的一個很好的特性是每個元素都包含它的位置,而不管它嵌套在哪個組中:+1:

svgs 沒有 z-index。 但是 svg 通過它們在 DOM 中的位置來確定哪些元素是最上面的。 因此,您可以刪除對象並將其放置在 svg 的末尾,使其成為“最后呈現”的元素。 然后在視覺上將那個渲染為“最頂層”。


使用jQuery:

function moveUp(thisObject){
    thisObject.appendTo(thisObject.parents('svg>g'));
}

用法:

moveUp($('#myTopElement'));

使用 D3.js:

d3.selection.prototype.moveUp = function() {
    return this.each(function() {
        this.parentNode.appendChild(this);
    });
};

用法:

myTopElement.moveUp();

使用 D3:

如果要以相反的順序將元素添加到數據中,請使用:

.insert('g', ":first-child")

而不是 .append

將元素添加到組元素的頂部

另一種解決方案是使用 div,它確實使用 zIndex 來包含 SVG 元素。如這里: https : //stackoverflow.com/a/28904640/4552494

截至本答案發布之日,發布的干凈、快速和簡單的解決方案並不令人滿意。 它們是基於 SVG 文檔缺乏 z 順序的有缺陷的陳述而構建的。 圖書館也不是必需的。 一行代碼可以執行大多數操作來操縱對象或對象組的 z 順序,這些操作在開發在 xyz 空間中移動 2D 對象的應用程序中可能需要。

Z 順序絕對存在於 SVG 文檔片段中

所謂的 SVG 文檔片段是從基本節點類型 SVGElement 派生的元素樹。 SVG 文檔片段的根節點是一個 SVGSVGElement,它對應於 HTML5 <svg>標簽。 SVGGElement 對應於<g>標記並允許聚合子項。

在 SVGElement 上擁有一個 z-index 屬性就像在 CSS 中一樣會破壞 SVG 渲染模型。 W3C SVG Recommendation v1.1 2nd Edition 的第 3.3 和 3.4 節聲明 SVG 文檔片段(來自 SVGSVGElement 的后代樹)是使用所謂的樹深度優先搜索來呈現的 該方案在該術語的任何意義上都是 az 順序。

Z 順序實際上是一種計算機視覺捷徑,可避免由於光線追蹤的復雜性和計算需求而需要真正的 3D 渲染。 SVG 文檔片段中元素的隱式 z-index 的線性方程。

z-index = z-index_of_svg_tag + depth_first_tree_index / tree_node_qty

這很重要,因為如果您想將位於正方形下方的圓移動到其上方,只需在圓之前插入正方形即可。 這可以在 JavaScript 中輕松完成。

支持方法

SVGElement 實例有兩種支持簡單易行的 z 順序操作的方法。

  • parent.removeChild(child)
  • parent.insertBefore(child, childRef)

不會造成混亂的正確答案

由於可以像刪除和插入 SVGCircleElement 或任何其他形狀一樣輕松地刪除和插入 SVGGElement( <g>標記),因此可以使用 SVGGElement 輕松實現 Adob​​e 產品和其他圖形工具的典型圖像層。 這個 JavaScript 本質上是一個移動下方命令。

parent.insertBefore(parent.removeChild(gRobot), gDoorway)

如果繪制為 SVGGElement gRobot 的孩子的機器人的層在繪制為 SVGGElement gDoorway 的孩子的門口之前,機器人現在在門口后面,因為門口的 z 階現在是機器人的 z 階加一。

Move Above命令幾乎同樣簡單。

parent.insertBefore(parent.removeChild(gRobot), gDoorway.nextSibling())

想想 a=a 和 b=b 來記住這一點。

insert after = move above
insert before = move below

讓 DOM 處於與視圖一致的狀態

這個答案正確的原因是因為它是最小的和完整的,並且像 Adob​​e 產品或其他設計良好的圖形編輯器的內部一樣,使內部表示處於與通過渲染創建的視圖一致的狀態。

替代但有限的方法

另一種常用的方法是將 CSS z-index 與多個 SVG 文檔片段(SVG 標簽)結合使用,除了底部之外,所有的背景幾乎都是透明的。 同樣,這破壞了 SVG 渲染模型的優雅,使得在 z 順序中向上或向下移動對象變得困難。


注意事項:

  1. https://www.w3.org/TR/SVG/render.html v 1.1,第 2 版,2011 年 8 月 16 日)

    3.3 渲染順序 SVG 文檔片段中的元素具有隱式繪制順序,SVG 文檔片段中的第一個元素首先被“繪制”。 后續元素繪制在先前繪制的元素之上。

    3.4 如何呈現組 諸如“g”元素(請參閱容器元素)之類的分組元素具有生成臨時單獨畫布的效果,該畫布初始化為透明黑色,在其上繪制子元素。 組完成后,為組指定的任何濾鏡效果都將應用於創建修改后的臨時畫布。 修改后的臨時畫布合成到背景中,考慮到組上的任何組級遮罩和不透明度設置。

我們已經到了2019 年,SVG 仍然不支持z-index

您可以在 Mozilla中的SVG2 支持站點上看到z-index的狀態 –未實現

您還可以在站點上看到錯誤 360148“支持 SVG 元素上的 'z-index' 屬性” (報告:12 年前)。

但是您在 SVG 中有 3 種可能性來設置它:

  1. element.appendChild(aChild);
  2. parentNode.insertBefore(newNode, referenceNode);
  3. targetElement.insertAdjacentElement(positionStr, newElement); (在 IE 中不支持 SVG)

交互式演示示例

有了這3個功能。

 var state = 0, index = 100; document.onclick = function(e) { if(e.target.getAttribute('class') == 'clickable') { var parent = e.target.parentNode; if(state == 0) parent.appendChild(e.target); else if(state == 1) parent.insertBefore(e.target, null); //null - adds it on the end else if(state == 2) parent.insertAdjacentElement('beforeend', e.target); else e.target.style.zIndex = index++; } }; if(!document.querySelector('svg').insertAdjacentElement) { var label = document.querySelectorAll('label')[2]; label.setAttribute('disabled','disabled'); label.style.color = '#aaa'; label.style.background = '#eee'; label.style.cursor = 'not-allowed'; label.title = 'This function is not supported in SVG for your browser.'; }
 label{background:#cef;padding:5px;cursor:pointer} .clickable{cursor:pointer}
 With: <label><input type="radio" name="check" onclick="state=0" checked/>appendChild()</label> <label><input type="radio" name="check" onclick="state=1"/>insertBefore()</label><br><br> <label><input type="radio" name="check" onclick="state=2"/>insertAdjacentElement()</label> <label><input type="radio" name="check" onclick="state=3"/>Try it with z-index</label> <br> <svg width="150" height="150" viewBox="0 0 150 150"> <g stroke="none"> <rect id="i1" class="clickable" x="10" y="10" width="50" height="50" fill="#80f"/> <rect id="i2" class="clickable" x="40" y="40" width="50" height="50" fill="#8f0"/> <rect id="i3" class="clickable" x="70" y="70" width="50" height="50" fill="#08f"/> </g> </svg>

將 SVG 元素推到最后,使其 z-index 位於頂部。 在 SVG 中,沒有稱為 z-index 的屬性。 嘗試在 javascript 下面將元素帶到頂部。

var Target = document.getElementById(event.currentTarget.id);
var svg = document.getElementById("SVGEditor");
svg.insertBefore(Target, svg.lastChild.nextSibling);

目標:是我們需要將其置於頂部的元素 svg:是元素的容器

通過變換移到前面:TranslateZ

警告:僅適用於 FireFox

 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 160" style="width:160px; height:160px;"> <g style="transform-style: preserve-3d;"> <g id="one" style="transform-style: preserve-3d;"> <circle fill="green" cx="100" cy="105" r="20" style="transform:TranslateZ(1px);"></circle> </g> <g id="two" style="transform-style: preserve-3d;"> <circle fill="orange" cx="100" cy="95" r="20"></circle> </g> </g> </svg>

它很容易做到:

  1. 克隆你的物品
  2. 克隆項目進行排序
  3. 通過克隆替換項目

 function rebuildElementsOrder( selector, orderAttr, sortFnCallback ) { let $items = $(selector); let $cloned = $items.clone(); $cloned.sort(sortFnCallback != null ? sortFnCallback : function(a,b) { let i0 = a.getAttribute(orderAttr)?parseInt(a.getAttribute(orderAttr)):0, i1 = b.getAttribute(orderAttr)?parseInt(b.getAttribute(orderAttr)):0; return i0 > i1?1:-1; }); $items.each(function(i, e){ e.replaceWith($cloned[i]); }) } $('use[order]').click(function() { rebuildElementsOrder('use[order]', 'order'); /* you can use z-index property for inline css declaration ** getComputedStyle always return "auto" in both Internal and External CSS decl [tested in chrome] rebuildElementsOrder( 'use[order]', null, function(a, b) { let i0 = a.style.zIndex?parseInt(a.style.zIndex):0, i1 = b.style.zIndex?parseInt(b.style.zIndex):0; return i0 > i1?1:-1; }); */ });
 use[order] { cursor: pointer; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="keybContainer" viewBox="0 0 150 150" xml:space="preserve"> <defs> <symbol id="sym-cr" preserveAspectRatio="xMidYMid meet" viewBox="0 0 60 60"> <circle cx="30" cy="30" r="30" /> <text x="30" y="30" text-anchor="middle" font-size="0.45em" fill="white"> <tspan dy="0.2em">Click to reorder</tspan> </text> </symbol> </defs> <use order="1" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sym-cr" x="0" y="0" width="60" height="60" style="fill: #ff9700; z-index: 1;"></use> <use order="4" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sym-cr" x="50" y="20" width="50" height="50" style="fill: #0D47A1; z-index: 4;"></use> <use order="5" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sym-cr" x="15" y="30" width="50" height="40" style="fill: #9E9E9E; z-index: 5;"></use> <use order="3" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sym-cr" x="25" y="30" width="80" height="80" style="fill: #D1E163; z-index: 3;"></use> <use order="2" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sym-cr" x="30" y="0" width="50" height="70" style="fill: #00BCD4; z-index: 2;"></use> <use order="0" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sym-cr" x="5" y="5" width="100" height="100" style="fill: #E91E63; z-index: 0;"></use> </svg>

這是有關 z-index 和 SVG 搜索的最高 Google 結果。 在閱讀了所有答案后,其中一些非常好,我仍然感到困惑。

所以對於像我這樣的新手來說,這是目前的總結,9 年后的 2022 年。

您不能將 z-index 與 SVG 一起使用。

在 SVG 中,z-index 由元素在文檔中出現的順序定義。

如果您希望某些東西出現在頂部或更靠近用戶,請最后繪制它。 來源

SVG 2 可以支持 z-index 但可能永遠不會出現

SVG 2 是實現該功能和其他功能的提議,但它有永遠不會向前發展的風險。

SVG 2 於 2016 年進入候選推薦階段,並於 2018 年進行了修訂,最新草案於 2021 年 6 月 8 日發布。來源

然而,它沒有很多支持,很少有人在研究它。 來源所以不要屏住呼吸等待這個。

您可以使用 D3,但可能不應該

通常用於可視化數據的D3通過綁定 z-index 然后排序來支持 z-index,但它是一個龐大而復雜的庫,如果您只是希望某個 SVG 出現在堆棧頂部,它可能不是最好的選擇。

只是想添加一個技巧,當您想將特定元素放在頂部時可以使用。

function moveInFront(element) {
    const svg = element.closest('svg'); // Find the parent SVG
    svg.appendChild(element); // Append child moves the element to the end
}

這是有效的,因為我引用了文檔,“ appendChild()將 [元素] 從其當前 position 移動到新位置”而不是添加副本。

注意:如果元素是嵌套的,則必須將元素移到組中的前面,並且可能也將組移到前面。

use可以用於此目的,但是那些在use help 之后放置的元素很難操作......我在使用它之后無法弄清楚的是:為什么我不能 hover(鼠標懸停,鼠標輸入操作都不是來自 js會工作)在使用元素上獲得額外的功能 - 比如〜在圓圈上顯示文本〜返回到圓圈重新排序后,因為它是操作那些 svg 對象的唯一方法

一個更好的use示例,我最終使用了它。

<svg>
  <defs>
    <circle id="one" fill="green" cx="40" cy="40" r="20" /> 
    <circle id="two" fill="orange" cx="50" cy="40" r="20"/> 
  </defs>
  <use href="#two" />
  <use href="#one" />
</svg>

要控制順序,您可以更改這些use元素的href屬性值。 這對動畫很有用。

感謝defs ,圓元素只繪制一次。

jsfiddle.net/7msv2w5d

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM