パーツ番号 08-15-10 ・ JavaScript使用
投げて飛んでいくドラッグ&リリース
勢いよくフリックすると慣性で飛んでいき、弱く離した場合はバネで元の位置に戻ります。WordPressのタスク完了スワイプや通知消去演出に使えます。
プレビュー
ソースコード
HTML
<div class="d08-15-10-wrap">
<div class="d08-15-10-stage" id="d08-15-10-stage">
<div class="d08-15-10-chip" id="d08-15-10-chip">✅ 完了</div>
</div>
<p class="d08-15-10-hint">フリックで放り投げる</p>
</div>CSS
.d08-15-10{width:100%;display:flex;align-items:center;justify-content:center}
.d08-15-10-wrap{display:flex;flex-direction:column;align-items:center;gap:10px}
.d08-15-10-stage{position:relative;width:220px;height:150px}
.d08-15-10-chip{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);background:linear-gradient(135deg,#6a5cff,#8b5cf6);color:#fff;font-size:13px;font-weight:700;padding:14px 20px;border-radius:14px;cursor:grab;touch-action:none;box-shadow:0 6px 16px rgba(106,92,255,.3);white-space:nowrap}
.d08-15-10-chip.is-drag{cursor:grabbing}
.d08-15-10-hint{font-size:11.5px;color:#9aa0b0;margin:0}JavaScript
(function(){
var root=document.getElementById('item-08-15-10');if(!root)return;
var chip=root.querySelector('#d08-15-10-chip');if(!chip)return;
var dragging=false,sx=0,sy=0,px=0,py=0,hist=[],raf=null;
function apply(x,y,op){chip.style.transform='translate(calc(-50% + '+x+'px), calc(-50% + '+y+'px))';chip.style.opacity=String(op);}
chip.addEventListener('pointerdown',function(e){
dragging=true;chip.classList.add('is-drag');chip.style.transition='';
if(raf)cancelAnimationFrame(raf);
sx=e.clientX-px;sy=e.clientY-py;hist=[{x:e.clientX,y:e.clientY,t:performance.now()}];
try{chip.setPointerCapture(e.pointerId);}catch(err){}
});
chip.addEventListener('pointermove',function(e){
if(!dragging)return;
px=e.clientX-sx;py=e.clientY-sy;
apply(px,py,1);
hist.push({x:e.clientX,y:e.clientY,t:performance.now()});
if(hist.length>5)hist.shift();
});
function springBack(){
var x=px,y=py,vx=0,vy=0,stiff=.16,damp=.74;
function step(){
var fx=(0-x)*stiff,fy=(0-y)*stiff;
vx=(vx+fx)*damp;vy=(vy+fy)*damp;
x+=vx;y+=vy;apply(x,y,1);
if(Math.abs(x)>.5||Math.abs(y)>.5||Math.abs(vx)>.5||Math.abs(vy)>.5){
raf=requestAnimationFrame(step);
}else{px=0;py=0;apply(0,0,1);}
}
raf=requestAnimationFrame(step);
}
function end(){
if(!dragging)return;
dragging=false;chip.classList.remove('is-drag');
var a=hist[0],b=hist[hist.length-1];
var dt=(b&&a)?((b.t-a.t)||16):16;
var vx=(b&&a)?(b.x-a.x)/dt*16:0;
var vy=(b&&a)?(b.y-a.y)/dt*16:0;
var speed=Math.sqrt(vx*vx+vy*vy);
if(speed>6){
var x=px,y=py;
function fly(){
x+=vx;y+=vy;vx*=.95;vy*=.95;
var op=Math.max(0,1-(Math.abs(x)+Math.abs(y))/260);
apply(x,y,op);
if(Math.abs(x)<300&&Math.abs(y)<220&&(Math.abs(vx)>.4||Math.abs(vy)>.4)){
raf=requestAnimationFrame(fly);
}else{
setTimeout(function(){
chip.style.transition='transform .4s cubic-bezier(.34,1.56,.64,1),opacity .3s';
px=0;py=0;apply(0,0,1);
setTimeout(function(){chip.style.transition='';},420);
},250);
}
}
raf=requestAnimationFrame(fly);
}else{
springBack();
}
}
chip.addEventListener('pointerup',end);
chip.addEventListener('pointercancel',end);
})();クラス名 .d08-15-10 は本ライブラリ内での識別用です。複数のパーツを同じページで使う場合は、重複しないよう名前を変更してください。