progress-ring

by xachary

HTML

<!-- svg defs(global) only -->
<svg style="width: 0; height: 0;">
  <defs>
    <linearGradient id="gauge-gradient">
      <stop offset="0%" stop-color="#ff00ff"></stop>
      <stop offset="100%" stop-color="#333"></stop>
    </linearGradient>
    <linearGradient id="gauge-gradient2">
      <stop offset="0%" stop-color="#ffffff"></stop>
      <stop offset="100%" stop-color="#333"></stop>
    </linearGradient>
    <linearGradient id="gauge-gradient3">
      <stop offset="0%" stop-color="#00ffff"></stop>
      <stop offset="100%" stop-color="#333"></stop>
    </linearGradient>
  </defs>
</svg>

<!-- line -->

<div style="border: 1px solid #ffffff; display: flex; align-items: center;">
  <svg viewBox="0 0 300 10" style="display: block;">
    <line x1="0" y1="5" x2="300" y2="5" stroke-width="10" stroke="#333" stroke-dasharray="75,25"></line>
  </svg>
</div>

<br />

<!-- radius + stroke = 40 + 10 = 50 -->

<!-- full track -->
<div class="gauge">
  <svg viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke="#333"></circle>
  </svg>
</div>

<!-- 3/4 track before rotate -->

<!-- circumference = radius * 2 * PI = 40 * 2 * Math.PI = 251.3274 -->
<!-- stroke-dasharray left = circumference * percent = 251.3274 * 0.75 = 188.4955 -->
<!-- stroke-dasharray right = circumference * (1 - percent) = 251.3274 * (1 - 0.75) = 62.8318 -->
<div class="gauge">
  <svg viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="188.4955,62.8318" stroke="#333"></circle>
  </svg>
</div>

<!-- 3/4 track after rotate 135deg -->
<div class="gauge">
  <svg viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="188.4955,62.8318" transform="rotate(135, 50, 50)" stroke="#333"></circle>
  </svg>
</div>

<br />

<!-- progress bar -->

<!-- stroke-dasharray left = circumference * 0.75 * percent = 188.4955 * 0.10 = 18.8495 -->
<!-- stroke-dasharray right =...

CSS

body {
  background: black;
}

.gauge {
  position: relative;
  display: inline-block;
}

.gauge > svg {
  width: 200px;
  height: 200px;
}

.gauge > span {
  color: #fff;
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  text-align: center;
  transform: translate(0, -50%);
  font-size: 2em;
}

#circle {
  transition: all 1s linear;
}

JavaScript

(function() {
  const radius = 40;
  const trackPercent = 0.75
  const circumference = 40 * 2 * Math.PI;
  const percent = 1.00;

  const strokeDasharrayLeft = circumference * trackPercent * percent
  const strokeDasharrayRight = circumference * trackPercent * (1 - percent) + circumference * (1 - trackPercent)

  const circle = document.querySelector('#circle');

  function change() {
    const strokeDasharray = circle.getAttribute('stroke-dasharray').split(',')
    const left = parseFloat(strokeDasharray[0])
    const right = parseFloat(strokeDasharray[1])

    if (left === 0) {
      circle.setAttribute('stroke-dasharray', `${strokeDasharrayLeft},${strokeDasharrayRight}`)
    } else {
      circle.setAttribute('stroke-dasharray', `0,251.3274`)
    }
  }

  setTimeout(function() {

    setInterval(function() {
      change()
    }, 1000)

    change()
  }, 0)
})();