tag:crieit.net,2005:https://crieit.net/tags/%E3%83%9E%E3%82%A6%E3%82%B9%E3%82%B9%E3%83%88%E3%83%BC%E3%82%AB%E3%83%BC/feed 「マウスストーカー」の記事 - Crieit Crieitでタグ「マウスストーカー」に投稿された最近の記事 2020-12-14T21:10:33+09:00 https://crieit.net/tags/%E3%83%9E%E3%82%A6%E3%82%B9%E3%82%B9%E3%83%88%E3%83%BC%E3%82%AB%E3%83%BC/feed tag:crieit.net,2005:PublicArticle/16363 2020-12-14T21:10:33+09:00 2020-12-14T21:10:33+09:00 https://crieit.net/posts/mouse-stalker-sample-20201214 カーソルを特定要素にホバーすると画像を表示するマウスストーカーのサンプル <p>マウスストーカーが盛んに取り上げられるようになって早数年。さすがにそろそろやり方くらいは……と思い、試してみることにしました。</p> <h2 id="コード"><a href="#%E3%82%B3%E3%83%BC%E3%83%89">コード</a></h2> <p>まずは成果物を。</p> <ul> <li>要素ホバーで拡大: <a target="_blank" rel="nofollow noopener" href="http://scrunchy56.starfree.jp/vampire_stoker_first/">Home - Vampire Stoker</a></li> <li>要素ホバーで背景画像表示: <a target="_blank" rel="nofollow noopener" href="http://scrunchy56.starfree.jp/vampire_stoker_last/">Home - Vampire Stoker</a></li> </ul> <p>最初の方(要素ホバーで拡大)は参考コードほぼそのままです。次のものはマウスストーカーが大きくなるだけでなく、背景画像をスポットライト的に切り抜いて表示する機能も付けたものになります。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/arm-band/test_vampire_stoker">arm-band/test_vampire_stoker</a></li> </ul> <p>リポジトリ。</p> <h3 id="HTML"><a href="#HTML">HTML</a></h3> <pre><code class="html"><div class="c-mouseStalker_wrapper"> <div class="c-mouseStalker"> <div class="c-mouseStalker_cursor" id="c-mouseStalker_cursor"></div> <div class="c-mouseStalker_delay" id="c-mouseStalker_delay"></div> </div> </div> </code></pre> <p>HTMLはいたってシンプル。カーソル用の要素とディレイがかかって追いかけてくる要素の2つの <code>div</code> を用意します。</p> <p>今回はさらにラッパーで覆って <code>overflow: hidden;</code> をかけることで、画面端にカーソルが移動した際にディレイ要素の大きさ分だけはみ出てスクロールバーが表示されないようにしました。</p> <pre><code class="html"><script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js" defer></script> </code></pre> <p>それから、今回はサクッと試すために CDN で TweenMax を読み込むようにしました。</p> <h3 id="css(Scss)"><a href="#css%28Scss%29">css(Scss)</a></h3> <pre><code class="scss">body { position: relative; // 元々のマウスカーソルを消す cursor: none; } .c-mouseStalker { // イベント反応させなくする pointer-events: none; width: 100%; height: 100%; position: absolute; top: 0; left: 0; &_wrapper { // イベント反応させなくする pointer-events: none; width: 100%; height: 100%; position: absolute; top: 0; left: 0; // 端にカーソルを持って行ったときにディレイの部分だけはみ出てスクロールバーが表示されてしまうのを抑止 overflow: hidden; } &_cursor, &_delay { position: absolute; top: 0; left: 0; pointer-events: none; // イベント反応させなくする } &_cursor { width: 0.5rem; height: 0.5rem; background-color: f.$color; z-index: 10001; border-radius: 50%; } &_delay { $delayRadius: 100px / 4; width: 100%; height: 100%; background-color: f.$main-color; z-index: 10000; transition: clip-path ease 0.1s; // 遅くするともっさりした感じになる opacity: 0.4; // at 以降は円の中心の定義 clip-path: ellipse($delayRadius $delayRadius at 50% 50%); &.active { $activeTimes: 4; background: { image: url("../img/img.jpg"); attachment: fixed; size: cover; position: center center; } opacity: 1; clip-path: ellipse($delayRadius * $activeTimes $delayRadius * $activeTimes at 50% 50%); } } } </code></pre> <ul> <li><code>body</code> の <code>cursor: none;</code>: デフォルトのマウスカーソルを非表示に</li> <li><code>.c-mouseStalker</code> と <code>.c-mouseStalker_wrapper</code>: <ul> <li><code>pointer-events: none;</code></li> <li>どちらも表示画面サイズいっぱいまで拡大</li> </ul></li> <li><code>.c-mouseStalker_wrapper</code>: <code>overflow: hidden;</code> で端にカーソルを持って行ったときにディレイの部分だけはみ出てスクロールバーが表示されてしまうのを抑止</li> <li><code>.c-mouseStalker_delay</code>: 肝 <ul> <li>要素自体は透明。 <code>clip-path</code> で切り取った円形の範囲のみ見える状態にする <ul> <li>デフォルトは単色半透明のマスク</li> <li>特定要素にホバーしたとき、 jQuery でクラス付与 (ホバー解除時にクラスも削除) <ul> <li>クラスが付与されたとき、背景を単色から <code>background-image</code> で指定した画像にする <ul> <li>背景画像は <code>background-attachment</code>, <code>background-size</code>, <code>background-position</code> 指定あり</li> </ul></li> </ul></li> </ul></li> <li><code>transition: clip-path ease 0.1s;</code> でホバー時の拡大縮小等の切り替えを easing <ul> <li><code>0.3s</code> にすると TweenMax のディレイも相まってもっさりした動きになってしまうので、 <code>0.1s</code> で</li> </ul></li> </ul></li> </ul> <h3 id="JavaScript (jQuery + TweenMax)"><a href="#JavaScript+%28jQuery+%2B+TweenMax%29">JavaScript (jQuery + TweenMax)</a></h3> <pre><code class="javascript">// mouse stalker const mouseStalker = () => { const $cursor = $('#c-mouseStalker_cursor'); const $delay = $('#c-mouseStalker_delay'); const paramsArray = { cursor: { width: $cursor.outerWidth(), coorX: 0, coorY: 0, delay: 0.001, }, delay: { width: $delay.outerWidth(), coorX: 0, coorY: 0, delay: 6, }, }; const activeClass = 'active'; let clipRadius = 100 / 4; let clipScale = 1; let clipPathCoor = `ellipse(${clipRadius * clipScale}px ${clipRadius * clipScale}px at 50% 50%)`; // カーソルの遅延アニメーション // ほんの少しだけ遅延させる (0.001秒) TweenMax.to( {}, paramsArray.cursor.delay, { repeat: -1, onRepeat: function() { paramsArray.delay.coorX += (paramsArray.cursor.coorX - paramsArray.delay.coorX) / paramsArray.delay.delay; paramsArray.delay.coorY += (paramsArray.cursor.coorY - paramsArray.delay.coorY) / paramsArray.delay.delay; clipPathCoor = `ellipse(${clipRadius * clipScale}px ${clipRadius * clipScale}px at ${paramsArray.delay.coorX}px ${paramsArray.delay.coorY}px)`; // delay TweenMax.set( $delay, { css: { clipPath: clipPathCoor, } } ); // cursor TweenMax.set( $cursor, { css: { left: paramsArray.cursor.coorX - (paramsArray.cursor.width / 2), top: paramsArray.cursor.coorY - (paramsArray.cursor.width / 2), } } ); } } ); // mouse hover $('#hoverElmID').on({ mouseenter: function () { $cursor.addClass(activeClass); $delay.addClass(activeClass); clipScale = 4; }, mouseleave: function () { $cursor.removeClass(activeClass); $delay.removeClass(activeClass); clipScale = 1; }, }); // get mouse coordinate $(document).on('mousemove', function (e) { paramsArray.cursor.coorX = e.pageX; paramsArray.cursor.coorY = e.pageY; }); }; window.addEventListener('load', () => { mouseStalker(); }); </code></pre> <ul> <li>だいたいサンプルコードに則ったコード</li> <li>カーソルとディレイ要素の各種パラメータは別の変数で持っていると個人的に分かりづらかったのでオブジェクトにまとめました</li> <li>変数 <code>clipPathCoor</code> で指定した値が実際の <code>clip-path</code> で切り取られるディレイ要素の指定 <ul> <li>カーソル用はほぼ弄らず</li> <li>ディレイ要素の方は TweenMax の <code>to</code> で指定するパラメータが <code>top</code>, <code>left</code> から <code>clip-path</code> のみに変更</li> </ul></li> <li>特定要素のホバー時に上述 Scss の指定が反映されるようにクラスの付け外しを実施 <ul> <li>同時に <code>clip-path</code> で切り取られる範囲を拡大縮小(拡大率の数値を変更している)</li> </ul></li> </ul> <hr /> <p>今回はこれで望んだ挙動になりました。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <h3 id="マウスストーカー"><a href="#%E3%83%9E%E3%82%A6%E3%82%B9%E3%82%B9%E3%83%88%E3%83%BC%E3%82%AB%E3%83%BC">マウスストーカー</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://www.evoworx.co.jp/blog/mouse-stoker-gsap/">イケてるマウスカーソルを簡単に実装する | 株式会社 エヴォワークス -EVOWORX-</a></li> <li><a target="_blank" rel="nofollow noopener" href="http://un-tech.jp/tweenmax-started/">Googleも推奨!アニメーションライブラリTweenMaxの使い方 入門編 | un-Tech</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://greensock.com/licensing/">Licensing - GreenSock</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://greensock.com/standard-license/">Standard License - GreenSock</a></li> </ul> <h3 id="背景画像切り抜き"><a href="#%E8%83%8C%E6%99%AF%E7%94%BB%E5%83%8F%E5%88%87%E3%82%8A%E6%8A%9C%E3%81%8D">背景画像切り抜き</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://teratail.com/questions/246261">JavaScript - マウスストーカーを透明のマスクにして背景を動的に切り取りたいのですが、どうすれば良いでしょうか?|teratail</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/CSS/basic-shape"> - CSS: カスケーディングスタイルシート | MDN</a></li> <li><a target="_blank" rel="nofollow noopener" href="http://www.htmq.com/css/clip-path.shtml">clip-path-CSSリファレンス</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/duka/items/e65354f103ebc9280959">CSS animation で遊び倒す - CSS Clip Path- - Qiita</a></li> </ul> <h3 id="要素内座標(未使用)"><a href="#%E8%A6%81%E7%B4%A0%E5%86%85%E5%BA%A7%E6%A8%99%28%E6%9C%AA%E4%BD%BF%E7%94%A8%29">要素内座標(未使用)</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://muumv.com/grid/">要素内のマウスカーソルの座標を取得する!スマホ対応【Javascript】 | MUUMV</a></li> </ul> arm-band