Pure CSS3 or SVG animated Doughnut Chart

15.5k views Asked by At

I am looking for a pure CSS3 or SVG animated doughnut chart.

  • Need to have the middle circle fill colour
  • the outer circle to be split with a grey and a blue ie: blue 80% complete, grey 20% left remaining.
  • need text in the middle of the circle.

I have found one example http://jsfiddle.net/4azpfk3r/

Can anyone help creating / editing the above to what i need please? Its half way there.

<div class="item css">
   <h2>CSS</h2>
    <svg width="160" height="160" xmlns="http://www.w3.org/2000/svg">
     <g>
     <title>Layer 1</title>
       <circle id="circle" class="circle_animation" r="69.85699" cy="81" cx="81" stroke-width="8" stroke="#69aff4" fill="none"/>
      </g>
   </svg>
 </div>

Thanks

1

There are 1 answers

8
Akshay On BEST ANSWER

Try this, it uses stroke-dasharray to create strokes with a length of 251.2 see here for more reference . The stroke-dashoffset attribute specifies the distance into the dash pattern to start the dash see here

<svg width="100%" height="100%" viewbox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="tomato"/>
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="grey"/>
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#00CCFF" stroke-dasharray="251.2" stroke-dashoffset="50.3"/>
    <text x="40" y="50" fill="black" font-size="10">Text</text>
</svg>

Here the stroke fills 80% (calculated using 251.2 - 251.2*80/100, 251.2 is the perimeter of the circle calculated using 2 * 3.14 * 40). ie stroke-dashoffset = perimeter - perimeter * amount / 100 also set stroke-dasharray to perimeter. perimeter = 2 * 3.14 * radius.

You can check this blog post that explains the creation of doughnut charts easily.

See a 50% filled circle

<svg width="100%" height="100%" viewbox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="tomato"/>
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="grey"/>
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#00CCFF" stroke-dasharray="251.2" stroke-dashoffset="125.6"/>
    <text x="40" y="50" fill="black" font-size="10">Text</text>
</svg>

Demo with multiple rings :

<svg width="300px" height="300px" viewbox="0 0 100 100">
    <!-- Center color -->
    <circle cx="50" cy="50" r="40" fill="#eee"/>
    <!-- Default color of ring -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="grey"/>
    
    <!-- Progress -->
    <!-- The amount shown as 'filled' is the amount the ring fills, starting from right center (3 o' clock) -->
    <!-- 100% fill -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#2196f3" stroke-dasharray="251.2" stroke-dashoffset="0"/>
    <!-- 80% fill -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#ff5722" stroke-dasharray="251.2" stroke-dashoffset="50.3"/>
    <!-- 70% filled -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#009688" stroke-dasharray="251.2" stroke-dashoffset="75.36"/>
    <!-- 50% filled -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#9c27b0" stroke-dasharray="251.2" stroke-dashoffset="125.6"/>
    <!-- 40% filled -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#e91e63" stroke-dasharray="251.2" stroke-dashoffset="150.72"/>
    <!-- 20% filled -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#f44336" stroke-dasharray="251.2" stroke-dashoffset="200.96"/>
    <!-- Center Text -->
    <text x="40" y="50" fill="black" font-size="10">Text</text>
</svg>

Demo with animation (not tested in all browsers)

$(".progress").each(function() {
  var dataProgress = $(this).attr("stroke-dashoffset");
  $(this).attr("stroke-dashoffset", "251.2");
  $(this).animate({
    "stroke-dashoffset": dataProgress
  },1500)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<svg width="300px" height="300px" viewbox="0 0 100 100">
        <!-- Center color -->
        <circle cx="50" cy="50" r="40" fill="#eee"/>
        <!-- Default color of ring -->
        <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="white"/>
        
        <!-- Progress -->
        <!-- The amount shown as 'filled' is the amount the ring fills, starting from right center (3 o' clock) -->
        <!-- 100% fill -->
        <circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#2196f3" stroke-dasharray="251.2" stroke-dashoffset="0"/>
        <!-- 80% fill -->
        <circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#ff5722" stroke-dasharray="251.2" stroke-dashoffset="50.3"/>
        <!-- 70% filled -->
        <circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#009688" stroke-dasharray="251.2" stroke-dashoffset="75.36"/>
        <!-- 50% filled -->
        <circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#9c27b0" stroke-dasharray="251.2" stroke-dashoffset="125.6"/>
        <!-- 40% filled -->
        <circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#e91e63" stroke-dasharray="251.2" stroke-dashoffset="150.72"/>
        <!-- 20% filled -->
        <circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#f44336" stroke-dasharray="251.2" stroke-dashoffset="200.96"/>
        <!-- Center Text -->
        <text x="40" y="50" fill="black" font-size="10">Text</text>
    </svg>

Solution using jquery :

Give data-fill=amount to each of the .progress and jquery will do the rest

var radius = parseInt($("#radius").attr("r")) // Get the radius of the circle 
var perimeter = 2 * 3.14 * radius;

$(".progress").each(function(){
  var amount = parseFloat($(this).attr("data-fill"));
  var fillAmount = perimeter - perimeter * amount / 100;
  
  $(this).attr({
    "stroke-dasharray":perimeter,
    "stroke-dashoffset":fillAmount
  })
  
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<svg width="300px" height="300px" viewbox="0 0 100 100">
    <!-- Center color -->
    <circle cx="50" cy="50" r="40" fill="#eee" id="radius"/>
    <!-- Default color of ring -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="grey"/>
    
    <!-- Progress -->
    <!-- The amount shown as 'filled' is the amount the ring fills, starting from right center (3 o' clock) -->
    <!-- 100% fill -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#2196f3" data-fill="100" class="progress"/>
    <!-- 80% fill -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#ff5722" data-fill="80" class="progress"/>
    <!-- 70% filled -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#009688" data-fill="70" class="progress"/>
    <!-- 50% filled -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#9c27b0" data-fill="50" class="progress"/>
    <!-- 40% filled -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#e91e63" data-fill="40" class="progress"/>
    <!-- 20% filled -->
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#f44336" data-fill="20" class="progress"/>
    <!-- Center Text -->
    <text x="40" y="50" fill="black" font-size="10">Text</text>
</svg>