Come usare z-index negli elementi svg?


154

Sto usando i cerchi svg nel mio progetto in questo modo,

<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>

E sto usando lo z-index nel gtag per mostrare gli elementi per primi. Nel mio progetto ho bisogno di usare solo il valore z-index, ma non posso usare z-index per i miei elementi svg. Ho cercato su Google molto ma non ho trovato nulla relativamente. Quindi, per favore, aiutami a usare z-index nel mio svg.

Ecco la DEMO.


Risposte:


163

specificazione

Nella specifica SVG versione 1.1 l'ordine di rendering si basa sull'ordine del documento:

first element -> "painted" first

Riferimento a SVG 1.1. specificazione

3.3 Ordine di rendering

Gli elementi in un frammento di documento SVG hanno un ordine di disegno implicito, con i primi elementi nel frammento di documento SVG che vengono prima "dipinti" . Gli elementi successivi sono dipinti sopra gli elementi precedentemente dipinti.


Soluzione (più pulita più veloce)

Dovresti mettere il cerchio verde come ultimo oggetto da disegnare. Quindi scambia i due elementi.

<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>

Ecco la forchetta del tuo jsFiddle .

Soluzione (alternativa)

Il tag usecon l'attributo xlink:hrefe come valore l'id dell'elemento. Tieni presente che potrebbe non essere la soluzione migliore anche se il risultato sembra soddisfacente. Avendo un po 'di tempo, qui il link della specifica SVG 1.1 "usa" l'elemento .

Scopo:

Per evitare di richiedere agli autori di modificare il documento di riferimento per aggiungere un ID all'elemento radice.

<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>


Note su SVG 2

La specifica SVG 2 è la prossima versione principale e supporta ancora le funzionalità sopra.

3.4. Ordine di rendering

Gli elementi in SVG sono posizionati in tre dimensioni. Oltre alla loro posizione sull'asse xey della vista SVG, gli elementi SVG sono posizionati sull'asse z. La posizione sull'asse z definisce l'ordine in cui sono dipinti .

Lungo l'asse z, gli elementi sono raggruppati in contesti di sovrapposizione.

3.4.1. Stabilire un contesto di sovrapposizione in SVG

...

I contesti di sovrapposizione sono strumenti concettuali utilizzati per descrivere l'ordine in cui gli elementi devono essere dipinti uno sopra l'altro quando il documento viene renderizzato, ...


C'è anche una vecchia bozza sulla sostituzione dell'ordine di rendering, ma è una funzione non disponibile. Progetto di riferimento
Maicolpt

12
yikes! non è sempre facile disegnare gli elementi nell'ordine in cui li vuoi verniciare, specialmente se gli oggetti vengono generati in modo programmatico e possono apparire nidificati (ad esempio, sembra che g non possa contenere a, b, in modo che a sia inferiore a g fratello c ma b è sopra di esso)
Michael,

@Michael: Nel tuo scenario, per prima cosa cercherò di capire se davvero gli elementi devono essere raggruppati.
Maicolpt,

1
Quel 'usa xlink: href' è bello, strano e perfetto per quello di cui ho bisogno !!
Ian

32

Come altri hanno già detto, z-index è definito dall'ordine in cui l'elemento appare nel DOM. Se riordinare manualmente il tuo html non è un'opzione o sarebbe difficile, puoi usare D3 per riordinare gruppi / oggetti SVG.

Utilizzare D3 per aggiornare l'ordine DOM e la funzionalità Mimic Z-Index

Aggiornamento dell'indice Z dell'elemento SVG con D3

Al livello più elementare (e se non si utilizzano gli ID per qualcos'altro), è possibile utilizzare gli ID elemento come supporto per z-index e riordinarli con quelli. Oltre a ciò puoi praticamente liberare la tua immaginazione.

Esempi nello snippet di codice

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>

L'idea di base è:

  1. Utilizzare D3 per selezionare gli elementi SVG DOM.

    var circles = d3.selectAll('circle')
  2. Crea una serie di indici z con una relazione 1: 1 con i tuoi elementi SVG (che desideri riordinare). Gli array di indici Z utilizzati negli esempi seguenti sono ID, posizione x & y, raggi, ecc.

    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. Quindi, usa D3 per associare i tuoi indici z a quella selezione.

    circles.data(zOrders[setOrderBy]);
  4. Infine, chiama D3.sort per riordinare gli elementi nel DOM in base ai dati.

    circles.sort(setOrder);

Esempi

inserisci qui la descrizione dell'immagine

  • È possibile impilare per ID

inserisci qui la descrizione dell'immagine

  • Con SVG più a sinistra in alto

inserisci qui la descrizione dell'immagine

  • I raggi più piccoli in alto

inserisci qui la descrizione dell'immagine

  • Oppure Specifica un array per applicare z-index per un ordine specifico: nel mio codice di esempio l'array [3,4,1,2,5]sposta / riordina il 3 ° cerchio (nell'ordine HTML originale) per essere 1 ° nel DOM, 4 ° per essere 2 °, 1 ° per essere 3 ° , e così via...


Sicuramente la migliore risposta qui ... 10/10. Perché ora questo è accettato?
Tigerrrrr

1
@Tigerrrrrr Importare una libreria esterna per fare qualcosa di semplice come controllare l'ordine di impilamento è una follia. A peggiorare le cose, D3 è una libreria particolarmente grande.
iMe

2
@Me, ben detto. Mentre questa è una soluzione a un problema, è degno di essere qui; non è e non dovrebbe mai essere la risposta. L'unica cosa che dovrebbe mai sostituire la risposta attuale sarebbe se esce una nuova specifica e il browser cambia. Chiunque cerchi di usare questa risposta, non importa tutto il D3, importa solo i moduli di cui hai bisogno. NON IMPORTARE TUTTO D3 solo per questo.
Steve Ladavich,

31

Prova a invertire #onee #two. Dai un'occhiata a questo violino: http://jsfiddle.net/hu2pk/3/

Update

In SVG, z-index è definito dall'ordine in cui l'elemento appare nel documento . Puoi dare un'occhiata anche a questa pagina se vuoi: https://stackoverflow.com/a/482147/1932751


1
Grazie, ma ho bisogno dell'elemento basato sul valore z-index.
Karthi Keyan,

Ok. E vuoi che #one sia su #due o al contrario?
Lucas Willems,

Sì, se ho detto che il valore dell'indice z come -1 per #one significa che verrà mostrato al livello più alto.
Karthi Keyan,

10
Non esiste alcuna proprietà z-index in nessuna delle specifiche SVG. L'unico modo per definire quali elementi compaiono in alto e quali compaiono in fondo è utilizzando l'ordinamento DOM
nicholaswmin

9
d3.selection.prototype.moveToFront = function() { return this.each(function() { this.parentNode.appendChild(this); }); };E allora si può dire selection.moveToFront()tramite stackoverflow.com/questions/14167863/...
MB21

21

Puoi usare 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>

Il cerchio verde appare in alto.
jsFiddle


4
Questo disegna #one due volte?
mareoraft,

@mareoraft Sì, #oneviene disegnato due volte. Ma se vuoi, puoi nascondere la prima istanza tramite CSS. useha lo stesso effetto della clonazione dell'elemento DOM riferito
Jose Rui Santos,

+1 perché non ha bisogno di javascript ma -1 perché potresti anche cambiare l'ordine dello <g>stesso quando cambi il DOM prima di caricare comunque.
Hafenkranich,

14

Come discusso, gli svgs vengono visualizzati in ordine e non tengono conto di z-index (per ora). Forse basta inviare l'elemento specifico nella parte inferiore del suo genitore in modo da renderlo per ultimo.

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

Ha funzionato per me.

Aggiornare

Se si dispone di un file SVG nidificato, contenente gruppi, è necessario estrarre l'elemento dal relativo parentNode.

function bringToTopofSVG(targetElement){
  let parent = targetElement.ownerSVGElement;
  parent.appendChild(targetElement);
}

Una bella caratteristica di SVG è che ogni elemento contiene la sua posizione indipendentemente dal gruppo in cui è nidificato: +1:


ciao, questo ha funzionato per me, ma quale sarebbe l'equivalente "portare a fondo"? Grazie
Gavin il

Gli elementi SVG di @gavin sono disegnati in ordine dall'alto verso il basso. Per mettere un elemento in cima, lo aggiungiamo () in modo che sia l'ultimo elemento. Viceversa, se vogliamo un elemento inviato in fondo, lo posizioniamo come primo elemento da prepend (). funzione bringToBottomofSVG (targetElement) {let parent = targetElement.ownerSVGElement; parent.prepend (targetElement); }
bumsoverboard

13

Usando D3:

Se si desidera reinserire ogni elemento selezionato, in ordine, come l'ultimo figlio del suo genitore.

selection.raise()

5
selection.raise()è nuovo in D3 a partire da v4.
Tephyr,

9

Non esiste un indice z per svgs. Ma svg determina quali dei tuoi elementi sono i più in alto rispetto alla loro posizione nel DOM. In questo modo puoi rimuovere l'oggetto e posizionarlo alla fine dello svg rendendolo l'elemento "ultimo rendering". Quello viene quindi reso "più in alto" visivamente.


Utilizzando jQuery:

function moveUp(thisObject){
    thisObject.appendTo(thisObject.parents('svg>g'));
}

utilizzo:

moveUp($('#myTopElement'));

Utilizzando D3.js:

d3.selection.prototype.moveUp = function() {
    return this.each(function() {
        this.parentNode.appendChild(this);
    });
};

utilizzo:

myTopElement.moveUp();


è il 2019 adesso, è ancora vero? Come SVG 2.0 ha ottenuto l'adozione nei browser moderni?
Andrew S,



4

Le soluzioni pulite, veloci e facili pubblicate alla data di questa risposta sono insoddisfacenti. Sono costruiti sulla base dell'affermazione errata che i documenti SVG mancano di ordine z. Neanche le librerie sono necessarie. Una riga di codice può eseguire la maggior parte delle operazioni per manipolare l'ordine z di oggetti o gruppi di oggetti che potrebbero essere richiesti nello sviluppo di un'app che sposta gli oggetti 2D in uno spazio xyz.

L'ordine Z esiste sicuramente nei frammenti di documenti SVG

Quello che viene chiamato un frammento di documento SVG è un albero di elementi derivati ​​dal tipo di nodo di base SVGElement. Il nodo radice di un frammento di documento SVG è un SVGSVGElement, che corrisponde a un tag HTML5 <svg> . Il SVGGElement corrisponde al tag <g> e consente di aggregare i figli.

Avere un attributo z-index su SVGElement come nei CSS avrebbe sconfitto il modello di rendering SVG. Le sezioni 3.3 e 3.4 della Raccomandazione SVG W3C v1.1 2a Edizione affermano che i frammenti del documento SVG (alberi di prole da un SVGSVGElement) sono resi usando quella che viene chiamata una prima ricerca approfondita dell'albero . Questo schema è in ordine alfabetico in ogni senso del termine.

L'ordine Z è in realtà un collegamento alla visione artificiale per evitare la necessità di un vero rendering 3D con le complessità e le esigenze di elaborazione del ray tracing. L'equazione lineare per l'indice z implicito degli elementi in un frammento di documento SVG.

z-index = z-index_of_svg_tag + depth_first_tree_index / tree_node_qty

Questo è importante perché se vuoi spostare un cerchio che era sotto un quadrato sopra di esso, devi semplicemente inserire il quadrato prima del cerchio. Questo può essere fatto facilmente in JavaScript.

Metodi di supporto

Le istanze di SVGElement hanno due metodi che supportano la manipolazione di ordini z semplice e facile.

  • parent.removeChild (bambino)
  • parent.insertBefore (child, childRef)

La risposta corretta che non crea disordine

Poiché SVGGElement ( <g> tag) può essere rimosso e inserito con la stessa facilità di SVGCircleElement o di qualsiasi altra forma, i livelli di immagine tipici dei prodotti Adobe e di altri strumenti grafici possono essere implementati facilmente utilizzando SVGGElement. Questo JavaScript è essenzialmente un comando Sposta sotto .

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

Se lo strato di un robot disegnato come figli di SVGGElement gRobot era davanti alla porta disegnato come figli di SVGGElement gDoorway, il robot è ora dietro la porta perché l'ordine z della porta ora è uno più l'ordine z del robot.

Un comando Sposta sopra è quasi altrettanto semplice.

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

Basti pensare a = a e b = b per ricordare questo.

insert after = move above
insert before = move below

Lasciare il DOM in uno stato coerente con la vista

Il motivo per cui questa risposta è corretta è perché è minimo e completo e, come gli interni dei prodotti Adobe o altri editor grafici ben progettati, lascia la rappresentazione interna in uno stato coerente con la vista creata dal rendering.

Approccio alternativo ma limitato

Un altro approccio comunemente usato è quello di utilizzare CSS z-index insieme a più frammenti di documenti SVG (tag SVG) con sfondi per lo più trasparenti in tutti tranne quello in basso. Ancora una volta, questo sconfigge l'eleganza del modello di rendering SVG, rendendo difficile spostare gli oggetti verso l'alto o verso il basso nell'ordine z.


APPUNTI:

  1. ( https://www.w3.org/TR/SVG/render.html v 1.1, 2a edizione, 16 agosto 2011)

    3.3 Ordine di rendering Gli elementi in un frammento di documento SVG hanno un ordine di disegno implicito, con i primi elementi nel frammento di documento SVG che vengono prima "dipinti". Gli elementi successivi sono dipinti sopra gli elementi precedentemente dipinti.

    3.4 Modalità di rendering dei gruppi Il raggruppamento di elementi come l'elemento 'g' (vedere gli elementi contenitore) ha l'effetto di produrre una tela separata temporanea inizializzata in nero trasparente su cui sono dipinti gli elementi figlio. Al completamento del gruppo, tutti gli effetti filtro specificati per il gruppo vengono applicati per creare un'area di disegno temporanea modificata. La tela temporanea modificata viene composta sullo sfondo, tenendo conto delle impostazioni di mascheramento e opacità a livello di gruppo sul gruppo.


4

Abbiamo già il 2019 e non z-indexè ancora supportato in SVG.

Puoi vedere sul sito il supporto SVG2 in Mozilla per cui lo stato z-index- Non implementato .

Puoi anche vedere sul sito Bug 360148 "Supporta la proprietà 'z-index' sugli elementi SVG" (segnalato: 12 anni fa).

Ma hai 3 possibilità in SVG di impostarlo:

  1. Con element.appendChild(aChild);
  2. Con parentNode.insertBefore(newNode, referenceNode);
  3. Con targetElement.insertAdjacentElement(positionStr, newElement);(Nessun supporto in IE per SVG)

Esempio di demo interattiva

Con tutte queste 3 funzioni.

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>


2

Spingi l'elemento SVG per ultimo, in modo che il suo indice z sia in cima. In SVG non esiste alcuna proprietà chiamata z-index. prova qui sotto javascript per portare in primo piano l'elemento.

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

Target: è un elemento per il quale dobbiamo portarlo in alto svg: è il contenitore di elementi


0

è facile farlo:

  1. clona i tuoi articoli
  2. ordina gli elementi clonati
  3. sostituire gli articoli con clonati

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>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.