Reputation: 326
I have trouble with ordering SVG elements. I wrote a script that takes the ratio of each number in an array to the sum of the numbers in it and creates a pie chart with regard to these numbers. Now, I'm trying to add some animations, but inherently, when I try to scale up the size of a slice, it seems behind the following paths.
I've tried the add z-index but apparently, that property doesn't work on SVG elements. I've tried to use 3D transform but I learned that too doesn't work on SVG. How can I overcome this problem?
My code:
var radius = 100
var slices = [3,4,3]
var sumSlices = slices.reduce((last,num) => last + num)
var degrees = Array.from(slices, num => (360*num)/sumSlices)
var colorPalet = ["#e668a0", "#53e1a0", "#53a7e1", "#f8a1c8", "#95f2c7", "#94caf0"]
var pie
var obj = new Array
var t, f1, f2, g1, g2
t = 0
degrees.forEach((degree, i) => {
obj[i] = new Object
f1 = radius * Math.cos((Math.PI/180)*t)
g1 = -(radius * Math.sin((Math.PI/180) * t))
obj[i]["lGo"] = f1 + " " + g1
t = degree + t
f2 = (radius * Math.cos((Math.PI/180) * t)) - f1
g2 = -(g1 + (radius * Math.sin((Math.PI/180) * t)))
if(degree < 180) obj[i]["aGo"] = radius + " " + radius + " 0 0 0" + f2 + " " + g2
else obj[i]["aGo"] = radius + " " + radius + " 0 1 0" + f2 + " " + g2
})
var tags = new Array
obj.forEach((sl, i) => {
tags[i] = '<path d="M'+ radius + " " + radius +' l'+ sl["lGo"] +' a'+ sl["aGo"] +' Z" fill="'+ colorPalet[i] +'" />'
})
document.getElementById("dd").innerHTML = tags.reduce((a, b) => a + " " + b)
body {margin:0}
.con {
position: absolute;
top:50%;
left:50%
}
.conIn {
position: absolute;
transform: translate(-50%, -50%);
}
svg {
overflow: initial;
}
path {
transition: 1s;
position: relative;
z-index: 1;
transform-origin: center
}
path:hover {
transform:scale(1.4);
}
<div class="con">
<div class="conIn">
<svg id="dd" width="100" height="100" >
</svg>
</div>
</div>
Upvotes: 0
Views: 741
Reputation: 3110
Unfortunately, as you noticed, SVG does not support z-index
. This functionality was proposed and eventually rejected. An <svg>
tag uses a single rendering/stacking context, and draws later children on top of earlier children.
Here are a few workarounds:
Use JavaScript to dynamically re-order items. You can add a mouseenter
event handler that moves the element to the end of the stack:
document.getElementById("dd").childNodes.forEach((path) =>
path.addEventListener('mouseenter', (e) =>
path.parentNode.appendChild(path)
)
);
Change your transition animations so that they don't cause overlap. The natural way to do this would be to manually set the .style.transitionOrigin
of your elements so that they scale from the center of the bar chart. See transform-origin. This will require a bit of computation, but given that you're already computing all the coordinates, it shouldn't be too hard.
Create separate <svg>
objects. Then you could use z-index
, I believe. But positioning them relative to each other would be quite difficult, I think.
By the way, your code would be easier to work with in these ways if you didn't assemble an HTML string and set innerHTML
, but instead uses document.createElement
to create elements and then document.getElementById("dd").appendChild
to add those elements as children.
Upvotes: 1