🐙

マウスにくっつくボタンのやつ

2023/01/16に公開

こんなやつ

いろんなサイトでよく見るようになったマウスにくっついてくるボタンのやつです。(正式名称はあるのかしら)
触ってて気持ちいいので、個人的に好きな実装のひとつです。

クラス

class StickBtn {
   constructor(target, easeMove, fps) {
      this.mouseX = 0;
      this.mouseY = 0;
      this.targetOffsetX = 0;
      this.targetOffsetY = 0;
      this.easeMove = easeMove;
      this.limitFrames = new LimitFrameRate(fps);

      this.target = target;
      this.id = null;

      this.stickAnimLoop = function (timestamp) {
         if (this.limitFrames.isLimitFrames(timestamp)) {
            this.start();
            return;
         }
         console.log('tick');
         let xTo = gsap.quickTo(this.target, 'x', {
               duration: durationVal,
               ease: 'power1.out',
            }),
            yTo = gsap.quickTo(this.target, 'y', {
               duration: durationVal,
               ease: 'power1.out',
            });
         xTo(this.mouseX * this.easeMove);
         yTo(this.mouseY * this.easeMove);
         this.start();
      };

      this.start = function () {
         this.id = requestAnimationFrame(this.stickAnimLoop.bind(this));
      };
      this.stop = function () {
         cancelAnimationFrame(this.id);
         gsap.to(this.target, {
            x: 0,
            y: 0,
            duration: durationVal,
            ease: 'back.out(4)',
            overwrite: true,
         });
      };
      this.mouseEnter = function (e) {
         e.stopPropagation();
         this.targetOffsetX = e.target.clientWidth / 2;
         this.targetOffsetY = e.target.clientHeight / 2;
         this.start();
      };
      this.mouseEnterInit = this.mouseEnter.bind(this);
      this.mouseMove = function (e) {
         e.stopPropagation();
         this.mouseX = e.offsetX - this.targetOffsetX;
         this.mouseY = e.offsetY - this.targetOffsetY;
      };
      this.mouseMoveInit = this.mouseMove.bind(this);
      this.mouseOut = function (e) {
         e.stopPropagation();
         this.mouseX = 0;
         this.mouseY = 0;
         this.stop();
      };
      this.mouseOutInit = this.mouseOut.bind(this);
   }

   //登録メソッド
   add() {
      if (!isTouch()) {
         this.target.addEventListener('mouseenter', this.mouseEnterInit);
         this.target.addEventListener('mousemove', this.mouseMoveInit);
         this.target.addEventListener('mouseleave', this.mouseOutInit);
      } else {
         return;
      }
   }
   //解除メソッド
   remove() {
      this.target.removeEventListener('mouseenter', this.mouseEnterInit);
      this.target.removeEventListener('mousemove', this.mouseMoveInit);
      this.target.removeEventListener('mouseleave', this.mouseOutInit);
   }
}
  • gsap.quickToでパフォーマンス改善してる、、はず。toでも違いはわからなかったのですがquickToの公式でマウスフォロワーの例があったので、たぶん正しい使い方のはず。
    https://greensock.com/docs/v3/GSAP/gsap.quickTo()
  • 登録と解除メソッドを用意してるのはpjax遷移させる時にdomを入れ替えないパーツにも適用させるために、適宜removeしたかったからです。
  • rAF制御も入れてますが、今回の場合はスマホで発火させないので、FPSの調整はあまり意味がないです
  • 解除する時にease: 'back.out(num)',にすると慣性っぽくなってスキです

Discussion