Как использовать z-index в svg-элементах?

Я использую круги 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>

И я использую z-index в теге g чтобы показать элементы первыми. В моем проекте мне нужно использовать только значение z-index, но я не могу использовать z-index для своих элементов svg. Я много гуглил, но ничего не нашел относительно. Поэтому, пожалуйста, помогите мне использовать z-index в моем svg.

Вот ДЕМО.

Ответ 1

Спецификация

В спецификации версии 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>

Ответ 2

Попробуйте инвертировать #one и #two. Посмотрите на эту скрипку: http://jsfiddle.net/hu2pk/3/

Update

В SVG z-индекс определяется порядком появления элемента в документе. Вы также можете заглянуть на эту страницу, если хотите: fooobar.com/questions/74645/...

Ответ 3

Как уже говорили другие, z-index определяется порядком, в котором элемент появляется в DOM. Если переупорядочивание html вручную не является вариантом или будет затруднительным, вы можете использовать D3 для переупорядочения групп/объектов SVG.

Используйте D3 для обновления порядка DOM и имитации функциональности Z-индекса

Обновление SVG Element Z-Index с помощью D3

На самом базовом уровне (и если вы не используете идентификаторы для чего-либо еще), вы можете использовать идентификаторы элементов в качестве замены для 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>

Ответ 4

Вы можете использовать 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

Ответ 5

Нет индекса z для svgs. Но 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();

Ответ 7

Как уже говорилось, svgs рендерится по порядку и не учитывает 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:

Ответ 8

Используя D3:

Если вы хотите повторно вставить каждый выбранный элемент, по порядку, как последний дочерний элемент его родителя.

selection.raise()

Ответ 9

Другим решением было бы использовать divs, которые используют zIndex для размещения элементов SVG. Как здесь: fooobar.com/questions/74645/...

Ответ 10

У нас уже 2019 год, и z-index все еще не поддерживается в SVG.

На сайте поддержки SVG2 в Mozilla вы можете видеть, что состояние для z-index - не реализовано.

Вы также можете увидеть на сайте ошибку 360148 "Поддержка свойства z-index для элементов SVG" (сообщается: 12 лет назад).

Но у вас есть 3 возможности в SVG:

  1. С element.appendChild(aChild);
  2. С parentNode.insertBefore(newNode, referenceNode);
  3. С targetElement.insertAdjacentElement(positionStr, newElement); (Нет поддержки в IE для SVG)

Интерактивный демонстрационный пример

При всем этом 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>

Ответ 11

Чистые, быстрые и простые решения, опубликованные на дату данного ответа, являются неудовлетворительными. Они построены на ошибочном утверждении, что в документах SVG отсутствует порядок z. Библиотеки тоже не нужны. Одна строка кода может выполнять большинство операций для управления порядком z объектов или групп объектов, которые могут потребоваться при разработке приложения, которое перемещает 2D-объекты в пространстве XYZ.

Порядок Z определенно существует во фрагментах документов SVG

То, что называется фрагментом документа SVG, представляет собой дерево элементов, полученных из базового узла типа SVGElement. Корневым узлом фрагмента документа SVG является SVGSVGElement, который соответствует тегу HTML5 <svg>. SVGGElement соответствует тегу <g> и разрешает агрегирование дочерних элементов.

Наличие атрибута z-index в SVGElement, как в CSS, победило бы модель рендеринга SVG. В разделах 3.3 и 3.4 Рекомендации W3C SVG v1.1, 2-е издание говорится, что фрагменты документа SVG (деревья потомков из SVGSVGElement) визуализируются с использованием так называемого поиска в глубине дерева. Эта схема в любом смысле этого слова.

Z-порядок - это, по сути, ярлык компьютерного зрения, позволяющий избежать необходимости реального 3D-рендеринга со сложностями и вычислительными требованиями трассировки лучей. Линейное уравнение для неявного z-индекса элементов во фрагменте документа SVG.

z-index = z-index_of_svg_tag + depth_first_tree_index / tree_node_qty

Это важно, потому что если вы хотите переместить круг, который был ниже квадрата, над ним, вы просто вставляете квадрат перед кругом. Это можно легко сделать в JavaScript.

Методы поддержки

Экземпляры SVGElement имеют два метода, которые поддерживают простое и легкое манипулирование z-порядком.

  • parent.removeChild (ребенок)
  • parent.insertBefore(child, childRef)

Правильный ответ, который не создает беспорядок

Поскольку SVGGElement (тег <g>) можно удалять и вставлять так же легко, как SVGCircleElement или любую другую форму, слои изображения, типичные для продуктов Adobe и других графических инструментов, могут быть легко реализованы с помощью SVGGElement. Этот JavaScript по сути является командой Move Below.

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

Если слой робота, нарисованный в качестве дочерних элементов SVGGElement gRobot, находился до того, как дверной проем рисовался в качестве дочерних элементов SVGGElement gDoorway, робот теперь находится за дверным проемом, потому что теперь z-порядок дверного проема равен единице плюс z-порядок робота.

Команда Move Above почти так же проста.

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-е издание, 16 августа 2011 г.)

    3.3 Элементы порядка рендеринга во фрагменте документа SVG имеют неявный порядок рисования, причем первые элементы во фрагменте документа SVG сначала "закрашиваются". Последующие элементы окрашиваются поверх ранее окрашенных элементов.

    3.4 Как визуализируются группы Такие элементы группировки, как элемент 'g (см. Элементы контейнера), создают временный отдельный холст, инициализированный прозрачным черным, на котором закрашиваются дочерние элементы. После завершения группы все эффекты фильтра, указанные для группы, применяются для создания измененного временного холста. Модифицированный временный холст накладывается на фон, принимая во внимание любые параметры маскирования на уровне группы и параметры непрозрачности в группе.

Ответ 12

Выдвиньте элемент 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: контейнер элементов

Ответ 13

это легко сделать:

  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>