Animated Canvas Arc

by navinleon

HTML

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css">
<div class="progress heart completed">
  <canvas id="bar" width="140" height="140"></canvas>
</div>

SCSS

*,*:before,*:after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
body {
  padding: 10px;
  background: #ccc;
}
//  Start here
.progress {
  position: relative;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  width: 140px;
  height: 140px;
  padding: 0;
  &:before {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    width: 132px;
    height: 132px;
    border: 2px solid #fff;
    border-radius: 50%;
    // preset color and font
    color: white;
    font-family: fontAwesome;
    font-size: 48px;
  }
  // Specific Variant center
  &.heart {
    &:before {
      content: "\0f21e";    // Use correct FontAwesome character
      padding-top: 6px;     // Vertical adjust to center
    }
  }
  // Completed Flag
  &.completed {
    &:after {
      position: absolute;
      top: 6.25%;
      right: 6.25%;
      height: 32px;
      width: 32px;
      border-radius: 50%;
      background-color: #FF5300; /// set to client color
      display: block;
      border: 2px solid #fff;
      text-align: center;
      font-family: fontAwesome;
      content: "\0f00c";
      color: white;
      font-size: 14px;
      line-height: 2em;
    }
  }
}

#bar {
  position: absolute;  
  top: 0px;
  left: 50%;
  transform: translateX(-50%);
  opacity: 1;
}
// end here

JavaScript

// CANVAS
var canvas = document.getElementById('bar'),
  width = canvas.width,
  height = canvas.height;

	console.log("width: " + width);
	console.log("height: " + height);

// CANVAS PROPERTIES
var ctx = canvas.getContext('2d');
ctx.lineWidth 		= 7;
ctx.strokeStyle 	= '#fff';
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur 		= 1;
ctx.shadowColor 	= '#fff';

// CANVAS MATH
var x = width / 2,
  	y = height / 2,
  	radius = 65,
  	circum = Math.PI * 2,
  	start = Math.PI / -2, // Start position (top)
  	finish = 65, // Final position of the draw (in %)
  	curr = 10; // Current position the draw starts (in %)

// CANVAS ANIMATION
// Enables browser-decided smooth animation (60fps)
var raf =
  window.requestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.msRequestAnimationFrame;
	window.requestAnimationFrame = raf;

// Animate function
function animate(draw_to) {
  // Clear off the canvas
  ctx.clearRect(0, 0, width, height);
  // Start over
  ctx.beginPath();
   
  // Re-draw from the very beginning each time so there isn't tiny line spaces between each section (the browser paint rendering will probably be smoother too)
  
  // arc(x, y, radius, startAngle, endAngle, anticlockwise)
  ctx.arc(x, y, radius, start, draw_to, false);
  // Draw
  ctx.stroke();
  // Increment percent
  curr++;
  // Animate until end
  if (curr < finish + 1) {
    // Recursive repeat this function until the end is reached (use requestAnimationFrame, and not setTimeout or setInterval!)
    requestAnimationFrame(function() {
      animate(circum * curr / 100 + start);
    });
  }
}

animate();

// origins: http://stackoverflow.com/questions/15692353/animate-a-canvas-circle-to-draw-on-load & http://jsfiddle.net/loktar/uhVj6/4/