jQuery 如何在 svg 元素中使用 z-index?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17786618/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use z-index in svg elements?
提问by Karthi Keyan
I'm using the svg circles in my project like this,
我在我的项目中像这样使用 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>
And I'm using the z-index in the g
tag to show the elements the first. In my project I need to use only z-index value, but I can't use the z-index to my svg elements. I have googled a lot but I didn't find anything relatively.
So please help me to use z-index in my svg.
我在g
标签中使用 z-index来首先显示元素。在我的项目中,我只需要使用 z-index 值,但我不能将 z-index 用于我的 svg 元素。我用谷歌搜索了很多,但我没有找到任何相对的东西。所以请帮助我在我的 svg 中使用 z-index。
Here is the DEMO.
这是演示。
回答by Maicolpt
Specification
规格
In the SVG specification version 1.1 the rendering order is based on the document order:
在 SVG 规范 1.1 版中,渲染顺序基于文档顺序:
first element -> "painted" first
Reference to the SVG 1.1. Specification
Elements in an SVG document fragment have an implicit drawing order, with the first elementsin the SVG document fragment getting "painted" first. Subsequent elements are painted on top of previously painted elements.
SVG 文档片段中的元素具有隐式绘制顺序,SVG 文档片段中的第一个元素首先“绘制”。后续元素绘制在先前绘制的元素之上。
Solution (cleaner-faster)
解决方案(更清洁更快)
You should put the green circle as the latest object to be drawn. So swap the two elements.
您应该将绿色圆圈作为要绘制的最新对象。所以交换两个元素。
<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>
Here the fork of your jsFiddle.
这里是你的jsFiddle 的分支。
Solution (alternative)
解决方案(替代)
The tag use
with the attribute xlink:href
and as value the id of the element. Keep in mind that might not be the best solution even if the result seems fine. Having a bit of time, here the link of the specification SVG 1.1 "use" Element.
use
带有属性的标签,xlink:href
值是元素的 id。请记住,即使结果看起来不错,这也可能不是最佳解决方案。有一点时间,这里是规范SVG 1.1 “使用” Element 的链接。
Purpose:
To avoid requiring authors to modify the referenced document to add an ID to the root 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>
Notes on SVG 2
SVG 2 注释
SVG 2 Specificationis the next major release and still supports the above features.
SVG 2 Specification是下一个主要版本,仍然支持上述功能。
Elements in SVG are positioned in three dimensions. In addition to their position on the x and y axis of the SVG viewport, SVG elements are also positioned on the z axis. The position on the z-axis defines the order that they are painted.
Along the z axis, elements are grouped into stacking contexts.
3.4.1. Establishing a stacking context in SVG
...
Stacking contexts are conceptual tools used to describe the order in which elements must be painted one on top of the otherwhen the document is rendered, ...
SVG 中的元素在三个维度上定位。除了它们在 SVG 视口的 x 和 y 轴上的位置之外,SVG 元素还位于 z 轴上。z 轴上的位置定义了它们的绘制顺序。
沿着 z 轴,元素被分组到堆叠上下文中。
...
堆叠上下文是概念性工具,用于描述渲染文档时元素必须在另一个之上绘制的顺序,...
回答by Lucas Willems
Try to invert #one
and #two
. Have a look to this fiddle : http://jsfiddle.net/hu2pk/3/
尝试反转#one
和#two
。看看这个小提琴:http: //jsfiddle.net/hu2pk/3/
Update
Update
In SVG, z-index is defined by the order the element appears in the document. You can have a look to this page too if you want : https://stackoverflow.com/a/482147/1932751
在 SVG 中,z-index 由元素在文档中出现的顺序定义。如果需要,您也可以查看此页面:https: //stackoverflow.com/a/482147/1932751
回答by Steve Ladavich
As others here have said, z-index is defined by the order the element appears in the DOM. If manually reordering your html isn't an option or would be difficult, you can use D3 to reorder SVG groups/objects.
正如这里的其他人所说,z-index 是由元素在 DOM 中出现的顺序定义的。如果手动重新排序您的 html 不是一种选择或很困难,您可以使用 D3 重新排序 SVG 组/对象。
Use D3 to Update DOM Order and Mimic Z-Index Functionality
使用 D3 更新 DOM 顺序和模仿 Z-Index 功能
Updating SVG Element Z-Index With D3
At the most basic level (and if you aren't using IDs for anything else), you can use element IDs as a stand-in for z-index and reorder with those. Beyond that you can pretty much let your imagination run wild.
在最基本的层面上(如果您不将 ID 用于其他任何用途),您可以使用元素 ID 作为 z-index 的替代品,并使用它们重新排序。除此之外,您几乎可以尽情发挥您的想象力。
Examples in code snippet
代码片段中的示例
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>
The basic idea is:
基本思想是:
Use D3 to select the SVG DOM elements.
var circles = d3.selectAll('circle')
Create some array of z-indices with a 1:1 relationship with your SVG elements (that you want to reorder). Z-index arrays used in the examples below are IDs, x & y position, radii, etc....
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] }
Then, use D3 to bind your z-indices to that selection.
circles.data(zOrders[setOrderBy]);
Lastly, call D3.sort to reorder the elements in the DOM based on the data.
circles.sort(setOrder);
使用 D3 选择 SVG DOM 元素。
var circles = d3.selectAll('circle')
创建一些与 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] }
然后,使用 D3 将您的 z 索引绑定到该选择。
circles.data(zOrders[setOrderBy]);
最后,调用 D3.sort 根据数据对 DOM 中的元素重新排序。
circles.sort(setOrder);
Examples
例子
- You can stack by ID
- 可以按ID堆叠
- With leftmost SVG on top
- 最左边的SVG在顶部
- Smallest radii on top
- 顶部的最小半径
- Or Specify an array to apply z-index for a specific ordering -- in my example code the array
[3,4,1,2,5]
moves/reorders the 3rd circle (in the original HTML order) to be 1st in the DOM, 4th to be 2nd, 1st to be 3rd, and so on...
- 或指定一个数组以将 z-index 应用于特定排序——在我的示例代码中,数组
[3,4,1,2,5]
移动/重新排序第 3 个圆圈(按原始 HTML 顺序)在 DOM 中为第 1 个,第 4 个为第 2 个,第 1 个为第 3 个, 等等...
回答by Jose Rui Santos
You can use 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>
The green circle appears on top.
jsFiddle
绿色圆圈出现在顶部。
js小提琴
回答by bumsoverboard
As discussed, svgs render in order and don't take z-index into account (for now). Maybe just send the specific element to the bottom of its parent so that it'll render last.
如前所述,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"));
Worked for me.
为我工作。
Update
更新
If you have a nested SVG, containing groups, you'll need to bring the item out of its parentNode.
如果您有一个包含组的嵌套 SVG,则需要将该项目从其 parentNode 中取出。
function bringToTopofSVG(targetElement){
let parent = targetElement.ownerSVGElement;
parent.appendChild(targetElement);
}
A nice feature of SVG's is that each element contains it's location regardless of what group it's nested in :+1:
SVG 的一个很好的特性是每个元素都包含它的位置,而不管它嵌套在哪个组中:+1:
回答by Diso
Using D3:
使用 D3:
If you want to re-inserts each selected element, in order, as the last child of its parent.
如果要按顺序重新插入每个选定元素,作为其父元素的最后一个子元素。
selection.raise()
回答by Hafenkranich
There is no z-index for svgs. But svg determines which of your elements are the uppermost by theire position in the DOM. Thus you can remove the Object and place it to the end of the svg making it the "last rendered" element. That one is then rendered "topmost" visually.
svgs 没有 z-index。但是 svg 通过它们在 DOM 中的位置来确定哪些元素是最上面的。因此,您可以删除对象并将其放置在 svg 的末尾,使其成为“最后呈现”的元素。然后在视觉上将那个渲染为“最顶层”。
Using jQuery:
使用jQuery:
function moveUp(thisObject){
thisObject.appendTo(thisObject.parents('svg>g'));
}
usage:
用法:
moveUp($('#myTopElement'));
Using D3.js:
使用 D3.js:
d3.selection.prototype.moveUp = function() {
return this.each(function() {
this.parentNode.appendChild(this);
});
};
usage:
用法:
myTopElement.moveUp();
回答by Nathan Hensher
Using D3:
使用 D3:
If you want to add the element in the reverse order to the data use:
如果要以相反的顺序将元素添加到数据中,请使用:
.insert('g', ":first-child")
Instead of .append
而不是 .append
回答by Roman Rekhler
Another solution would be to use divs, which do use zIndex to contain the SVG elements.As here: https://stackoverflow.com/a/28904640/4552494
另一种解决方案是使用 div,它确实使用 zIndex 来包含 SVG 元素。如这里:https: //stackoverflow.com/a/28904640/4552494
回答by Douglas Daseeco
The clean, fast, and easy solutions posted as of the date of this answer are unsatisfactory. They are constructed over the flawed statement that SVG documents lack z order. Libraries are not necessary either. One line of code can perform most operations to manipulate the z order of objects or groups of objects that might be required in the development of an app that moves 2D objects around in an x-y-z space.
截至本答案发布之日,发布的干净、快速和简单的解决方案并不令人满意。它们是基于 SVG 文档缺乏 z 顺序的有缺陷的陈述而构建的。图书馆也不是必需的。一行代码可以执行大多数操作来操纵对象或对象组的 z 顺序,这些操作在开发在 xyz 空间中移动 2D 对象的应用程序中可能需要。
Z Order Definitely Exists in SVG Document Fragments
Z 顺序绝对存在于 SVG 文档片段中
What is called an SVG document fragment is a tree of elements derived from the base node type SVGElement. The root node of an SVG document fragment is an SVGSVGElement, which corresponds to an HTML5 <svg>tag. The SVGGElement corresponds to the <g>tag and permits aggregating children.
所谓的 SVG 文档片段是从基本节点类型 SVGElement 派生的元素树。SVG 文档片段的根节点是一个 SVGSVGElement,它对应于 HTML5 <svg>标签。SVGGElement 对应于<g>标记并允许聚合子项。
Having a z-index attribute on the SVGElement as in CSS would defeat the SVG rendering model. Sections 3.3 and 3.4 of W3C SVG Recommendation v1.1 2nd Edition state that SVG document fragments (trees of offspring from an SVGSVGElement) are rendered using what is called a depth first search of the tree. That scheme is a z order in every sense of the term.
在 SVGElement 上拥有一个 z-index 属性就像在 CSS 中一样会破坏 SVG 渲染模型。W3C SVG Recommendation v1.1 2nd Edition 的第 3.3 和 3.4 节声明 SVG 文档片段(来自 SVGSVGElement 的后代树)是使用所谓的树的深度优先搜索来呈现的。该方案在该术语的任何意义上都是 az 顺序。
Z order is actually a computer vision shortcut to avoid the need for true 3D rendering with the complexities and computing demands of ray tracing. The linear equation for the implicit z-index of elements in an SVG document fragment.
Z 顺序实际上是一种计算机视觉捷径,可避免由于光线追踪的复杂性和计算需求而需要真正的 3D 渲染。SVG 文档片段中元素的隐式 z-index 的线性方程。
z-index = z-index_of_svg_tag + depth_first_tree_index / tree_node_qty
This is important because if you want to move a circle that was below a square to above it, you simply insert the square before the circle. This can be done easily in JavaScript.
这很重要,因为如果您想将位于正方形下方的圆移动到其上方,只需在圆之前插入正方形即可。这可以在 JavaScript 中轻松完成。
Supporting Methods
支持方法
SVGElement instances have two methods that support simple and easy z order manipulation.
SVGElement 实例有两种支持简单易行的 z 顺序操作的方法。
- parent.removeChild(child)
- parent.insertBefore(child, childRef)
- parent.removeChild(child)
- parent.insertBefore(child, childRef)
The Correct Answer That Doesn't Create a Mess
不会造成混乱的正确答案
Because the SVGGElement (<g>tag) can be removed and inserted just as easily as a SVGCircleElement or any other shape, image layers typical of Adobe products and other graphics tools can be implemented with ease using the SVGGElement. This JavaScript is essentially a Move Belowcommand.
由于可以像删除和插入 SVGCircleElement 或任何其他形状一样轻松地删除和插入SVGGElement(<g>标记),因此可以使用 SVGGElement 轻松实现 Adobe 产品和其他图形工具的典型图像层。这个 JavaScript 本质上是一个移动下方命令。
parent.insertBefore(parent.removeChild(gRobot), gDoorway)
If the layer of a robot drawn as children of SVGGElement gRobot was before the doorway drawn as children of SVGGElement gDoorway, the robot is now behind the doorway because the z order of the doorway is now one plus the z order of the robot.
如果绘制为 SVGGElement gRobot 的孩子的机器人的层在绘制为 SVGGElement gDoorway 的孩子的门口之前,机器人现在在门口后面,因为门口的 z 阶现在是机器人的 z 阶加一。
A Move Abovecommand is almost as easy.
一个以上移动命令是几乎一样简单。
parent.insertBefore(parent.removeChild(gRobot), gDoorway.nextSibling())
Just think a=a and b=b to remember this.
想想 a=a 和 b=b 来记住这一点。
insert after = move above
insert before = move below
Leaving the DOM in a State Consistent With the View
让 DOM 处于与视图一致的状态
The reason this answer is correct is because it is minimal and complete and, like the internals of Adobe products or other well designed graphics editors, leaves the internal representation in a state that is consistent with the view created by rendering.
这个答案正确的原因是因为它是最小的和完整的,并且像 Adobe 产品或其他设计良好的图形编辑器的内部一样,使内部表示处于与通过渲染创建的视图一致的状态。
Alternative But Limited Approach
替代但有限的方法
Another approach commonly used is to use CSS z-index in conjunction with multiple SVG document fragments (SVG tags) with mostly transparent backgrounds in all but the bottom one. Again, this defeats the elegance of the SVG rendering model, making it difficult to move objects up or down in the z order.
另一种常用的方法是将 CSS z-index 与多个 SVG 文档片段(SVG 标签)结合使用,除了底部之外,所有的背景几乎都是透明的。同样,这破坏了 SVG 渲染模型的优雅,使得在 z 顺序中向上或向下移动对象变得困难。
NOTES:
笔记:
- (https://www.w3.org/TR/SVG/render.htmlv 1.1, 2nd Edition, 16 August 2011)
3.3 Rendering Order Elements in an SVG document fragment have an implicit drawing order, with the first elements in the SVG document fragment getting "painted" first. Subsequent elements are painted on top of previously painted elements.
3.4 How groups are rendered Grouping elements such as the ‘g' element (see container elements) have the effect of producing a temporary separate canvas initialized to transparent black onto which child elements are painted. Upon the completion of the group, any filter effects specified for the group are applied to create a modified temporary canvas. The modified temporary canvas is composited into the background, taking into account any group-level masking and opacity settings on the group.
- (https://www.w3.org/TR/SVG/render.htmlv 1.1,第 2 版,2011 年 8 月 16 日)
3.3 渲染顺序 SVG 文档片段中的元素具有隐式绘制顺序,SVG 文档片段中的第一个元素首先被“绘制”。后续元素绘制在先前绘制的元素之上。
3.4 如何呈现组 诸如“g”元素(请参阅容器元素)之类的分组元素具有生成临时单独画布的效果,该画布初始化为透明黑色,在其上绘制子元素。组完成后,为组指定的任何滤镜效果都将应用于创建修改后的临时画布。修改后的临时画布合成到背景中,考虑到组上的任何组级遮罩和不透明度设置。