円形プログレスカウンター

モーション種別
  • スーッと系
コンポーネント
  • カウンター
トリガー
  • ロード時
技術
  • JavaScript

概要

円形のメーターと進捗度合いを示すアニメーションです。ロード時などに使えます。

JavaScriptでアニメーションの時間を指定し、その間でカウンターを0〜1で変動させています。

進捗度合いはカウンターを整数化して表示しています。

円のメータについてはSVGで描き、その長さを正規化し、stroke-dashoffsetを初期値1からカウンターを引き算することで0に近づけ、円のメーターをアニメーションさせています。

stroke-dashoffsetが0になることで円メーターが完了しますが、0になったタイミング(カウンターが100%になったタイミング)で円メーターの線を実線にすることで、始点と終点の継ぎ目が出ないように工夫しています。

コードサンプル

HTML

<div class="loader">
  <svg class="ring" viewBox="0 0 120 120">
    <circle class="track" cx="60" cy="60" r="54" pathLength="1"/>
    <circle class="progress" cx="60" cy="60" r="54" pathLength="1"/>
  </svg>
  <p class="value" aria-live="polite" aria-label="読み込み進捗">
    <span class="number">0</span><span class="percent">%</span>
  </p>
</div>

CSS

.loader {
  --circle-dia: 4em;

  position: relative;
  display: grid;
  place-items: center;
  width: var(--circle-dia);
  aspect-ratio: 1 / 1;
}

.ring {
  position: absolute;
  inset: 0;
  transform: rotate(-90deg);
}

circle {
  fill: none;
  stroke-width: 8;
}

.track {
  stroke: #F4F5F9;
}

.progress {
  stroke: #08254f;
  stroke-width: 8;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  stroke-linecap: butt;
  shape-rendering: geometricPrecision;
}

.value .percent {
  font-size: 0.8em;
}

JavaScript

document.addEventListener("DOMContentLoaded", function () {
  const numberEl   = document.querySelector(".number");
  const progressEl = document.querySelector(".progress");
  const duration   = 2000;

  window.runAnimation = function() {
    const start = performance.now();
    let last = -1;

    numberEl.textContent = "0";
    progressEl.style.strokeDasharray  = "1";
    progressEl.style.strokeDashoffset = "1";

    function frame(now){
      const raw = Math.min((now - start) / duration, 1);
      const pct = Math.floor(raw * 100);

      if (pct !== last){
        numberEl.textContent = pct;
        last = pct;
      }
      progressEl.style.strokeDashoffset = 1 - raw;

      if (raw < 1) {
        requestAnimationFrame(frame);
      } else {
        progressEl.style.strokeDasharray = "none";
        progressEl.style.strokeDashoffset = "0";
      }
    }

    requestAnimationFrame(frame);
  };

  runAnimation(); // ロード時に実行
});

お問い合わせ Contact

制作のご依頼やその他ご相談は、お問い合わせフォームにて受け付けております。

お問い合わせフォームへ