Search code examples
svggradientpolar-coordinates

SVG polar gradients


I'm a beginner at SVG, but I'd like to learn some techniques.

To be short, is there a simple way to create something like this?

A common spinner

I was thinking about creating a polar gradient and then clipping it:

Polar gradient

But how do I generate a polar gradient?

Even if there's no native method, maybe it could be made with a simple linear gradient and then using some rectangular-polar coordinate transformation. Is there a way to do so?


Solution

  • So this is the solution I developed:

    <?xml version="1.0" standalone="no"?>
    <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 
    <svg viewBox="0 0 100 100" version="1.1" onload="makeGradient();">
        <script>
            function makeGradient() {
                var root = document.rootElement, i = 256, cir, a;
                for (; i--;) {
                    a = i*Math.PI/128;
                    cir = document.createElementNS("http://www.w3.org/2000/svg", "circle");
                    cir.setAttribute("cx", 50 - Math.sin(a)*45);
                    cir.setAttribute("cy", 50 - Math.cos(a)*45);
                    cir.setAttribute("r", "5");
                    cir.setAttribute("fill", "rgb(" + i + ", " + i + ", " + i + ")");
                    root.appendChild(cir);
                }
            }
        </script>
    </svg>
    

    Minified version (395 bytes):

    <?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" version="1.1" onload="g(this.namespaceURI,document,Math)"><script>function g(n,d,m,i,c,a,p,z){for(i=256;i--;){a=i*m.PI/128;c=d.createElementNS(n,"circle");for(p in z={cx:10-m.sin(a)*9,cy:10-m.cos(a)*9,r:1,fill:"rgb("+[i,i,i]+")"})c.setAttribute(p,z[p]);d.rootElement.appendChild(c)}}</script></svg>
    

    This was made creating circles filled with 256 shades of gray (it sounds like porn literature for coders!) and conveniently placed.

    The radii can be adjusted: I've chosen 45 for the whole spinner and 5 for the single circles. Moreover, the detail can be adjusted too if 256 are too many:

    for (; i -= 2;) { ...
    

    Use powers of 2 for optimal results. Or just define the number of steps:

    var steps = 100, i = steps;
    for (; i--;) {
        a = i*2*Math.PI/steps;
        ...
        cir.setAttribute("fill", "rgb(" + i*255/steps + ", " + ...);
    }
    

    A big "thank you" to Erik Dahlström for the hint, and thank you Michael Mullany for the attempt :)

    Edit: Here's a fiddle to demonstrate the code.

    Edit 2: Here's another fiddle using curved segments to create the spinner. You can adjust the number of segments and the size, and even see it spinning. I don't know why when the size is auto, there's a bottom margin of 5 pixels on the SVG, this making the spinning slightly off-centered...