マウスチェイサー

  • Updated: 2024.01.14
  • Published: 2022.12.29
  • 489views

概要

マウスの動きに追随する、マウスチェイサー(英語にしただけ^^)を実装します。
マウスに近づくにつれてゆっくり動くようにするのと、リンクにマウスオーバーで変形するようにもします。


ソース

if ( !window.mp ) {
  window.mp = (e)=>{ // マウスの座標取得
    let posX,posY;
    if(e.changedTouches){
      posX = e.changedTouches[0].clientX;
      posY = e.changedTouches[0].clientY;
    }else if(e.clientX){
      posX = e.clientX;
      posY = e.clientY;
    }else{
      posX = e.pageX;
      posY = e.pageY;
    }
    return {
      x: posX,
      y: posY
    }
  }
}

function setMouseChaser(){
  if('ontouchstart' in window) return false;

  let pos = { x: -100, y: -100 };
  let arv = { x: 0, y: 0 };

  let $body = document.getElementsByTagName('body')[0];
  let $mc = document.createElement('div');
  let $inner = document.createElement('div'); 

  $mc.classList.add('MouseChaser');

  $mc.appendChild($inner);
  $body.appendChild($mc);

  window.addEventListener('mousemove',(e)=>{
    arv = mp(e);
  },false);

  window.addEventListener('mouseover',(e)=>{
    let $target = e.target.closest('a');
    let tagName = ($target !== null) ? $target.tagName.toLowerCase() : null;

    if(tagName !== null) {
      $mc.classList.add('hover');
    }
  },false);

  window.addEventListener('mouseout',(e)=>{
    let $target = e.target.closest('a');
    let tagName = ($target !== null) ? $target.tagName.toLowerCase() : null;

    if(tagName !== null) {
      $mc.classList.remove('hover');
    }
  },false);
  
  function animate() {
    pos.x += (arv.x - pos.x)/5;
    pos.y += (arv.y - pos.y)/5;
    $mc.style.left = `${ pos.x }px`;
    $mc.style.top = `${ pos.y }px`;
    requestAnimationFrame(animate);
  }
  animate();
}

setMouseChaser();
.MouseChaser {
    z-index: 10000;
    position: fixed;
    pointer-events: none;
}
.MouseChaser div {
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
    -webkit-transition: all 500ms cubic-bezier(0.165, 0.84, 0.44, 1);
    transition: all 500ms cubic-bezier(0.165, 0.84, 0.44, 1);
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background-color: #000;
}
.MouseChaser.hover div {
    width: 100px;
    height: 100px;
}

解説

if ( !window.mp ) {
  window.mp = (e)=>{ // マウスの座標取得
    let posX,posY;
    if(e.changedTouches){
      posX = e.changedTouches[0].clientX;
      posY = e.changedTouches[0].clientY;
    }else if(e.clientX){
      posX = e.clientX;
      posY = e.clientY;
    }else{
      posX = e.pageX;
      posY = e.pageY;
    }
    return {
      x: posX,
      y: posY
    }
  }
}

mp関数はマウスの座標を取得する関数です。
window.mpにしているのはグローバルな関数にしたかったのでそうしています。
この辺りは好みの問題なのでローカル関数にしていただいてもOKです。


if('ontouchstart' in window) return false;

デバイスがタッチイベントに対応している場合はマウスチェイサーを動かないようにしています。


  let pos = { x: -100, y: -100 };
  let arv = { x: 0, y: 0 };

デフォルトの値を設定しています。posはマウスチェイサーの座標、arvは移動目標座標(マウスの座標)になります。


  let $body = document.getElementsByTagName('body')[0];
  let $mc = document.createElement('div');
  let $inner = document.createElement('div'); 

  $mc.classList.add('MouseChaser');

  $mc.appendChild($inner);
  $body.appendChild($mc);

マウスチェイサー用の要素を生成しています。HTMLに直接コーディングで挿入しても良いですが、タッチデバイスでは動かさないようにしているので、JavaScriptで生成しています。


  window.addEventListener('mousemove',(e)=>{
    arv = mp(e);
  },false);

マウスの移動でマウス座標を取得します。取得には先ほどのmp関数を使用します。


  window.addEventListener('mouseover',(e)=>{
    let $target = e.target.closest('a');
    let tagName = ($target !== null) ? $target.tagName.toLowerCase() : null;

    if(tagName !== null) {
      $mc.classList.add('hover');
    }
  },false);

  window.addEventListener('mouseout',(e)=>{
    let $target = e.target.closest('a');
    let tagName = ($target !== null) ? $target.tagName.toLowerCase() : null;

    if(tagName !== null) {
      $mc.classList.remove('hover');
    }
  },false);

マウスオーバー、マウスアウトでクラス(hover)の付け替えをしています。
マウスオーバーされた要素の親要素にaタグがある場合のみしています。 


  function animate() {
    pos.x += (arv.x - pos.x)/5;
    pos.y += (arv.y - pos.y)/5;
    $mc.style.left = `${ pos.x }px`;
    $mc.style.top = `${ pos.y }px`;
    requestAnimationFrame(animate);
  }
  animate();

アニメーションはrequestAnimationFrameで行っています。

pos.x += (arv.x - pos.x)/5;

数式 現在座標+=(目標座標-現在座標)/移動数値 でマウスに移動するようにしています。
移動数値は5にしているので、一回のループでマウスと要素の間を1/5縮める処理になります。
なので、マウスと要素距離が小さくなると移動量も小さくなるのでマウスに近づくほどゆっくりになります。
移動数値を小さくすれば要素の動きは早く、大きくすればゆっくり移動させることができます。


.MouseChaser div {
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
    -webkit-transition: all 500ms cubic-bezier(0.165, 0.84, 0.44, 1);
    transition: all 500ms cubic-bezier(0.165, 0.84, 0.44, 1);
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background-color: #000;
}
.MouseChaser.hover div {
    width: 100px;
    height: 100px;
}

ホバーのアニメーションはCSSアニメーションで設定しています。
transitionを設定しておいて、hoverクラスが追加された時に横幅、高さを変更しています。

関連記事

人気の投稿

最新の投稿

タグ

月別アーカイブ