<div id="example"></div>
html, body {
  background-color: #2962FF;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  position: relative;
}

circle {
          transition: stroke-dashoffset 0.35s;
          transform: rotate(-90deg);
          transform-origin: 50% 50%;
        }
View Compiled
const ProgressRing = Vue.component('progress-ring', {
  props: {
    radius: Number,
    progress: Number,
    stroke: Number
  },
  data() {
    const normalizedRadius = this.radius - this.stroke * 2;
    const circumference = normalizedRadius * 2 * Math.PI;
    
    return {
      normalizedRadius,
      circumference
    };
  },
  computed: {
    strokeDashoffset() {
      return this.circumference - this.progress / 100 * this.circumference;
    }
  },
  template: `
    <svg
      :height="radius * 2"
      :width="radius * 2"
     >
       <circle
         stroke="white"
         :stroke-dasharray="circumference + ' ' + circumference"
         :style="{ strokeDashoffset: strokeDashoffset }"
         :stroke-width="stroke"
         fill="transparent"
         :r="normalizedRadius"
         :cx="radius"
         :cy="radius"
      />
    </svg>
  `
});

  
// launch example with progress ring
new Vue({
  el: '#example',
  components: {
    'progress-ring': ProgressRing
  },
  data() {
    return { progress: 0 }
  },
  mounted() {
    // emulating progress
    const interval = setInterval(() => {
      this.progress += 10;
      if (this.progress === 100)
        clearInterval(interval);
    }, 1000);
  },
  template: `
    <div>
      <progress-ring radius="60" :progress="progress" stroke="4"></progress-ring>
    </div>
  `
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js