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

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>

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

Вот ДЕМО.

Карти Киан
источник

Ответы:

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и как значение идентификатором элемента. Имейте в виду, что это может быть не лучшим решением, даже если результат кажется хорошим. Имея немного времени, здесь ссылка на спецификацию SVG 1.1 "use" Element .

Цель:

Чтобы не требовать от авторов изменения ссылочного документа для добавления идентификатора в корневой элемент.

<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 Specification является следующей основной версией и все еще поддерживает вышеуказанные функции.

3.4. Порядок оформления

Элементы в SVG расположены в трех измерениях. В дополнение к их положению на осях x и y окна просмотра SVG, элементы SVG также расположены на оси z. Положение на оси z определяет порядок их рисования .

Вдоль оси z элементы сгруппированы в контексты суммирования.

3.4.1. Установление стекового контекста в SVG

...

Контексты стека - это концептуальные инструменты, используемые для описания порядка, в котором элементы должны быть нарисованы один над другим при визуализации документа, ...

Maicolpt
источник
Существует также старый черновик о переопределении порядка рендеринга, но эта функция недоступна. Проект ссылки
Майколпт
12
Хлоп! не всегда легко нарисовать элементы в том порядке, в котором вы хотите, чтобы они были нарисованы, особенно если объекты генерируются программно и могут казаться вложенными (например, кажется, что g не может содержать a, b, так что a ниже g родного брата) с, но б выше)
Майкл
@Michael: В вашем сценарии сначала я попытаюсь понять, действительно ли элементы должны быть сгруппированы.
Maicolpt
1
Это «использовать xlink: href» круто, странно и идеально подходит для того, что мне нужно!
Ян
32

Как уже говорили другие, z-индекс определяется порядком, в котором элемент появляется в 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>

Основная идея:

  1. Используйте D3 для выбора элементов SVG DOM.

    var circles = d3.selectAll('circle')
  2. Создайте некоторый массив z-индексов с соотношением 1: 1 с вашими элементами SVG (которые вы хотите изменить в порядке). Массивы Z-индекса, используемые в приведенных ниже примерах, представляют собой идентификаторы, координаты 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), чтобы быть 1-м в DOM, 4-м - 2-м, 1-м - 3-м , и так далее...

Стив Ладавич
источник
Определенно лучший ответ здесь ... 10/10. Почему это сейчас принято?
Tigerrrrr
1
@Tigerrrrrr Импортировать внешнюю библиотеку, чтобы сделать что-то столь же простое, как управление порядком размещения, - безумие. Что еще хуже, D3 - это особенно большая библиотека.
IME
2
@ Хорошо, хорошо сказано. Хотя это решение проблемы, что делает его достойным быть здесь; это не так , и никогда не должно быть, ответ. Единственное, что должно когда-либо заменить текущий ответ, - это если выйдет более новая спецификация и изменится браузер. Любой желающий использовать этот ответ, не импортируйте все D3, просто импортируйте нужные вам модули. НЕ ИМПОРТИРУЙТЕ ВСЕ D3 только для этого.
Стив Ладавич
31

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

Update

В SVG z-индекс определяется порядком, в котором элемент появляется в документе . Вы также можете просмотреть эту страницу, если хотите: https://stackoverflow.com/a/482147/1932751

Лукас Виллемс
источник
1
Спасибо, но мне нужно, чтобы элемент на основе значения z-index.
Karthi Keyan
Хорошо. И вы хотите, чтобы #one был на # два или наоборот?
Лукас Виллемс
да, если я сказал значение z-index как -1 для #one, значит, оно будет отображаться на верхнем уровне.
Karthi Keyan
10
В любой спецификации SVG нет свойства z-index. Единственный способ определить, какие элементы появляются сверху, а какие снизу, - это использовать порядок DOM
nicholaswmin,
9
d3.selection.prototype.moveToFront = function() { return this.each(function() { this.parentNode.appendChild(this); }); };И тогда вы можете сказать selection.moveToFront()через stackoverflow.com/questions/14167863/…
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 дважды?
Марофт
@mareoraft Да, #oneрисуется дважды. Но если вы хотите, вы можете скрыть первый экземпляр с помощью CSS. useимеет тот же эффект, что и клонирование упомянутого элемента DOM
Хосе Руи Сантос
+1, потому что он не нуждается в javascript, но -1, потому что вы могли бы также изменить порядок самого <g>себя при изменении DOM перед загрузкой в ​​любом случае.
Hafenkranich
14

Как уже говорилось, 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:

bumsoverboard
источник
привет, это сработало для меня, но каким будет эквивалент «довести до дна»? Спасибо
Гэвин
@gavin SVG элементы нарисованы в порядке сверху вниз. Чтобы поместить элемент сверху, мы добавляем () его так, чтобы это был последний элемент. И наоборот, если мы хотим, чтобы элемент был отправлен снизу, мы помещаем его как первый элемент с помощью prepend (). function yieldToBottomofSVG (targetElement) {пусть parent = targetElement.ownerSVGElement; parent.prepend (targetElement); }
bumsoverboard
13

Используя D3:

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

selection.raise()
Diso
источник
5
selection.raise()новый в D3 с v4.
Тефир
9

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

Hafenkranich
источник
его 2019 сейчас, это все еще правда? Как SVG 2.0 получил распространение в современных браузерах?
Андрей С.
4

Чистые, быстрые и простые решения, опубликованные на дату данного ответа, являются неудовлетворительными. Они построены на ошибочном утверждении, что в документах 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 или других хорошо разработанных графических редакторов, оставляет внутреннее представление в состоянии, которое соответствует представлению, созданному при рендеринге.

Альтернативный, но ограниченный подход

Другой обычно используемый подход заключается в использовании z-индекса CSS в сочетании с несколькими фрагментами документа 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' (см. Элементы контейнера), создают эффект создания отдельного временного холста, инициализированного прозрачным черным, на котором закрашиваются дочерние элементы. После завершения группы все эффекты фильтра, указанные для группы, применяются для создания измененного временного холста. Измененный временный холст накладывается на фон, принимая во внимание любые параметры маскирования и непрозрачности на уровне группы в группе.

Дуглас Дасеко
источник
4

У нас уже 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>

Бхарата
источник
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>

tdjprog
источник