I've got an animated spinner SVG file. It's 12 bars in a circle that alter opacity.
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: rgba(0, 0, 0, 0) none repeat scroll 0% 0%; display: block; shape-rendering: auto;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<g transform="rotate(0 50 50)">
<rect x="48" y="17.5" rx="0" ry="0" width="4" height="15" fill="#336699">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.9166666666666666s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(30 50 50)">
<rect x="48" y="17.5" rx="0" ry="0" width="4" height="15" fill="#336699">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.8333333333333334s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(60 50 50)">
<rect x="48" y="17.5" rx="0" ry="0" width="4" height="15" fill="#336699">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.75s" repeatCount="indefinite"></animate>
</rect>
</g>
... [and so on, 12 times]
This works fine, but it's really repetitive, so I factored out one rect in a defs tag, and used use
to place it.
<defs>
<g id="bar">
<rect x="48" y="17.5" rx="0" ry="0" width="4" height="15" fill="#336699">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" repeatCount="indefinite"></animate>
</rect>
</g>
</defs>
<use xlink:href="#bar" transform="rotate(0 50 50)"/>
<use xlink:href="#bar" transform="rotate(30 50 50)"/>
...
This also works fine except I need to set the begin
property in the nested animate
tag. I've no idea how to reach that. The MDN for SVG's use doesn't seem to talk about altering children of elements made with use
and searching Google and SO doesn't turn up anything useful, since use
is such a common word.
I tried <use xlink:href="#bar" transform="rotate(0 50 50)"><animate begin="-0.9167s"></animate></use>
and a few other things that didn't work.
use
?Thanks all, and as this is my second question on SO, I'm more than open to suggestions on question form/content. Cheers.
To be clear, I don't want to do the animation in CSS or Javascript, I want everything contained in the SVG file. If it's not possible, that's good to know, too.
If you don't want repetition, you need code to create repetitive lines.
That can be done with a native Web Component (JSWC)
If you don't want code, you need to write repetitive lines.
Web Component:
customElements.define("svg-spinner", class extends HTMLElement {
connectedCallback() {
let size = this.getAttribute("size") || 100;
let background = this.getAttribute("background") || "transparent";
let fill = this.getAttribute("fill") || "#336699";
let spokes = new Array(12).fill("").map((_, idx) => {
return `<rect transform="rotate(${idx*30} 50 50)" fill="${fill}"
x="48" y="17.5" rx="0" ry="0" width="4" height="15">` +
`<animate attributeName="opacity" begin="${-(idx/12)}" values="1;0"
keyTimes="0;1" dur="1s" repeatCount="indefinite">
</animate></rect>`}).join("")
let style = `margin:auto;background:${background} none repeat scroll 0% 0%;display:inline-block;shape-rendering:auto`;
let svg = `<svg style="${style}" width="${size}px" height="${size}px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">` +
spokes + `</svg>`
this.innerHTML = svg;
}
});
<svg-spinner size="150"></svg-spinner>
<svg-spinner size="150" fill="green"></svg-spinner>
<svg-spinner size="150" fill="hotpink" background="pink"></svg-spinner>