I am working with a svg element which is following
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150">
<rect id="bg" width="150" height="150" fill="#e6e6e6"></rect>
<circle id="circ0" cx="75" cy="75" r="72" fill="none" stroke="blue" stroke-linecap="round" stroke-linejoin="round"></circle>
<circle id="circ1" cx="75" cy="75" r="69" fill="none" stroke="green" stroke-linecap="round" stroke-linejoin="round"></circle>
<circle id="circ2" cx="75" cy="75" r="66" fill="none" stroke="red" stroke-linecap="round" stroke-linejoin="round"></circle>
<script href="index.js"></script>
</svg>
I want to reverse the order of these circles with javascript, which I am currently doing by this way
const svg = document.querySelector("svg");
var x = document.querySelectorAll("[class^='circ']");
var bucket = [];
x.forEach((a, i) => {
bucket.push(a)
});
bucket.reverse();
x.forEach(
(a, i) => a.parentNode.removeChild(a)
);
bucket.forEach(
(a, i) => {
a.setAttribute("class", 'circ' [i]);
a.setAttribute("id", "circ" [i]);
svg.appendChild(a);
}
)
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150">
<rect id="bg" width="150" height="150" fill="#e6e6e6"></rect>
<circle id="circ0" cx="75" cy="75" r="72" fill="none" stroke="blue" stroke-linecap="round" stroke-linejoin="round"></circle>
<circle id="circ1" cx="75" cy="75" r="69" fill="none" stroke="green" stroke-linecap="round" stroke-linejoin="round"></circle>
<circle id="circ2" cx="75" cy="75" r="66" fill="none" stroke="red" stroke-linecap="round" stroke-linejoin="round"></circle>
<script href="index.js"></script>
</svg>
Is there a better way of doing this?
CodePudding user response:
append(child)
by itself moves DOM Nodes. So your code can be simplified.
But for complexer SVG you probably want to swap DOM positions, because there could be other Elements in between you don't want to affect.
- Hold CTRL key to see what happens with
append
- Click to see the swapping version,
a matter of processing an Array and swapping the first with the last element. - Note:
append
was not available in Internet Explorer, that is why you see most posts usingappendChild
.
Modern browsers have loads more DOM goodies:replaceWith
after
,before
etc.
<svg viewBox="0 0 10 10" style="height:200px">
<style>
text { font-size: 2px }
[y="3"]{ fill:yellow }
.first { stroke: black; stroke-width: 0.5 }
</style>
<rect id="bg" width="10" height="10" fill="grey"></rect>
<circle id="c0" cx="2" cy="5" r="2" fill="red" />
<text x="0" y="3">R</text>
<circle id="c1" cx="4" cy="5" r="3" fill="green" />
<text x="1" y="3">G</text>
<circle id="c2" cx="6" cy="5" r="4" fill="blue" />
<text x="2" y="3">B</text>
<text x="1" y="6">Click Me!</text>
</svg>
<script>
let svg = document.querySelector("svg");
function append() {
[...svg.querySelectorAll("circle")]
.reverse().forEach((c, i) => {
c.parentNode.append(c);
c.setAttribute("class", c.id = 'c' i);
});
}
function swap() {
function swapElements(e1, e2) {
let {id,previousSibling,className:{baseVal:c2}} = e2;
e1.after(e2); // put e2 after e1
e2.id = e1.id; e2.setAttribute("class", e1.getAttribute("class"));
previousSibling.after(e1); // put e1 after where e2 WAS
e1.id = id; e1.setAttribute("class", c2);
}
let circles = [...svg.querySelectorAll("circle")];
while (circles.length) {
let c1 = circles.shift();
if (circles.length) swapElements(c1, circles.pop())
}
}
svg.onclick = (e) => (e.ctrlKey && append()) || swap();
</script>