svg 요소에서 z-index를 사용하는 방법은 무엇입니까?


154

이 프로젝트에서 svg circle을 사용하고 있습니다.

<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 문서 조각의 첫 번째 요소"페인트" 됩니다. 후속 요소는 이전에 페인트 한 요소 위에 페인트됩니다.


솔루션 (보다 빠르고 빠름)

녹색 원은 가장 최근에 그릴 객체로 놓아야합니다. 따라서 두 요소를 바꾸십시오.

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


SVG 2에 대한 참고 사항

SVG 2 사양 은 다음 주요 릴리스이며 위의 기능을 계속 지원합니다.

3.4. 렌더링 순서

SVG의 요소는 3 차원으로 배치됩니다. SVG 뷰포트의 x 및 y 축에서의 위치 외에 SVG 요소도 z 축에 있습니다. z 축의 위치 는 페인트 순서를 정의합니다 .

z 축을 따라 요소는 스태킹 컨텍스트로 그룹화됩니다.

3.4.1. SVG에서 스태킹 컨텍스트 설정

...

스태킹 컨텍스트는 문서가 렌더링 될 때 요소가 다른 요소 위에 그려 져야하는 순서설명하는 데 사용되는 개념적 도구입니다 .


렌더링 순서를 재정의하는 데 대한 오래된 초안이 있지만 사용할 수없는 기능입니다. 초안 참조
Maicolpt

12
이케 특히 객체가 프로그래밍 방식으로 생성되고 중첩되어 나타날 수있는 경우 (예 : g 가 a, b를 포함 할 수없는 것처럼 보입니다) c 그러나 b는 위에있다)
Michael

@Michael : 시나리오에서 먼저 요소를 그룹화해야하는지 이해하려고합니다.
Maicolpt

1
'xlink : href 사용'은 시원하고 이상하며 내가 필요한 것에 완벽합니다!
Ian

32

다른 사람들이 말했듯이 z-index는 요소가 DOM에 나타나는 순서로 정의됩니다. HTML을 수동으로 재정렬하는 것이 옵션이 아니거나 어려운 경우 D3을 사용하여 SVG 그룹 / 객체를 재정렬 할 수 있습니다.

D3을 사용하여 DOM 순서 업데이트 및 Z- 인덱스 기능 모방

D3를 사용하여 SVG 요소 Z- 인덱스 업데이트

가장 기본적인 수준에서 (그리고 다른 용도로 ID를 사용하지 않는 경우) 요소 ID를 z- 인덱스의 독립형으로 사용하고 다시 정렬 할 수 있습니다. 그 너머로 상상력을 크게 발휘할 수 있습니다.

코드 스 니펫의 예

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]은 DOM에서 1 번째, 4 번째에서 2 번째, 1 번째에서 3 번째로 (원래 HTML 순서로) 3 번째 원을 이동 / 재주문합니다. , 등등...


확실히 가장 좋은 대답은 10/10입니다. 이것이 왜 지금 받아 들여 집니까?
Tigerrrrr

1
@Tigerrrrrr 스택 순서를 제어하는 ​​것만 큼 간단한 작업을 수행하기 위해 외부 라이브러리를 가져 오는 것은 광기입니다. 더 나쁘게 만들기 위해 D3는 특히 큰 라이브러리입니다.
iMe

2
@iMe, 잘 말했다. 이것이 문제에 대한 해결책 이지만 여기에 합당하게 만들 수 있습니다. 그것은하지 않고, 없어야 결코 대답. 최신 답변을 대체해야 할 유일한 것은 최신 사양이 나오고 브라우저가 변경되는 경우입니다. 이 답변을 사용하려는 사람은 D3을 모두 가져 오는 것이 아니라 필요한 모듈을 가져 오십시오. 이를 위해 D3을 모두 가져 오지 마십시오.
Steve Ladavich

31

반전을 시도 #one하고 #two. 이 바이올린을 살펴보십시오 : http://jsfiddle.net/hu2pk/3/

Update

SVG에서 z-index는 요소가 문서에 나타나는 순서로 정의됩니다 . 원하는 경우이 페이지를 볼 수도 있습니다 : https : //.com/a/482147/1932751


1
고맙지 만 z- 인덱스 값을 기반으로 요소가 필요합니다.
Karthi Keyan

확인. 그리고 #one이 # 2 또는 그 반대가 되길 원하십니까?
루카스 윌렘 스

나중에 #one에 대해 z-index 값을 -1로 말하면 최상위에 표시됩니다.
Karthi Keyan

10
SVG 사양에는 z-index 속성이 없습니다. 어떤 요소가 맨 위에 나타나고 맨 아래에 나타나는지를 정의하는 유일한 방법은 DOM 순서를 사용하는 것입니다.
nicholaswmin

9
d3.selection.prototype.moveToFront = function() { return this.each(function() { this.parentNode.appendChild(this); }); };그리고 당신은 stackoverflow.com/questions/14167863/…selection.moveToFront() 를 통해 말할 수 있습니다
mb21 September

21

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>

녹색 원이 맨 위에 나타납니다.
jsFiddle


4
이것은 #one을 두 번 그리는가?
mareoraft

@mareoraft 네, #one두 번 그려집니다. 그러나 원하는 경우 CSS를 통해 첫 번째 인스턴스를 숨길 수 있습니다. use참조 된 DOM 요소를 복제하는 것과 동일한 효과가 있습니다.
Jose Rui Santos

Javascript가 필요하지 않기 때문에 +1이지만 <g>,로드하기 전에 DOM을 변경할 때 자체 순서를 변경할 수도 있기 때문에 -1 입니다.
Hafenkranich

14

논의한 바와 같이 svgs는 순서대로 렌더링되며 z- 인덱스는 고려하지 않습니다 (현재). 어쩌면 특정 요소를 부모의 맨 아래로 보내서 마지막으로 렌더링 할 수 있습니다.

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의 좋은 기능은 각 요소가 어떤 그룹에 중첩되어 있는지에 관계없이 위치를 포함한다는 것입니다.


안녕, 이것은 나를 위해 일했지만 '바닥에 가져 오는'것은 무엇입니까? 감사합니다
gavin

@gavin SVG 요소는 위에서 아래로 순서대로 그려집니다. 요소를 맨 위에 놓기 위해 마지막 요소가되도록 append ()합니다. 반대로 요소를 맨 아래로 보내려면 prepend ()를 통해 첫 번째 요소로 배치합니다. 함수 bringToBottomofSVG (targetElement) {let parent = targetElement.ownerSVGElement; parent.prepend (targetElement); }
bumsoverboard

13

D3 사용 :

선택한 각 요소를 부모의 마지막 자식으로 순서대로 다시 삽입합니다.

selection.raise()

5
selection.raise()v4부터 D3의 새로운 기능입니다.
tephyr

9

svgs에 대한 z- 인덱스가 없습니다. 그러나 svg는 DOM에서 요소의 위치에 따라 가장 높은 요소를 결정합니다. 따라서 Object를 제거하고 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이 최신 브라우저에서 채택되면서?
앤드류 S



4

이 답변 날짜에 게시 된 깨끗하고 빠르고 쉬운 솔루션은 불만족 스럽습니다. SVG 문서에는 z 순서가 없다는 잘못된 설명으로 구성됩니다. 라이브러리도 필요하지 않습니다. 한 줄의 코드는 대부분의 작업을 수행하여 xyz 공간에서 2D 객체를 이동시키는 앱 개발에 필요할 수있는 객체 또는 객체 그룹의 z 순서를 조작 할 수 있습니다.

SVG 문서 조각에 Z 순서가 존재 함

SVG 문서 조각은 기본 노드 유형 SVGElement에서 파생 된 요소 트리입니다. SVG 문서 조각의 루트 노드는 SVGSVGElement이며 HTML5 <svg> 태그에 해당합니다. SVGGElement는 <g> 태그에 해당하며 자식을 집계 할 수 있습니다.

CSS에서와 같이 SVGElement에 z-index 속성이 있으면 SVG 렌더링 모델이 무효화됩니다. W3C SVG 권장 사항 v1.1 2 판의 3.3 절과 3.4 절에서는 SVG 문서 조각 (SVGVSElement의 자손 나무)을 트리의 깊이 우선 검색 이라고하는 것을 사용하여 렌더링한다고 설명 합니다 . 이 계획은 모든 의미에서 z 순서입니다.

Z 순서는 실제로 레이 트레이싱의 복잡성과 컴퓨팅 요구와 함께 진정한 3D 렌더링이 필요하지 않도록하는 컴퓨터 비전 바로 가기입니다. SVG 문서 조각에서 요소의 암시 적 z- 색인에 대한 선형 방정식.

z-index = z-index_of_svg_tag + depth_first_tree_index / tree_node_qty

정사각형 아래에있는 원을 그 위로 이동하려면 원 앞에 정사각형을 삽입하기 만하면됩니다. 이것은 JavaScript에서 쉽게 수행 할 수 있습니다.

지원 방법

SVGElement 인스턴스에는 간단하고 쉬운 z 순서 조작을 지원하는 두 가지 메소드가 있습니다.

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

혼란을 일으키지 않는 정답

SVGGElement ( <g> 태그)는 SVGCircleElement 또는 다른 모양처럼 쉽게 제거하고 삽입 할 수 있기 때문에 SVGGElement 를 사용하여 Adobe 제품 및 기타 그래픽 도구의 일반적인 이미지 레이어를 쉽게 구현할 수 있습니다. 이 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을 떠나기

이 답변이 옳은 이유는 Adobe 제품이나 기타 잘 디자인 된 그래픽 편집기의 내부와 같이 최소화되고 완벽하기 때문입니다. 렌더링으로 작성된 뷰와 일치하는 상태로 내부 표현을 유지합니다.

대안이지만 접근 방식

일반적으로 사용되는 또 다른 방법은 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

우리는 이미 2019z-index여전히 SVG에서 지원되지 않습니다.

사이트의 SVG2 지원에서z-index구현되지 않음 상태를 알 수 있습니다 .

버그 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라는 속성이 없습니다. 요소를 맨 위로 가져 오려면 아래 자바 스크립트를 사용해보십시오.

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.