カテゴリー
CSS HTML jQuery Webサイト作成 WordPress

マウスの進入・退出方向検出

こんにちは、エムケーワイです。無観客ですが、ようやくプロ野球が始まりましたね。

今回は、画像に対するマウスの進入方向および退出方向の検出にトライします。

そして、マウスが画像上に進入した方向からキャプションをスライドインさせ、退出した方向にキャプションをスライドアウトさせます。ここで、キャプションは画像の簡単な説明で、サイズは画像と同じ、背景色は半透明のトマト色です。

まずは結果から。下の画像上にマウスを色々な方向から侵入させたり、退出させたりしてみてください。

コーヒー豆と目覚まし時計

画像2

絵のような街角

画像3

山と湖

WordPressのカップケーキ

では、実現方法を説明して行きます。

目次 [閉じる]
  1. HTMLコード
  2. CSS設定
  3. jQueryコード

1. HTMLコード

今回はWordPressのブロックエディターで2列のカラムを2個縦に並べ、各カラムに画像とキャプションを配置しました。

ただ、キャプションのテキストを矩形領域の中央に表示できるようにするため、コードエディターでfigcaptionタグ内のテキストをpタグで囲むよう修正しました。

一つ目の2列カラムのHTMLコードのみ示しておきます。

<div class="wp-block-columns">
    <div class="wp-block-column">
        <div class="wp-block-image">
            <figure class="aligncenter size-large">
                <img src="https://mky-memo.com/..." (中略) >
                <figcaption>
                    <p>コーヒー豆と目覚まし時計</p>
                </figcaption>
            </figure>
        </div>
    <div class="wp-block-column">
        <div class="wp-block-image">
            <figure class="aligncenter size-large">
                <img src="https://mky-memo.com/..." (中略) >
                <figcaption>
                    <p>絵のような街角</p>
                </figcaption>
            </figure>
        </div>
    </div>
</div>

2. CSS設定

キャプションは初期状態では画像の領域外に配置し、非表示としています。

2-1. figure要素に対する設定

.wp-block-image figure {
    margin-top: 0;
    margin-bottom: 0;
    display: block !important;
    position: relative;
    overflow: hidden;	/* キャプションを非表示 */
}
  • 画像とキャプションのサイズを同じにするため、親要素であるfigure要素のサイズが画像サイズと同じになるよう、margin-top、margin-bottomを0にします。
  • displayはテーマで”table”が設定されているので、”block”に上書き変更します。
  • 子要素である画像とキャプションの位置を絶対指定できるよう”position: relative”とします。
  • キャプションを非表示にするため”overflow: hidden“とします。

2-2. figcaption要素に対する設定

.wp-block-image figure figcaption {
    margin-top: 0;
    padding: 10px;
    background-color: rgba(255, 99, 71, 0.8);
    color: rgb(255, 255, 255);
    /* 親要素と同じサイズに */
    width: 100%;
    height: 100%;
    /* 親要素の領域外に配置 */
    position: absolute;
    left: 100%;
    top: 100%;
}
  • margin-top、padding、背景色、文字色を設定しています。
  • 親要素(figure要素)と同じサイズにするために、”width: 100%”、”height: 100%”としています。
  • 位置を絶対指定とし、親要素の領域外(右下)に配置しています。初期状態では、figure要素の領域外の要素は表示されません。

2-3. figcaption要素内のp要素に対する設定

figcaption p {
    /* 親要素の縦横中央に配置 */
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translateX(-50%) translateY(-50%);
    font-weight: bold;
}
  • 位置を絶対指定できるよう”position: absolute”としています。
  • 位置を親要素(figcaption要素)の縦横中央に配置しています。topおよびleftの”50%”は親要素の幅、高さに対するパーセント値、transformの”-50%”は自身の幅、高さに対するパーセント値となります。このように設定することでp要素は親要素の縦横中央に配置されます。

3. jQueryコード

jQuery(function () {

    var _figure = jQuery('.wp-block-image figure');
	
    /* マウス進入・退出時の処理 */
    _figure.on('mouseenter mouseleave', function(event) {
        var _caption = jQuery(this).find('figcaption'),
            dir = getMouseInOutDir(event),
            target,
            posIn = {
                top: '0%',
                left: '0%'
            },
            posOut = (function () {
                switch (dir) {
                    case 0: return { top: '-100%', left: '0%' }; 
                            break;	// top
                    case 1: return { top: '0%', left: '100%' }; 
                            break;	// right
                    case 2: return { top: '100%', left: '0%' };    
                            break;	// bottom
                    default: return { top: '0%', left: '-100%' }; 
                             break;	// left
                }
            })();
            
        if (event.type === 'mouseenter') {
            target = posIn;
            _caption.css(posOut);
        } else {
            target = posOut;
        }
        _caption.stop(true).animate(target, 300, 'swing');
    });

    /* マウスの進入・退出方向を検出する */
    function getMouseInOutDir(event) {
        var _ele = jQuery(event.currentTarget),
            offset = _ele.offset(),
            w = _ele.outerWidth(),
            h = _ele.outerHeight(),
            /* 画像中心を原点として座標を求める */
            x = (event.pageX - offset.left - w / 2) * ((w > h)? h / w: 1),
            y = (event.pageY - offset.top - h / 2) * ((h > w)? w / h: 1),
            /* 角度を算出し、どの辺上にあるか判定する */
            deg = Math.atan2(y, x) * (180 / Math.PI);
            dir = Math.round((deg + 180) / 90  + 3) % 4;
            
        return dir;
    }
});

3-1. マウス進入・退出時の処理

まず、”mouseenter“、”mouseleave“イベントが発生した際の処理について説明します。

  1. 変数_captionには、イベントが発生したfigcaption要素を含むjQueryオブジェクトが代入されます。
  2. 変数dirには、関数getMouseInOutDir()の戻り値として、イベントが発生した辺を示す値が代入されます(0:上辺、1:右辺、2:底辺、3:左辺)。
  3. 変数targetには、アニメーションの最終状態を示すオブジェクトが代入されます。
  4. 変数posInには、キャプション表示時の位置(top、left)が代入されます。
  5. 変数posOutには、キャプション非表示時の位置(top、left)が代入されます。処理は即時関数として実行され、イベントが発生した辺に応じた位置が代入されます
  6. “mouseenter”イベントが発生した際は、targetにposInを代入します。また、キャプションの位置をposOutにします。これがアニメーション開始時のキャプションの位置となります。
  7. “mouseleave”イベントが発生した際は、targetにposOutを代入します。アニメーション開始時のキャプションの位置の設定は不要です。
  8. キャプションをスライドイン/スライドアウトさせるアニメーションを開始します。アニメーションの所要時間は300msです。

3-2. マウス進入・退出時方向の検出

次に、関数getMouseInOutDir()の処理について説明します。

  1. 変数_eleには、イベントが発生した要素を含むjQueryオブジェクトが代入されます。”event.currentTarget“でイベントが発生した要素を取得できます。
  2. 変数offsetには上記要素のhtml要素左上からのオフセット、変数w、hには上記要素の幅と高さが代入されます。
  3. 変数x、yには、イベント発生位置を画像の中心を原点とする座標系に変換した値が代入されます。このとき、後の処理を簡単にするため、画像の幅と高さが同じ(正方形)になるよう調整します。
  4. 3で算出した座標から逆正接(角度)を算出し、変数degに代入します。単位は度(degree)、範囲は-180度~180度です。このとき、Y座標の+/-が一般的な数学座標の逆になるので、符号を反転したくなりますが、そのままで進めます。理由は後述します。なお、atan2()は第1引数がY座標値、第2引数がX座標値となるので注意が必要です。
  5. 4で算出した角度から、イベントが画像のどの辺で発生したかを求め、変数dirに代入します。具体的には、角度に180を加算して正の値としてから90で除算し(※1)、結果を4で割った余りを求めています。この結果dirは、イベントが上辺で発生した場合は0、右辺で発生した場合は1、底辺で発生した場合は2、左辺で発生した場合は3となります。時計回りに数値が大きくなり、CSSのborderプロパティの設定順と整合が取れます。これが、4で符号を反転しなかった理由です(※2)。
  6. dirを返します。

(※1)3でXとYの座標の範囲が同じになっているので、角度を90で除算した結果でイベントがどの辺で発生したかが分かります(下図は画像が横長の場合の例です)。

逆正接
除算結果イベントが発生した辺
0.5 ~ 1.5上辺
1.5 ~ 2.5右辺
2.5 ~ 3.5底辺
0 ~ 0.5
3.5 ~ 4
左辺

(※2)4で符号を反転させると、dirの値が反時計回りに大きくなり、CSSのborderプロパティの設定順と整合が取れなくなります(下図参照)。必ずしも整合を取る必要はないと思いますが、時間が経ってから修正する場合や、他の人が修正することになった場合に、整合が取れていた方が理解しやすいのではないかと考えます。

逆正接 Y軸反転

いかがでしたでしょうか?

“mouseenter”、”mouseleave”イベントが発生した座標から、マウスの進入方向、退出方向を求める方法について説明しました。また、それを応用してマウス進入時はその方向からキャプションをスライドイン、退出時はその方向にキャプションをスライドアウトさせてみました。

今回も”overflow: hidden”を使いましたね。

数学的な要素もあり、Webサイト作成とは関係ないじゃないか、と思われた方がいるかもしれませんが、こういった通常のプログラミングの範疇の処理もjQueryでプログラミング可能です。

最後までお読みいただきありがとうございました。