← 動的パーツギャラリーへ戻る

パーツ番号 09-06-12 ・ JavaScript使用

コンプリート達成コンフェッティ演出

円形プログレスが100%まで満ちると紙吹雪が舞い上がり「コンプリート!」の達成感を演出します。学習サイトの全ミッション制覇や実績コンプリート表示に使えます。

js

プレビュー

ソースコード

HTML

<div class="d09-06-12-box">
          <div class="d09-06-12-ring-wrap">
            <svg viewBox="0 0 100 100" class="d09-06-12-svg">
              <circle cx="50" cy="50" r="42" class="d09-06-12-bg"/>
              <circle cx="50" cy="50" r="42" class="d09-06-12-bar"/>
            </svg>
            <span class="d09-06-12-label">7/10</span>
          </div>
          <button type="button" class="d09-06-12-btn">全ミッション達成</button>
          <div class="d09-06-12-confetti"></div>
        </div>

CSS

.d09-06-12-box{position:relative;display:flex;flex-direction:column;align-items:center;gap:14px}
        .d09-06-12-ring-wrap{position:relative;width:100px;height:100px}
        .d09-06-12-svg{width:100px;height:100px;transform:rotate(-90deg)}
        .d09-06-12-bg{fill:none;stroke:#f1f5f9;stroke-width:8}
        .d09-06-12-bar{fill:none;stroke:#f59e0b;stroke-width:8;stroke-linecap:round;stroke-dasharray:264;stroke-dashoffset:186;transition:stroke-dashoffset 1s cubic-bezier(.2,.8,.2,1),stroke 1s ease}
        .d09-06-12-bar.is-full{stroke:#22c55e}
        .d09-06-12-label{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:15px;font-weight:800;color:#1e293b}
        .d09-06-12-btn{border:none;border-radius:999px;padding:9px 22px;background:#f59e0b;color:#fff;font-size:12.5px;font-weight:700;cursor:pointer}
        .d09-06-12-btn:disabled{opacity:.6;cursor:default}
        .d09-06-12-confetti{position:absolute;inset:0;pointer-events:none;overflow:visible}
        .d09-06-12-piece{position:absolute;left:50%;top:20px;width:6px;height:10px;opacity:0}
        .d09-06-12-piece.is-fly{animation:d09-06-12-fly .9s ease-out forwards}
        @keyframes d09-06-12-fly{
          0%{opacity:1;transform:translate(0,0) rotate(0deg)}
          100%{opacity:0;transform:translate(var(--dx),var(--dy)) rotate(var(--rot))}
        }

JavaScript

(function(){
        var root=document.getElementById('item-09-06-12');
        if(!root)return;
        var bar=root.querySelector('.d09-06-12-bar');
        var label=root.querySelector('.d09-06-12-label');
        var btn=root.querySelector('.d09-06-12-btn');
        var confetti=root.querySelector('.d09-06-12-confetti');
        var colors=['#f59e0b','#ec4899','#3b82f6','#10b981','#8b5cf6'];
        btn.addEventListener('click',function(){
          bar.style.strokeDashoffset='0';
          bar.classList.add('is-full');
          label.textContent='10/10';
          btn.disabled=true;
          setTimeout(function(){
            for(var i=0;i<16;i++){
              var p=document.createElement('span');
              p.className='d09-06-12-piece';
              p.style.background=colors[i%colors.length];
              var angle=Math.random()*Math.PI*2;
              var dist=40+Math.random()*36;
              p.style.setProperty('--dx',(Math.cos(angle)*dist)+'px');
              p.style.setProperty('--dy',(Math.sin(angle)*dist-20)+'px');
              p.style.setProperty('--rot',(Math.random()*400-200)+'deg');
              confetti.appendChild(p);
              (function(el){ requestAnimationFrame(function(){ el.classList.add('is-fly'); }); setTimeout(function(){ el.remove(); },950); })(p);
            }
          },300);
          setTimeout(function(){
            bar.style.strokeDashoffset='186';
            bar.classList.remove('is-full');
            label.textContent='7/10';
            btn.disabled=false;
          },3200);
        });
      })();

クラス名 .d09-06-12 は本ライブラリ内での識別用です。複数のパーツを同じページで使う場合は、重複しないよう名前を変更してください。