svg要素でz-indexを使用するには?


154

私はこのような私のプロジェクトで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>

また、gタグでz-indexを使用して、最初の要素を表示しています。私のプロジェクトでは、z-index値のみを使用する必要がありますが、svg要素にz-indexを使用できません。私はたくさんグーグルしましたが、比較的何も見つかりませんでした。それで、私のsvgでz-indexを使用するのを手伝ってください。

これがデモです。


回答:


163

仕様

SVG仕様バージョン1.1では、レンダリングの順序はドキュメントの順序に基づいています。

first element -> "painted" first

SVG 1.1への参照。仕様

3.3レンダリング順序

SVGドキュメントフラグメントの要素には暗黙的な描画順序があり、SVGドキュメントフラグメントの最初の要素最初「ペイント」されます。後続の要素は、以前にペイントされた要素の上にペイントされます。


ソリューション(より速くより速く)

緑色の円を、描画する最新のオブジェクトとして配置する必要があります。したがって、2つの要素を入れ替えます。

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

ここにあなたのjsFiddleのフォークがあります。

ソリューション(代替)

use属性をxlink:href持ち、値として要素のIDを持つタグ。結果が正常に見えても、最善の解決策ではない可能性があることに注意してください。少し時間がありましたが、ここではSVG 1.1仕様の「use」要素のリンクを使用しています

目的:

作成者が参照されたドキュメントを変更してルート要素に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>


SVG 2に関する注意

SVG 2仕様は次のメジャーリリースであり、上記の機能を引き続きサポートしています。

3.4。レンダリング順序

SVGの要素は3次元で配置されます。SVGビューポートのx軸とy軸上の位置に加えて、SVG要素はz軸上にも配置されます。z軸上の位置は、それらが描画される順序を定義しますます。

z軸に沿って、要素はスタックコンテキストにグループ化されます。

3.4.1。SVGでのスタッキングコンテキストの確立

...

スタッキングコンテキストは、ドキュメントのレンダリング時に要素を重ねて描画する必要がある順序説明するために使用される概念的なツールです...


レンダリング順序のオーバーライドに関する古いドラフトもありますが、これは使用できない機能です。ドラフト参照
Maicolpt 2014

12
うわぁ!特にオブジェクトがプログラムで生成され、入れ子になっているように見える場合(たとえば、gがa、bを含むことができず、aがgの兄弟より下にあるように見える)cですが、bはそれを上回っています)
Michael

@Michael:シナリオでは、最初に、要素を本当にグループ化する必要があるかどうかを理解しようとします。
Maicolpt

1
「use xlink:href」はクールで奇妙で、必要なものに最適です。
イアン、

32

ここで他の人が言ったように、z-indexは要素がDOMに現れる順序によって定義されます。HTMLを手動で並べ替えることができない場合、または難しい場合は、D3を使用してSVGグループ/オブジェクトを並べ替えることができます。

D3を使用してDOM順序を更新し、Z-Index機能を模倣する

D3によるSVG要素のZ-Indexの更新

最も基本的なレベル(および他に何もIDを使用していない場合)では、要素IDをz-indexの代用として使用して、それらを並べ替えることができます。それ以上に、想像力を大胆に発揮させることができます。

コードスニペットの例

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>

基本的な考え方は次のとおりです。

  1. D3を使用してSVG DOM要素を選択します。

    var circles = d3.selectAll('circle')
  2. SVG要素(並べ替えたい)と1対1の関係にあるzインデックスの配列を作成します。以下の例で使用されているZインデックス配列は、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]
    }
  3. 次に、D3を使用してZインデックスをその選択にバインドします。

    circles.data(zOrders[setOrderBy]);
  4. 最後に、D3.sortを呼び出して、データに基づいてDOM内の要素を並べ替えます。

    circles.sort(setOrder);

ここに画像の説明を入力してください

  • IDで積み重ねることができます

ここに画像の説明を入力してください

  • 一番左のSVGを上に

ここに画像の説明を入力してください

  • 上部の最小半径

ここに画像の説明を入力してください

  • または、特定の順序にz-indexを適用する配列を指定します-このサンプルコードでは、配列[3,4,1,2,5]は3番目の円を(元のHTML順序で)DOMで1番目に、4番目が2番目に、1番目が3番目に移動/並べ替えます、 等々...


間違いなくここで最良の答え... 10/10。なぜこれが今受け入れられるのですか?
Tigerrrrr

1
@Tigerrrrrrスタック順序の制御と同じくらい簡単なことをするために外部ライブラリをインポートすることは狂気です。さらに悪いことに、D3は特に大きなライブラリです。
iMe

2
@iMe、よく言った。これは問題の解決策ですがここにいる価値があります。それが、ではなく、あってはならない決して答え。現在の答えに取って代わるべき唯一のものは、より新しい仕様が出てブラウザが変わった場合でしょう。この答えを使用したい人は、D3のすべてをインポートするのではなく、必要なモジュールをインポートしてください。このためだけにD3のすべてをインポートしないでください。
スティーブ・ラダヴィッチ

31

反転#oneしてみてください#two。このフィドルを見てください:http : //jsfiddle.net/hu2pk/3/

Update

SVGでは、z-indexは要素がドキュメントに表示される順序で定義されます。必要に応じて、このページもご覧ください。https//stackoverflow.com/a/482147/1932751


1
ありがとうございますが、z-index値に基づく要素が必要です。
Karthi Keyan 2013

OK。そして、あなたは#oneが#twoまたはその反対にあることを望みますか?
Lucas Willems 2013

#oneのz-index値を-1と言った場合、トップレベルで表示されることを意味します。
Karthi Keyan 2013

10
SVG仕様のいずれにもz-indexプロパティはありません。上に表示される要素と下に表示される要素を定義する唯一の方法は、DOM順序付けを使用することです
nicholaswmin 2013

9
d3.selection.prototype.moveToFront = function() { return this.each(function() { this.parentNode.appendChild(this); }); };そして、あなたはstackoverflow.com/questions/14167863/…selection.moveToFront()を介して言うことができます
mb21

21

あなたは使用することができます使用を

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

緑色の円が上部に表示されます。
jsFiddle


4
これは#oneを2回引きますか?
mareoraft 2015

@mareoraftはい、#one2回描画されます。ただし、必要に応じて、CSSで最初のインスタンスを非表示にすることができます。use参照されたDOM要素を複製するのと同じ効果があります
Jose Rui Santos

+1はJavaScriptを必要としないためですが、-1は、<g>ロードする前にDOMを変更するときに、それ自体の順序を変更することもできるためです。
Hafenkranich、2016年

14

説明したように、svgは順番にレンダリングされ、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"));

私のために働いた。

更新

グループを含むネストされたSVGがある場合は、アイテムをそのparentNodeから取り出す必要があります。

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

SVGの優れた機能は、:+ 1でネストされているグループに関係なく、各要素にその位置が含まれていることです。


こんにちは、これは私にとってはうまくいきましたが、「底まで持っていく」相当はどうでしょうか ありがとう
gavin

@gavin SVG要素は上から順に描画されます。要素を上に配置するには、append()を最後の要素になるように追加します。逆に、一番下に要素を送信したい場合は、prepend()によって最初の要素として配置します。function bringToBottomofSVG(targetElement){let parent = targetElement.ownerSVGElement; parent.prepend(targetElement); }
bumsoverboard

13

D3の使用:

選択した各要素をその親の最後の子として順番に再挿入する場合。

selection.raise()

5
selection.raise()D4のv4の新機能です。
テファー2018年

9

svgのz-indexはありません。しかし、svgは、DOM内の位置によって、どの要素が最上位にあるかを決定します。したがって、オブジェクトを削除してsvgの最後に配置すると、「最後にレンダリングされた」要素になります。次に、それは視覚的に「最上位」にレンダリングされます。


jQueryの使用:

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

使用法:

moveUp($('#myTopElement'));

D3.jsの使用:

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

使用法:

myTopElement.moveUp();


2019年になりましたが、これは本当ですか?SVG 2.0が最新のブラウザで採用されたとき、
Andrew S



4

この回答の日付の時点で投稿された、クリーンで高速で簡単なソリューションは、満足のいくものではありません。これらは、SVGドキュメントにz順序が欠けているという欠陥のあるステートメントに基づいて作成されています。ライブラリも必要ありません。1行のコードでほとんどの操作を実行して、2次元オブジェクトをxyz空間で移動するアプリの開発で必要になる可能性のあるオブジェクトまたはオブジェクトグループのzオーダーを操作できます。

ZオーダーがSVGドキュメントフラグメントに確実に存在する

いわゆるSVGドキュメントフラグメントは、ベースノードタイプSVGElementから派生した要素のツリーです。SVGドキュメントフラグメントのルートノードは、HTML5 <svg>タグに対応するSVGSVGElement です。SVGGElementは<g>に対応しますタグに子の集約を許可します。

CSSのようにSVGElementにz-index属性があると、SVGレンダリングモデルが無効になります。W3C SVG勧告v1.1 2nd Editionのセクション3.3および3.4​​では、SVGドキュメントフラグメント(SVGSVGElementからの子のツリー)は、ツリーの深さ優先検索を使用してレンダリングされると述べています。そのスキームは、用語のあらゆる意味でzオーダーです。

Zオーダーは、レイトレーシングの複雑さとコンピューティングの要求を伴う真の3Dレンダリングの必要性を回避するためのコンピュータビジョンショートカットです。SVGドキュメントフラグメント内の要素の暗黙のz-indexの線形方程式。

z-index = z-index_of_svg_tag + depth_first_tree_index / tree_node_qty

正方形の下にあった円をその上に移動する場合は、円の前に正方形を挿入するだけなので、これは重要です。これはJavaScriptで簡単に実行できます。

サポート方法

SVGElementインスタンスには、シンプルで簡単なzオーダー操作をサポートする2つのメソッドがあります。

  • parent.removeChild(子)
  • parent.insertBefore(child、childRef)

混乱を引き起こさない正解

SVGGElement(<g>タグ)は、SVGCircleElementまたは他の形状と同じように簡単に削除および挿入できるため、SVGGElementを使用すると、アドビ製品や他のグラフィックツールに典型的な画像レイヤーを簡単に実装できます。このJavaScriptは基本的に「下に移動」コマンドです。

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

SVGGElement gRobotの子として描画されたロボットのレイヤーがSVGGElement gDoorwayの子として描画された出入り口の前にある場合、戸口のZオーダーはロボットのZオーダーに1を加えたものになるため、ロボットは戸口の後ろになりました。

上記移動コマンドは、ほとんどの場合簡単です。

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

これを覚えるには、a = aとb = bを考えてください。

insert after = move above
insert before = move below

ビューと整合性のある状態でDOMを残す

この答えが正しい理由は、それが最小限で完全であり、アドビ製品の内部または他の適切に設計されたグラフィックエディターと同様に、内部表現がレンダリングによって作成されたビューと一致する状態のままになるためです。

代替であるが限られたアプローチ

一般的に使用される別のアプローチは、CSS z-indexを複数のSVGドキュメントフラグメント(SVGタグ)と組み合わせて使用​​することです。繰り返しますが、これはSVGレンダリングモデルの優雅さを無効にし、zオーダーでオブジェクトを上下に移動することを困難にします。


ノート:

  1. https://www.w3.org/TR/SVG/render.html v 1.1、第2版、2011年8月16日)

    3.3 SVGドキュメントフラグメントのレンダリング順序要素には暗黙の描画順序があり、SVGドキュメントフラグメントの最初の要素が最初に「ペイント」されます。後続の要素は、以前にペイントされた要素の上にペイントされます。

    3.4グループのレンダリング方法 'g'要素(コンテナー要素を参照)などのグループ化要素は、子要素が描画される透明な黒に初期化された一時的な個別のキャンバスを作成する効果があります。グループが完了すると、グループに指定されたすべてのフィルター効果が適用され、変更された一時キャンバスが作成されます。変更された一時キャンバスは、グループレベルのマスキングとグループの不透明度設定を考慮して、背景に合成されます。


4

2019年はすでにありz-index、SVGではまだサポートされていません。

MozillaのSVG2サポートのサイトで、状態がz-index実装されていないことがわかります

サイトBug 360148「SVG要素の「z-index」プロパティをサポートする」でも確認できます(報告:12年前)。

しかし、それを設定するSVGには3つの可能性があります。

  1. element.appendChild(aChild);
  2. parentNode.insertBefore(newNode, referenceNode);
  3. targetElement.insertAdjacentElement(positionStr, newElement);(SVGのためのIEでサポートされません)

インタラクティブなデモの例

この3つの機能すべて。

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

SVG要素を最後までプッシュして、そのZインデックスが上になるようにします。SVGには、z-indexというプロパティはありません。以下のjavascriptを試して、要素を上に移動します。

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

ターゲット:トップに移動する必要のある要素ですsvg:要素のコンテナーです


0

それを行うのは簡単です:

  1. アイテムを複製する
  2. 複製したアイテムを並べ替える
  3. 複製したアイテムで置き換える

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>

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.