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

时间:2013-07-22 11:38:29

标签: javascript jquery svg z-index

我正在我的项目中使用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元素。我google了很多,但我找不到任何相对的东西。 所以请帮我在我的svg中使用z-index。

以下是DEMO.

14 个答案:

答案 0 :(得分:136)

规范

在SVG规范1.1版中,渲染顺序基于文档顺序:

first element -> "painted" first

参考SVG 1.1. Specification

  

3.3 Rendering Order

     

SVG文档片段中的元素具有隐式绘制顺序,SVG文档片段中的第一个元素得到&#34;绘制&#34;第一即可。后续元素绘制在先前绘制的元素之上。


解决方案(更干净 - 更快)

您应该将绿色圆圈作为要绘制的最新对象。所以交换这两个元素。

&#13;
&#13;
<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>
&#13;
&#13;
&#13;

这是您jsFiddle的分支。

解决方案(替代方案)

标记use,其属性为xlink:href,值为元素的ID。请记住,即使结果看起来不错,也可能不是最佳解决方案。有一点时间,这里是规范SVG 1.1 "use" Element的链接。

  

目的:

     

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

&#13;
&#13;
<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>
&#13;
&#13;
&#13;


关于SVG 2的注释

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

  

3.4. Rendering order

     

SVG中的元素以三维方式定位。除了它们在SVG视口的x和y轴上的位置之外,SVG元素也位于z轴上。 z轴上的位置定义了它们的绘制顺序

     

沿z轴,元素被分组到堆叠上下文中。

     

3.4.1. Establishing a stacking context in SVG

     

...

     

堆叠上下文是概念性工具,用于描述在呈现文档时元素必须一个在另一个上面的顺序,...

答案 1 :(得分:28)

尝试反转#one#two。看看这个小提琴:http://jsfiddle.net/hu2pk/3/

<强> Update

在SVG中, z-index由元素在文档中出现的顺序定义。如果需要,您也可以查看此页面:https://stackoverflow.com/a/482147/1932751

答案 2 :(得分:21)

正如其他人所说,z-index是由元素在DOM中出现的顺序定义的。如果手动重新排序您的html不是一个选项或者很难,您可以使用D3来重新排序SVG组/对象。

使用D3更新DOM订单并模仿Z-Index功能

here

在最基本的级别(如果您没有使用其他ID),您可以使用元素ID作为z-index的替代,并重新排序。除此之外,你几乎可以让你的想象力疯狂。

代码段中的示例

<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>
var circles = d3.selectAll('circle')

基本理念是:

  1. 使用D3选择SVG DOM元素。

    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]
    }
    
  2. 创建一些与您的SVG元素(要重新排序)的1:1关系的z-indices数组。以下示例中使用的Z索引数组是ID,x和amp; y位置,半径等......

    circles.data(zOrders[setOrderBy]);
    
  3. 然后,使用D3将z-indices绑定到该选择。

    circles.sort(setOrder);
    
  4. 最后,调用D3.sort根据数据重新排序DOM中的元素。

    [3,4,1,2,5]
  5. 实施例

    Updating SVG Element Z-Index With D3

    • 您可以按ID
    • 进行堆叠

    enter image description here

    • 最左边的SVG位于顶部

    enter image description here

    • 顶部最小的半径

    enter image description here

    • 或指定一个数组以应用特定排序的z-index - 在我的示例代码中,数组System.out.println("The book named " + Object.bookName); 移动/重新排序第3个圆圈(在原始HTML顺序中)为DOM中的第1个,第4个是第2名,第1名是第3名,依此类推......

答案 3 :(得分:19)

您可以使用use

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

绿色圆圈出现在顶部 jsFiddle

答案 4 :(得分:9)

svgs没有z-index。但是svg确定哪些元素在DOM中的最重要位置。因此,您可以删除Object并将其放在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();

答案 5 :(得分:8)

如上所述,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:

答案 6 :(得分:7)

使用D3:

如果您想以相反的顺序将元素添加到数据使用:

>>> re.search(r'\d+\.\d+', 'hello Rs. 150.00').group()
'150.00'

>>> re.search(r'\d+\.\d+', 'hello Rs. 150.00 and some more text').group()
'150.00'

而不是.append

Adding an element to top of a group element

答案 7 :(得分:6)

使用D3:

如果要按顺序重新插入每个选定元素,作为其父级的最后一个子元素。

selection.raise()

答案 8 :(得分:5)

另一个解决方案是使用div,它使用zIndex来包含SVG元素。如下所示: https://stackoverflow.com/a/28904640/4552494

答案 9 :(得分:3)

截至本答复日期发布的清晰,快速,简便的解决方案并不令人满意。它们构建在SVG文档缺乏z顺序的错误陈述之上。图书馆也不是必需的。一行代码可以执行大多数操作来操作在x-y-z空间中移动2D对象的应用程序开发中可能需要的对象或对象组的z顺序。

在SVG文档碎片中肯定存在Z顺序

所谓的SVG文档片段是从基本节点类型SVGElement派生的元素树。 SVG文档片段的根节点是SVGSVGElement,它对应于HTML5 &lt; svg&gt; 标记。 SVGGElement对应&lt; g&gt; 标记,并允许聚合子代。

在CSS中使用SVGElement上的z-index属性会破坏SVG渲染模型。 W3C SVG Recommendation v1.1 2nd Edition的第3.3和3.4节规定SVG文档片段(来自SVGSVGElement的后代树)使用所谓的深度优先搜索树进行渲染。该方案在每个意义上都是一个z阶。

Z顺序实际上是一种计算机视觉快捷方式,可以避免对光线跟踪的复杂性和计算需求进行真正的3D渲染。 SVG文档片段中元素的隐式z索引的线性方程。

z-index = z-index_of_svg_tag + depth_first_tree_index / tree_node_qty

这很重要,因为如果您想将一个方形下方的圆圈移动到它上方,只需在圆形之前插入方形。这可以在JavaScript中轻松完成。

支持方法

SVGElement实例有两种方法支持简单和简单的z顺序操作。

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

没有造成混乱的正确答案

因为可以像SVGCircleElement或任何其他形状一样轻松地删除和插入SVGGElement(&lt; g&gt; 标记),所以可以使用Adobe产品和其他图形工具的典型图像层实现轻松使用SVGGElement。这个JavaScript本质上是一个 Move Below 命令。

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处于与视图一致的状态

这个答案是正确的原因是因为它是最小和完整的,并且像Adobe产品的内部或其他精心设计的图形编辑器一样,使内部表示处于与渲染创建的视图一致的状态。

替代但有限的方法

另一种常用的方法是将CSS z-index与多个SVG文档片段(SVG标记)结合使用,除了底层之外的所有部分都具有大多数透明背景。同样,这会破坏SVG渲染模型的优雅,使得难以按z顺序向上或向下移动对象。

备注:

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

    3.3渲染顺序SVG文档片段中的元素具有隐式绘制顺序,SVG文档中包含第一个元素   片段首先被“画”。后续元素被绘制   以前绘制元素的顶部。

         

    3.4如何渲染组分组元素(如'g'元素(请参阅容器元素))具有生成临时的效果   单独的画布初始化为透明黑色到哪个孩子   元素被绘。完成组后,任何过滤器   为组创建的效果将应用于创建修改后的效果   临时画布。修改后的临时画布合成到   背景,考虑任何组级别的掩蔽和不透明度   小组上的设置。

答案 10 :(得分:3)

我们已经 2019 ,并且SVG仍不支持z-index

您可以在站点 SVG2 support in Mozilla 上看到z-index的状态– 未实现

您还可以在 Bug 360148 "Support the 'z-index' property on SVG elements" 网站上看到(报告:12年前)。

但是您可以在SVG中设置3种可能性:

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

交互式演示示例

具有这三个功能。

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>

答案 11 :(得分:2)

将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:是元素的容器

答案 12 :(得分:0)

容易做到:

  1. 克隆您的项目
  2. 排序克隆的项目
  3. 替换项目通过克隆

- (float)getFloatPartOfString:(NSString *)numstr {
    NSScanner *scanner = [NSScanner scannerWithString:numstr];
    int numerator = 0;
    int denominator = 0;

    float number = 0;
    if ([scanner scanInt:&numerator]) && [scanner scanString:@"/" intoString:nil] && [scanner scanInt:&denominator] {
        number = (float)numerator / (float)denominator;
    } else {
        NSLog(@"Didn't find integer / integer");
    }

    NSLog(@"%@ turns into %f", numstr, number);

    return number;
}
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;
}

答案 13 :(得分:0)

通过transform: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>