sticky-button

by miyabi_irokoto

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/gsap.min.js"></script>
<!DOCTYPE html>
<html lang="ja"></html>
<head>
  <meta charset="UTF-8"/>
  <title></title>
  <link rel="stylesheet" href="./assets/css/style.css"/>
</head>
<body>
  <div class="container">
    <div class="sticky"></div>
  </div>
</body>

CSS

body { 
  margin: 0;
}
.container{
  width: 100vw;
  height: 100vh;
  position: relative;
  background: #f7f7f7;
}
.sticky{
  width: 100px;
  height: 100px;
  margin: auto;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background: #000;
  border-radius: 50%;
  box-shadow: 0 0 5px rgba(0,0,0,.8);
}

JavaScript

class sticky {
  constructor(target){
    
    this.gbcr = target.getBoundingClientRect();
    
    this.el = {
      target: target,
      x: this.gbcr.x,
      y: this.gbcr.y,
      w: this.gbcr.width,
      h: this.gbcr.height,
    }

    this.attraction = 20;

    this.mouse = {
      x: 0,
      y: 0,
      cx: 0,
      cy: 0
    }

    this.frag = false;

    this.el.target.addEventListener('mouseenter', () => { this.mouseEnter() });
    this.el.target.addEventListener('mouseleave', () => { this.mouseLeave() });
    this.bindMouseMove = this.mouseMove.bind(this);
    this.onRequestAnimationFrame();
  }

  mouseMove(e) {
    this.mouse.x = gsap.utils.mapRange(this.el.x, this.el.x + this.el.w, -this.attraction, this.attraction, e.clientX);
    this.mouse.y = gsap.utils.mapRange(this.el.y, this.el.y + this.el.h, -this.attraction, this.attraction, e.clientY);
  }

  mouseEnter() {
    this.frag = true;
    addEventListener('mousemove',this.bindMouseMove);
  }

  mouseLeave() {
    this.frag = false;
    this.mouse.cx = 0;
    this.mouse.cy = 0;
    gsap.to(this.el.target, {
      x: 0,
      y: 0,
      duration: .3,
      ease: 'elastic.out(1, 0.5)'
    });
    removeEventListener('mousemove',this.bindMouseMove);
  }

  onRequestAnimationFrame() {
    if(this.frag){
      this.mouse.cx = gsap.utils.interpolate(this.mouse.cx, this.mouse.x, 0.1);
      this.mouse.cy = gsap.utils.interpolate(this.mouse.cy, this.mouse.y, 0.1);
      gsap.set(this.el.target, {
        x: this.mouse.cx,
        y: this.mouse.cy
      });
    }
    
    requestAnimationFrame(() => { this.onRequestAnimationFrame() });
  }
}

new sticky(document.querySelector('.sticky'));