SVG重排序z-index(Raphael可选)

68

我如何在 Raphael 或其底层的 SVG 元素创建后重新排序它们?更好的做法是,SVG 中是否存在类似图层的东西?

理想情况下,我希望有两个或更多的图层,可以随时将元素放置在其中;一个背景图层和一个前景图层。如果那不是一个选项,将元素移到前面会很好,将其推到后面在这种特殊情况下会更好。

谢谢!


3
翻译:哎呀,拉斐尔甚至有toFront和toBack方法。我太糊涂了,竟然没注意到。还要感谢你下面的回答,也许我最终会使用它们。 - Miles
6个回答

95

给我代码!

// move element "on top of" all others within the same grouping
el.parentNode.appendChild(el); 

// move element "underneath" all others within the same grouping
el.parentNode.insertBefore(el,el.parentNode.firstChild);

// move element "on top of" all others in the entire document
el.ownerSVGElement.appendChild(el); 

// move element "underneath" all others in the entire document
el.ownerSVGElement.appendChild(el,el.ownerSVGElement.firstChild); 

在 Raphael 中,使用 toBack()toFront() 更加容易:

raphElement.toBack()  // Move this element below/behind all others
raphElement.toFront() // Move this element above/in front of all others

详情

SVG在绘制对象时使用"绘画模型":文档中后出现的项目会在先出现的元素之后(在顶部)绘制。要更改项目的分层,必须使用appendChildinsertBefore等方法重新排序DOM中的元素。

您可以在此处查看示例:http://phrogz.net/SVG/drag_under_transformation.xhtml

  1. 拖动红色和蓝色对象使它们重叠。
  2. 单击每个对象并观察其弹出到顶部。(黄色圆圈始终可见。)

此示例中元素的重新排序由源代码的第93/94行完成:

el.addEventListener('mousedown',function(e){
  el.parentNode.appendChild(el); // move to top
  ...
},false);

当鼠标按下一个元素时,它会被移动到所有同级元素的最后一个位置,导致它在所有其他元素之上绘制,成为最上层的元素。


40

如果您正在使用Raphael,那么弹出元素并将其置于前景和背景很简单:

element.toBack()
element.toFront()

这里是相关文档


4

SVG 中没有 z-index 属性,后面出现的对象会显示在前面出现的对象之上。因此,您可以将节点移动到树的开头或结尾来满足您的需求。

<g> (分组)元素是 SVG 中的通用容器,因此它们可以成为图层。只需在组之间移动节点即可实现所需效果。


2
但是如果我想将分层作为一个独立的概念与分组区分开来怎么办?例如,我有两个身体部位的形状,一个用于主体,另一个用于手臂。这两个部分都由两个单独的形状组成:一个用于描边轮廓,另一个用于填充。它们需要以以下方式分层:{手臂填充} {身体填充} {手臂描边} {身体描边},以使它们无缝地融合在一起,而不会重叠它们的轮廓(轮廓需要平滑地勾勒出它们)。但是我需要将手臂填充与手臂描边以及身体填充与身体描边分组,以便更容易地对它们进行变换 :/ 如何将分组与查看分离? - SasQ

0
如果您预定义图形对象,那么您可以随着时间的推移以不同的顺序将它们分层。
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1000 1000" width="400" height="400">
  <rect x="0" y="0" width="1000" height="1000" fill="black"/>
  <defs>
    <rect id="a1" x="0"   y="0"   width="500" height="500" fill="red"/>
    <rect id="a2" x="100" y="100" width="500" height="500" fill="blue"/>
  </defs>
  <g> 
    <use xlink:href="#a1"/>
    <use xlink:href="#a2"/>
    <set attributeName="visibility"  to="hidden" begin="2s"/> 
  </g>
  <g visibility="hidden"> 
    <use xlink:href="#a2"/>
    <use xlink:href="#a1"/>
    <set attributeName="visibility"  to="visible" begin="2s"/> 
  </g>
</svg>

0

我还没有尝试过,但SVG渲染顺序看起来可能是一个解决方案。而且'z-index'也即将到来,它已经在提案中了。


-2
其实,我认为appendChild()单独使用会复制元素而不仅仅是移动它。这可能不是问题,但如果你想避免重复,我建议像这样做:
el.parentNode.appendChild(el.parentNode.removeChild(el));

2
appendChild 方法移动节点,而不是复制节点。请参见 https://developer.mozilla.org/zh-CN/docs/Web/API/Node/appendChild。 - Paul Gobée
1
这个答案是错误的,应该被删除。因为appendChild会移动节点。 - Michelle
1
为什么你(或其他人)不给这个回答投反对票呢?! - Balder
我点了个踩,但实际上对于那些可能认为append会复制元素然后再读取评论的人来说,这是一个有用的答案。 - chaimp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接