smooth animation

Move an object while drawing a circle

by uto usui

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
<div class="target"></div>
<div class="ring"></div>

SCSS

body {
  position: relative;
  width: 100vw;
  height: 100vh;
  transform-style: preserve-3d;
  perspective: 500px;
  background-color: #E9EFFF;
}

.target {
  width: 50px;
  height: 50px;
  background-color: #25ECB7;
  transform-origin: 50% 50% 50%;
  border-radius: 100%;
}

.ring {
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(100vw / 2 - 50px * 2 - 10px);
  height: calc(100vw / 2 - 50px * 2 - 10px);
  border: 1px solid #898FB2;
  border-radius: 100%;
  transform: translate(-50%, -50%);
}

Babel + JSX

class smoothMove {

  /**
   *
   * @param target {Object}
   * @param speed {Number}
   * @param wrapWidth {Number}
   * @param wrapHeight {Number}
   */
  constructor(target, speed = 2, wrapWidth = window.innerWidth, wrapHeight = window.innerHeight) {

    this.target = target;

    // 角度
    this.angle = 0;
    // スピード
    this.speed = speed;

    // 中心の座標
    this.center = {
      x: wrapWidth / 2 - this.target.width() / 2,
      y: wrapHeight / 2 - this.target.height() / 2
    };

    // 動く範囲を円の半径で表現
    // この倍の値(直径)が移動範囲になる
    this.radius = window.innerHeight / 4;

    return this;

  }

  /**
   * ラジアンに変換する
   * @param angle
   * @returns {number}
   */
  getRadian(angle) {

    return angle * Math.PI / 180;

  }

  /**
   * アニメーションを始める
   */
  play() {

    let radian = this.getRadian(this.angle);

    // Math.sin(radian)は-1から1までを正弦波で返す
    // radiusをかけることでそれを半径とする円の範囲でアニメーション
    let offsetX = Math.sin(radian) * this.radius;
    let offsetY = Math.cos(radian) * this.radius;


    TweenMax.set(this.target, {
      x: this.center.x + offsetX,
      y: this.center.y + offsetY,
    });

    // アニメーションで使用する角度を進める量
    // つまり、速度
    this.angle += this.speed;

    requestAnimationFrame(() => {

      this.play();

    });

  }

}

let anim = new smoothMove($('.target'));
anim.play();