0

I would like to make this graphic in SVG. I can use <animate> tags and I can manipulate the SVG document with javascript. I would prefer to do it all in SVG if possible.

enter image description here

Sean Clark Hess
  • 15,859
  • 12
  • 52
  • 100
  • How far have you got? – Robert Longson Feb 26 '14 at 16:26
  • Researching looks like I will have to animate an arc in the path data by hand... http://jbkflex.wordpress.com/2011/07/28/creating-a-svg-pie-chart-html5/ – Sean Clark Hess Feb 26 '14 at 16:28
  • 1
    I don't think so, you should be able to use SMIL for this. Animate the stroke-dasharray property of an arc path. – Robert Longson Feb 26 '14 at 16:29
  • You can always find a creative way to do it in SVG. I imagined drawing an arc and rotating a rectangle by one of the corners positioned in the center. Then you would gradually cover up half a circle. Or come up with some better shape to achieve something like this. – helderdarocha Feb 26 '14 at 16:30

4 Answers4

5

Here's a simpler example:

<svg height="200" width="200" viewBox="0 0 144 144">
    <circle cx="72" cy="72" r="49" stroke-width="6" stroke="#F68524" fill="none"/>
    <circle cx="72" cy="72" r="49" 
        stroke-width="6" stroke="#838588" fill="none">
        <animate attributeName="stroke-dasharray" values="154 0;0 154" dur="1s" repeatCount="indefinite"/>
    </circle>
</svg>

The proper values to use for the stroke-dasharray are based on the circle's circumference, 2 * π * r, and we want half of that so divide it by 2. In the example that computes to roughly 154.

See jsfiddle.

Update: Pretty close, but not quite the same, as noted. Here's a version that also animates the colors:

<svg height="200" width="200" viewBox="0 0 144 144">
    <circle cx="72" cy="72" r="49" stroke-width="6" stroke="#F68524" fill="none">
        <animate attributeName="stroke" values="#838588;#F68524" 
                 dur="2s" calcMode="discrete" repeatCount="indefinite"/>
    </circle>
    <circle cx="72" cy="72" r="49" 
        stroke-width="6" stroke="#838588" fill="none">
        <animate attributeName="stroke-dasharray" values="154 0;0 154" 
                 dur="1s" repeatCount="indefinite"/>
        <animate attributeName="stroke" values="#F68524;#838588" 
                 dur="2s" calcMode="discrete" repeatCount="indefinite"/>
    </circle>
</svg>

See jsfiddle.

Erik Dahlström
  • 59,452
  • 12
  • 120
  • 139
  • Woah that's awesome. I don't understand what it is doing though. What do the values represent? Please note that your example is not *quite* right. When it loops around it shouldn't have that flash. It should smoothly start spreading gray instead of orange. – Sean Clark Hess Feb 28 '14 at 18:28
1

This is just an idea for a starting point. You can then apply masks to hide and show parts of the graphic.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
    <circle cx="200" cy="200" r="100" fill="gray"/>
    <rect x="100" y="200" height="101" width="201" fill="white">
        <animateTransform attributeName="transform" 
            attributeType="XML"
            type="rotate" 
            from="0 200 200" 
            to="360 200 200" 
            dur="5s"
            repeatCount="indefinite"/>
    </rect>
    <circle cx="200" cy="200" r="90" fill="white"/>
</svg>
helderdarocha
  • 23,209
  • 4
  • 50
  • 65
1

Huge thanks to @helderdarocha to pointing me in the right direction.

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="144px" height="144px" viewBox="0 0 144 144" enable-background="new 0 0 144 144">

    <defs>
        <clipPath id="rotation-top" clip-path="url(#top-half)">
            <rect x="0" y="72" height="72" width="144">
                <animateTransform attributeName="transform" 
                    attributeType="XML"
                    type="rotate" 
                    from="360 72 72" 
                    to="0 72 72" 
                    dur="3s"
                    repeatCount="indefinite">
                </animateTransform>
            </rect>
        </clipPath>
        <clipPath id="rotation-bottom" clip-path="url(#bottom-half)">
            <rect x="0" y="0" height="72" width="144">
                <animateTransform attributeName="transform" 
                    attributeType="XML"
                    type="rotate" 
                    from="360 72 72" 
                    to="0 72 72" 
                    dur="3s"
                    repeatCount="indefinite">
                </animateTransform>
            </rect>
        </clipPath>
        <clipPath id="top-half">
            <rect x="0" y="0" height="72" width="144">
            </rect>
        </clipPath>
        <clipPath id="bottom-half">
            <rect x="0" y="72" height="72" width="144">
            </rect>
        </clipPath>
    </defs>

    <!-- background white -->
    <circle opacity="0.56" fill="#FFFFFF" cx="72" cy="72" r="72"/>

    <!-- back gray color -->
    <circle cx="72" cy="72" r="49" stroke-width="6" stroke="#838588" fill-opacity="0.0"/>

    <!-- foreground orange color --> 
    <circle 
        cx="72" cy="72" r="49" 
        stroke-width="6" stroke="#F68524" fill-opacity="0.0" 
        clip-path="url(#rotation-bottom)"
    />

    <circle 
        cx="72" cy="72" r="49" 
        stroke-width="6" stroke="#F68524" fill-opacity="0.0" 
        clip-path="url(#rotation-top)"
    />

</svg>
Sean Clark Hess
  • 15,859
  • 12
  • 52
  • 100
1

For cross-browser animation it is better to use Javascript. (IE doesn't support SMIL). setInterval is quite robust in all browsers.

For instance, to continously rotate an element, you would use:

function basicRotate()
{
    var FPS=100  //----frames per second---
    var angle = 0//---starting value---
    function frame()
    {
        angle++
        myElement.setAttribute("transform","rotate("+angle+" "+centetX+" "+centerY+")")
        if (angle == 360)
        angle=0
    }
    //---start interval timer---
    var iT = setInterval(frame, 1000/FPS ) //---draw every 10ms ---
} 
Francis Hemsher
  • 3,478
  • 2
  • 13
  • 15