With JavaScript, can I change the Z index/layer of an SVG <g> element?

Let's say I have a couple composite shapes (<g>). I want to be able to click and drag them, but I want the one I happen to be dragging at the moment to be on TOP of the other one in the Z order, so that if I drag it over the OTHER one, the other one should be eclipsed.

Answers:

Answer

Z index in SVG is defined by the order the elements appear in the document. You will have to change the element order if you want to bring a specific shape to the top.

Answer

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

Answer

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>

Answer

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

Answer

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

Answer

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

Answer

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');
Answer

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.

Answer

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.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.