如何在SVG元素中使用Z-index?

2020/10/28 01:23 · javascript ·  · 0评论

我在这样的项目中使用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值,但是不能对我的svg元素使用z-index。我在Google上搜索了很多,但没有找到任何相对的东西。因此,请帮助我在我的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值作为元素的ID。请记住,即使结果看起来不错,也可能不是最佳解决方案。有一点时间,这里规范SVG 1.1的链接“使用”元素

目的:

为了避免要求作者修改引用的文档以向根元素添加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规范是下一个主要版本,仍然支持上述功能。

3.4。渲染顺序

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

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

3.4.1。在SVG中建立堆叠环境

...

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

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

Update

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

就像其他人所说的那样,z-index由元素在DOM中出现的顺序定义。如果无法手动对html进行重新排序或很难,则可以使用D3对SVG组/对象进行重新排序。

使用D3更新DOM顺序和模拟Z索引功能

使用D3更新SVG元素Z-索引

在最基本的级别上(如果您没有将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索引数组是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]将DOM中的第3个圆(按原始HTML顺序)移动/重新排序为DOM中的第1个,第4个为第2个,第1个为第3个, 等等...

您可以使用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

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

使用D3:

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

selection.raise()

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();

使用D3:

如果要以相反的顺序将元素添加到数据,请使用:

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

代替.append

将元素添加到组元素的顶部

另一种解决方案是使用div,该div确实使用zIndex包含SVG元素。例如:https :
//stackoverflow.com/a/28904640/4552494

我们已经有2019年z-index但SVG仍不支持。

您可以在Mozilla网站上看到SVG2支持状态为z-index未实现

您还可以在站点Bug 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顺序的有缺陷的语句构建的。图书馆也不是必需的。一行代码可以执行大多数操作,以操纵在xyz空间中移动2D对象的应用程序的开发中可能需要的对象或对象组的z顺序。

SVG文档片段中绝对存在Z顺序

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

在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(<g>标记),因此可以使用SVGGElement轻松实现Adobe产品和其他图形工具的典型图像层。此JavaScript本质上是“移至下方”命令。

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

如果将绘制为SVGGElement gRobot的子代的机器人的层位于绘制为SVGGElement gDoorway的子代的门口之前,则该机器人现在位于门口后面,因为门口的z阶现在为1加上其z阶。

移至上方”命令几乎一样容易。

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,第二版,2011年8月16日)

    3.3渲染顺序SVG文档片段中的元素具有隐式的绘制顺序,其中SVG文档片段中的第一个元素首先被“绘制”。后续元素被绘制在先前绘制的元素之上。

    3.4如何呈现组诸如“ g”元素(请参见容器元素)之类的分组元素具有产生临时的单独画布的作用,该画布被初始化为透明黑色,并在其上绘制子元素。组完成后,将为该组指定的所有滤镜效果都将应用以创建修改后的临时画布。修改后的临时画布会组合到背景中,并考虑到该组上的任何组级别的遮罩和不透明度设置。

将SVG元素推至最后,使其z索引位于顶部。在SVG中,没有称为z-index的属性。请尝试在下面的javascript中将元素置于顶部。

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

目标:是我们需要将其放在顶部的元素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>

通过transform:TranslateZ移到最前面

<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>
本文地址:http://javascript.askforanswer.com/ruhezaisvgyuansuzhongshiyongz-index.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!