ドラッグ(慣性・バウンド)

物理シミュレーションの有無と精度・慣性アルゴリズムの実装差を主要ライブラリで比較

💻 PC でご覧の方へ:3 つとも PC マウスに対応。フリック(素早くドラッグして離す)で慣性・バウンドの物理挙動が確認できます。
Framer Motion

読み込み中...

tsx
'use client';
import { motion } from 'framer-motion';

export function FramerDragDemo() {
  return (
    <div className="relative h-64 bg-gray-100 rounded-lg overflow-hidden flex items-center justify-center">
      <motion.div
        drag
        dragConstraints={{ left: -100, right: 100, top: -80, bottom: 80 }}
        dragElastic={0.2}
        dragTransition={{ bounceStiffness: 300, bounceDamping: 20 }}
        whileDrag={{ scale: 1.1 }}
        className="w-16 h-16 bg-rose-500 rounded-xl cursor-grab active:cursor-grabbing flex items-center justify-center text-white font-bold"
      >
        ドラッグ
      </motion.div>
    </div>
  );
}

物理シミュレーション比較表

項目Framer Motion@use-gesture/reactPointer Events API
慣性(フリック後)dragTransition で自動(power・timeConstant)velocity 取得 → 自前 RAF 実装Δpos/Δt 速度 → 完全自前 RAF 実装
減衰モデル内部 Spring 物理(timeConstant で時定数制御)v *= DAMPING(指数関数的・手実装)v *= DAMPING(指数関数的・手実装)
バウンド実装bounceStiffness / bounceDamping(Spring 物理)v = -v × RESTITUTION(手実装)v = -v × RESTITUTION(手実装)
壁の弾性dragElastic 係数(0 = 固定 / 1 = 完全弾性)rubberband オプション(距離 → スケール変換)実装次第(本デモは即座停止)
速度取得精度useVelocity(MotionValue を時間微分・リアルタイム)EMA フィルタ済み velocity(use-gesture が平滑化)生 Δpos/Δt(手動 LPF 実装が必要)
物理パラメータ可視性4パラメータ(power / timeConst / bounce×2)DAMPING・RESTITUTION を自分で定義完全自由(物理方程式を直接記述)
実装コスト低:設定のみ・物理コード不要中:速度取得は楽・慣性は手実装高:速度計算・LPF・慣性・バウンド全手実装

物理シミュレーションの精度と制御

Framer Motion — Spring 物理エンジン内蔵

慣性は power × velocity × timeConstant で目標位置を計算し、バウンドは bounceStiffness / bounceDamping の Spring で制御。物理方程式を一切書かずに自然な挙動が得られる。useVelocity で慣性フェーズ中もリアルタイムに速度を取得できる点が強力。

@use-gesture/react — 速度取得のみ担当

velocity は EMA で平滑化済みの高精度値を提供するが、慣性・バウンドの物理ループは開発者が実装する。v *= DAMPING の減衰定数を直接制御できるため、ゲーム的な強いバウンドや摩擦感のある動きなど、物理感覚を細かく調整したい場合に適する。

Pointer Events API — 物理方程式の直接記述

速度は Δpos / Δt の生値のため LPF(ローパスフィルタ)の手実装が必要。フリック終了直前の指の動きが止まっている場合、速度がほぼ 0 になり慣性が発生しないことがある。EMA weight・DAMPING・RESTITUTION のすべてを直接制御できる代わりに、実装コストと品質維持の責任が開発者側に全面的にかかる。

⚠️ iOS Safari での注意点

  • • ドラッグ要素に touch-action: none が必須(ページスクロールとの競合回避)
  • • Framer の motion コンポーネントは内部で自動付与。use-gesture・Vanilla は手動指定が必要
  • • Vanilla 実装では setPointerCapture でポインタをキャプチャしないと、指が要素外に出た瞬間にドラッグが途切れる
  • pointercancel イベントを必ず処理しておかないと、電話着信などシステム割り込み時に慣性が永久ループする可能性がある
  • • iOS の scroll-snapoverscroll-behavior が干渉する場合は、祖先要素の CSS を確認する

🤖 AIプロンプトテンプレート

Reactでドラッグ(慣性・バウンド付き)を実装してください。以下の要件を満たしてください。

- Framer Motion、@use-gesture/react、またはPointer Events APIのいずれかを使用すること
- マウスとタッチの両方でドラッグ操作ができること
- フリック(素早くドラッグして離す)で慣性アニメーションが発生すること
- 境界(コンテナ枠)でバウンス(弾性反発)するアニメーションを実装すること
- dragElasticまたは同等のゴム引き効果(境界外での抵抗感)を実装すること
- iOS Safariでtouch-action: noneを適切に設定し、ページスクロールとの競合を避けること

⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。