Search code examples
css-animationssvg-animate

SVG donut with colored segments and clock animation


I'm new to SVG and trying to familiarize myself with it. I would like to create a SVG donut with several segments each segments with different color. It's important that the segments should be interactive (meaning if I hover over them they should change color or pop out). The whole donut should appear with a clock animation.

I tried this with a simple circle and set the stroke-dasharray and stroke-dashoffset accordingly. The donut appears properly but when I apply the clock animation with CSS it overrides the color of all segments to the color of the last segment. But then I was thinking about if I want each segment to be interactive probably I have to create a circle svg element for each segment or a create svg arcs and build my donut that way.

I would appreciate any advice which way should I go. Here's my code so far:

HTML:

 <svg id = "circleMenuViewBox" width = "100%" height = "100%" viewBox="-10 -10 100 100">
    <defs>
      <circle id ="circlemenu" cx="10" cy="10" r="5" stroke-width="3" fill="none" stroke-dasharray="31.4"/>
      </defs>
      <use href="#circlemenu" stroke="#689689" stroke-dashoffset="0"/>
      <use href="#circlemenu" stroke="#83E8BA" stroke-dashoffset="7.85"/>
      <use href="#circlemenu" stroke="#B2E6D4" stroke-dashoffset="15.7"/>
      <use href="#circlemenu" stroke="#504136" stroke-dashoffset="23.55"/>
    </svg>

CSS:

#circlemenu { 
 fill: none;
 stroke-dasharray: 31.4;
 stroke-dashoffset: 31.4;
 animation: clock-animation 0.2s linear;
 animation-fill-mode: forwards;
}
@keyframes clock-animation {
  0% {
    stroke-dashoffset: 31.4;
  }
  100% {
    stroke-dashoffset: 0;
  }
}

Solution

  • Your animation is causing the last circle to overlay all other segments.

    Instead of animating the circle definition referenced by all <use> instances you can create a <mask> to progressively show the donut chart.

    #circleMask { 
     fill: none;
     stroke-dasharray: 31.4;
     stroke-dashoffset: 31.4;
     animation: clock-animation 0.8s linear;
     animation-fill-mode: forwards;
    }
    @keyframes clock-animation {
      0% {
        stroke-dashoffset: 31.4;
      }
      100% {
        stroke-dashoffset: 0;
      }
    }
    <svg id="circleMenuViewBox" width="100%" height="100%" viewBox="-10 -10 100 100">
      <defs>
        <circle id="circlemenu" cx="10" cy="10" r="5" stroke-width="3" fill="none" stroke-dasharray="31.4" />
        <mask id="mask" maskUnits="userSpaceOnUse">
            <use id="circleMask" class="segment" href="#circlemenu" stroke="#fff" />
        </mask>
      </defs>
      <g mask="url(#mask)">
      <use class="segment" href="#circlemenu" stroke="#689689" stroke-dashoffset="0" />
      <use class="segment" href="#circlemenu" stroke="#83E8BA" stroke-dashoffset="7.85" />
      <use class="segment" href="#circlemenu" stroke="#B2E6D4" stroke-dashoffset="15.7" />
      <use class="segment" href="#circlemenu" stroke="#504136" stroke-dashoffset="23.55" />
        </g>
    </svg>