使用 JavaScript,是否可以更改 SVG < g > 元素的 Z 索引/层?

假设我有两个复合形状(<g>)。我希望能够点击并拖动它们,但是我希望我此刻正在拖动的那个按 Z 顺序在另一个上面,这样如果我拖动它在另一个上面,另一个应该会被遮挡。

93010 次浏览

Z index in SVG is defined by the order the elements appear in the document (subsequent elements are painted on top of previous elements).

You will have to change the element order if you want to bring a specific shape to the top.

Yes the order is what specifies what object will be in front of the other. To manipulate the order you will need to move things about the DOM. There is a good example of this on the SVG wiki at https://www.w3.org/TR/SVG11/render.html#RenderingOrder

An alternative to moving elements in the tree is to use <use> elements where you change the xlink:href attribute so that it gives you the z ordering you want.

Here's an old thread on svg-developers mailinglist discussing this topic in context of wanting to animate some shapes.

Update:

<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
style="width:100%; height: 100%">
<circle id="c1" cx="50" cy="50" r="40" fill="lime" />
<rect id="r1" x="4" y="20" width="200" height="50" fill="cyan" />
<circle id="c2" cx="70" cy="70" r="50" fill="fuchsia" />
<use id="use" xlink:href="#c1" />
</svg>

In this example the <use> element is the last one, which makes it the frontmost element. We can choose any of the other elements to act as frontmost simply by changing the xlink:href attribute. In the above example we picked the circle with id="c1", which makes it appear as the topmost element.

See fiddle.

This is old question, but...

On FireFox (7+) and Chrome (14+) you can pull svg_element to the top. This does not give you freedom of full z axis control, but it's better than nothing ;)

Just append that element again.

var svg = doc.createElemNS('svg');
var circle = doc.createElemNS('circle');
var line = doc.createElemNS('line');


svg.appendChild(circle); // appends it
svg.appendChild(line);   // appends it over circle
svg.appendChild(circle); // redraws it over line now

I thought it was going to throw en error or something.

appendChild == replace itself == redraw

SVG uses a "painters model" of rendering. Paint is applied in successive operations to the output device such that each operation paints over some area of the output device. When the area overlaps a previously painted area the new paint partially or completely obscures the old.- link to this

Another solution not mentioned is to put each svg item/set of items into a div. You can alter the z-index of the divs easily.

Fiddle: SVG elements cycles with z-index for containers

...Press on the buttons to 'push' that element to the front. (vs repainting the whole set and pushing 1 element to front, but keeping the original order as in the accepted solution)

It would be very nice to have relative z indices...

stackOverflow wants me to put the code if it's a link from jsfiddle?...ook

var orderArray=[0,1,2];
var divArray = document.querySelectorAll('.shape');
var buttonArray = document.querySelectorAll('.button');


for(var i=0;i<buttonArray.length;i++){
buttonArray[i].onclick=function(){
var localI = i;
return function(){clickHandler(orderArray.indexOf(localI));};
}();
}




function clickHandler(divIndex) {
orderArray.push(orderArray.splice(divIndex, 1)[0]);
orderDivs();
}


function orderDivs(){
for(var i=0;i<orderArray.length;i++){
divArray[orderArray[i]].style.zIndex=i;
}
}
svg {
width: 100%;
height: 100%;
stroke: black;
stroke-width:2px;
pointer-events: all;
}
div{
position:absolute;
}
div.button{
top:55%;
height:5%;
width:15%;
border-style: outset;
cursor:pointer;
text-align: center;
background:rgb(175, 175, 234);
    

}
div.button:hover{
border-style: inset;
background:yellow;
    

}
div.button.first{
left:0%;
}
div.button.second{
left:20%;
}
div.button.third{
left:40%;
}
<div class="shape">
<svg>
<circle cx="50" cy="50" r="40" fill="lime" />
</svg>
</div>
<div class="shape">
<svg>
<rect x="4" y="20" width="200" height="50" fill="cyan" />
</svg>
</div>
<div class="shape">
<svg>
<circle cx="70" cy="70" r="50" fill="fuchsia" />
</svg>
</div>


<div class='button first'>lime</div>
<div class='button second'>cyan</div>
<div class='button third'>fuchsia</div>

If you use the svg.js library, you can use the ".front()" command to move any element to the top.

Adam Bradley's comment to Sam's answer was exactly on point. It uses jQuery rather than CSS only, but he said this:

$('#thing-i-want-on-top').appendTo('#my-svg');

However, for what I was creating, I needed my SVG Path to be above any other path on hover, but still be below my SVG Text. So here's what I came up with:

$('#thing-i-want-on-top').insertBefore('#id-for-svg-text');

Both appendTo and insertBefore will move your element to a new location allowing you to change the depth of the SVG element at will.

In SVG, to get a higher larger Z index you should move the element down in the DOM tree. You can do this with jQuery, selecting the SVG element, removing it and appending it again at the position you want:

$('g.element').remove().appendTo('svg');