Loading SVG circle (using stroke-dashoffset)

(bonus: loading state)

by jorgeluis

HTML

<div class="container">

  <div class="p-1">
    <svg class="doughnut" width="100%" height="100%" viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="48" class="base-circle" stroke-width="4" />
      <circle class="value-circle" cx="50" cy="50" r="48" stroke-width="4"
        stroke-dasharray="301.584"
        stroke-dashoffset="38.99050285714287"
      />
    </svg>
  </div>

</div>


<button type="button" id="toggle">
Toggle loading state
</button>

<button type="button" id="reset">
Reset
</button>

CSS

.doughnut {
  fill: none;
  transform: rotate(-90deg);
}

.base-circle, .value-circle {
  fill: none;
}
.base-circle {
  stroke: rgba(150, 150, 150, 0.2)
}
.value-circle {
  stroke: orange;
  transition: stroke-dashoffset 1s;
}

/* loading state animation */
.is-loading .value-circle {
  animation: resetDashoffset 2s linear infinite;
  opacity: 0.3;
  transition: opacity 1s;
  stroke: var(--mute-color, #666);
  stroke-dasharray: 303;
  stroke-dashoffset: 305;
}
.reset .value-circle {
  animation: resetDashoffset 1s reverse;
  stroke-dasharray: 303;
}

@keyframes resetDashoffset {
  to {
    stroke-dashoffset: 0;
  }
}

@keyframes resetDasharray {
  to {
    stroke-dashoffset: 0;
  }
}




/* 
  the styles below are only for demo design 
*/
body {
  background: #191D22
}
.container {
  display: flex;
  justify-content: space-around;
}
svg {
  max-width: 150px;
}
.p-1 {
  padding: 1em
}

JavaScript

var toggle = document.querySelector('#toggle');
var reset = document.querySelector('#reset');

var doughnut = document.querySelector('.doughnut');


toggle.addEventListener('click', function() {
	doughnut.classList.toggle('is-loading')
})

reset.addEventListener('click', function() {
	doughnut.classList.remove('is-loading')
	doughnut.classList.toggle('reset')
})