1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

はじめてのアドベントカレンダーAdvent Calendar 2023

Day 17

【React】シンプルなマウスストーカー(ポインター)を手軽に作成する

Posted at

背景

マウスを動かした際の演習として、マウスのカーソルを追従するようついてくるマウスストーカーがあります。
このマウスストーカーを効果的に使用する事で、よりリッチな表現をする事ができると思います。
本記事ではReactを使用し、3つの円を使ったシンプルなマウスストーカーのサンプルについて解説します。
以下のgif画像が完成形です。

mouse_st.gif

環境

  • vite:5.0
  • React:18.2.0

全体のコード

先に全体のコードとCSSを以下に記載します。

App.jsx
import { useEffect, useState } from "react";
import "./App.css";

const Pointer = ({ name, position }) => (
  <div
    className={`${name}`}
    style={{
      transform: `translate(${position.x}px, ${position.y}px)`,
    }}
  ></div>
);


function App() {
  // マウスの座標
  const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });

  useEffect(() => {
    const mouseMoveListener = (event) => {
      setMousePosition({ x: event.clientX, y: event.clientY });
    };

    // マウント時:マウスイベントリスナを追加
    window.addEventListener("mousemove", mouseMoveListener);

    // アンマウント時:マウスイベントリスナを削除
    return () => {
      window.removeEventListener("mousemove", mouseMoveListener);
    };
  }, []);

  return (
    <div className="App">
      <Pointer name="pointer is-small" position={mousePosition} />
      <Pointer name="pointer" position={mousePosition} />
      <Pointer name="pointer is-large" position={mousePosition} />
    </div>
  );
}

export default App;
App.css
App.css
body {
  padding: 0;
  margin: 0;
  background-color: aliceblue;
}

.pointer.large {
  width: 50px;
  height: 50px;
  top: -27px;
  left: -27px;
  background: rgba(0, 157, 255, 0);
  border: 2px solid rgba(0, 157, 255, 0.5);
  border-radius: 50%;
  transition: 0.5s cubic-bezier(0.075, 0.82, 0.165, 1);
}

.pointer {
  width: 40px;
  height: 40px;
  background: rgba(0, 157, 255, 0.75);
  position: fixed;
  top: -20px;
  left: -20px;
  border-radius: 50%;
  transition: 1s cubic-bezier(0.075, 0.82, 0.165, 1);
}

.pointer.small {
  width: 15px;
  height: 15px;
  top: -7.5px;
  left: -7.5px;
  background: rgba(0, 119, 255, 0.5);
  transition: 0.2s cubic-bezier(0.075, 0.82, 0.165, 1) transform;
}
main.jsx
main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)

コードの詳細

以下は、ポインターを生成するコンポーネントです。
今回は3つのPointerコンポーネントを作成するので共通した1つのPointerコンポーネントを作成しておきます。

const Pointer = ({ name, position }) => (
  <div
    className={`${name}`}
    style={{
      transform: `translate(${position.x}px, ${position.y}px)`,
    }}
  ></div>
);

Appコンポーネントでは、mousePositionというマウスの座標を示す状態変数を作成し、
初期値として { x: 0, y: 0 } を設定しています。

useEffectフックを使用し、マウント時にマウスの移動イベントリスナーを追加し、
アンマウントされたときにリスナーを削除しています。

function App() {
  const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });

  useEffect(() => {
    const mouseMoveListener = (event) => {
      setMousePosition({ x: event.clientX, y: event.clientY });
    };

    window.addEventListener("mousemove", mouseMoveListener);

    return () => {
      window.removeEventListener("mousemove", mouseMoveListener);
    };
  }, []);

最後にPointerコンポーネントを呼び出し、
異なる3つサイズのポインターを表示しています。

return (
  <div className="App">
    <Pointer name="pointer small" position={mousePosition} />
    <Pointer name="pointer" position={mousePosition} />
    <Pointer name="pointer large" position={mousePosition} />
  </div>
);

Pointerに当てているCSSは以下の通りです。

3つのPointerに当てているCSS

.pointer.large {
  width: 50px;
  height: 50px;
  top: -27px;
  left: -27px;
  background: rgba(0, 157, 255, 0);
  border: 2px solid rgba(0, 157, 255, 0.5);
  border-radius: 50%;
  transition: 0.5s cubic-bezier(0.075, 0.82, 0.165, 1);
}

.pointer {
  width: 40px;
  height: 40px;
  background: rgba(0, 157, 255, 0.75);
  position: fixed;
  top: -20px;
  left: -20px;
  border-radius: 50%;
  transition: 1s cubic-bezier(0.075, 0.82, 0.165, 1);
}

.pointer.small {
  width: 15px;
  height: 15px;
  top: -7.5px;
  left: -7.5px;
  background: rgba(0, 119, 255, 0.5);
  transition: 0.2s cubic-bezier(0.075, 0.82, 0.165, 1) transform;
}

Pointerが動く速度を調整する方法

今回は3つのPointerを作成しました。
3つとも同じスピードで動かすよりも、
それぞれのPointerが異なるスピードで動いた方が
マウスストーカーとしてはリッチに見えそうな気がします。
(個人の感想です。)

その場合は、以下のようにCSSのtransitionプロパティの秒数を変える事で、
マウスを追従するスピードを変化させる事ができます。

CSS
.pointer.large {
  transition: 0.5s cubic-bezier(0.075, 0.82, 0.165, 1);
}

.pointer {
  transition: 1s cubic-bezier(0.075, 0.82, 0.165, 1);
}

.pointer.small {
  transition: 0.2s cubic-bezier(0.075, 0.82, 0.165, 1) transform;
}

実行結果

以下のようにマウスの動きを追従するポインターを作成できました。
さらに大きさ、色、透過度等を調整する事でサイトにあったポインターを作成する事ができると思います。

mouse_st.gif

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?