JavaScriptを使ってマウスポインターにプレビューを表示する

# はじめに
Webページの特定のオブジェクト(テーブルのセルなど)にマウスポインターを置いた場合、そのオブジェクトと紐づいている情報を用いて、マウスポインターの横に何かのプレビューを表示する方法を紹介します。
表示されるプレビューは、マウスポインターの位置を追いかけていきます。

## プレビュー表示の例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1184971/704798ce-2a7a-2327-ebc8-421d2fb2f383.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1184971/9581d76c-ede9-089c-4e3b-1e44cfad440e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1184971/6cf23a1f-8fdd-f107-6275-de0e40ff1d6a.png)


# プレビュー表示のサンプルコード
例として作成したサンプルコードは、HTML、JavaScript、CSSの3つのファイルで構成されます。
Webページサンプルには、1つのテーブルに3つのセルがあり、各セルにマウスポインターを置くと、マウスポインターの位置に合わせてプレビューが表示されます。
JavaScriptコードには「jQuery」ライブラリーを使いました。


## サンプルのフォルダ構成
サンプルコードや画像ファイルは以下のように構成されています。
```:フォルダ構成
sample
  ├─ index.html
  ├─ script.js
  ├─ style.css
  └─ img
      ├─ bg1.jpg
      ├─ bg2.jpg
      └─ bg2.jpg
```

## HTMLコードサンプル
HTMLコードは、以下のように作成しました。
各セルには、画像表示で使う情報(img_src、img_description)が入っています。
```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link rel="stylesheet" href="style.css" />
    <title>Preview</title>
  </head>

  <body>
    <!-- 表を作成する -->
    <table id="image-table" border="1">
      <tbody>
        <tr>
          <td width="100" img_src="bg1.jpg" img_description="お花畑">背景 1</td>
        </tr>
        <tr>
          <td width="100" img_src="bg2.jpg" img_description="海">背景 2</td>
        </tr>
        <tr>
          <td width="100" img_src="bg3.jpg" img_description="夜景">背景 3</td>
        </tr>
      </tbody>
    </table>

    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    <script src="script.js"></script>
  </body>
</html>
```

## JavaScriptコードサンプル
JavaScriptコードは以下のように作成しました。
マウスポインターが以下の動作のコードが作成されています。
- マウスポインターがセルに位置した場合、プレビューを表示
- マウスポインターがセルに位置しない場合、プレビューを非表示
- マウスポインターの位置に合わせてプレビューを移動

```javascript:script.js
$().ready(function () {
  imgPreview(this);
});

function imgPreview() {
  var xOffset = 10;
  var yOffset = 20;
  var imgWidth = 320;
  var imgHeight = 180;

  // マウスポインターが位置しているセルに該当する画像のプレビューを表示する
  $("#image-table td").hover(
    function (e) {
      var imgId = $(this).closest("td").attr("img_src");
      var imgValue = $(this).closest("td").attr("img_description");

      $("body").append(
        `<p id="preview"><img src="./img/${imgId}" width="${imgWidth}" height="${imgHeight}"><br>${imgValue}</p>`
      );
      $("#preview")
        .css("top", e.pageY - xOffset + "px")
        .css("left", e.pageX + yOffset + "px")
        .fadeIn("fast");
    },
    // マウスポインターがセルに位置しないと、プレビューを非表示する
    function () {
      $("#preview").remove();
    }
  );

  // マウスポインターの位置に合わせてプレビューを表示を移動する
  $("#image-table td").mousemove(function (e) {
    var previewWidth = $("#preview").width();
    var previewHeight = $("#preview").height();

    if (e.pageY + previewHeight > $(window).innerHeight() + $(document).scrollTop()) {
      $("#preview").css("top", e.pageY - xOffset - previewHeight + "px");
    } else {
      $("#preview").css("top", e.pageY - xOffset + "px");
    }

    if (e.pageX + previewWidth > $(window).innerWidth() + $(document).scrollLeft()) {
      $("#preview").css("left", e.pageX - yOffset - previewWidth + "px");
    } else {
      $("#preview").css("left", e.pageX + yOffset + "px");
    }

    if (
      e.pageY + previewHeight > $(window).innerHeight() + $(document).scrollTop() &&
      e.pageX + previewWidth > $(window).innerWidth() + $(document).scrollLeft()
    ) {
      $("#preview")
        .css("top", e.pageY - xOffset - previewHeight - xOffset + "px")
        .css("left", e.pageX - yOffset - previewWidth + "px");
    }
  });
}
```

## CSSコードサンプル
CSSファイルは以下のように作成しました。
プレビューのスタイルのみ作成しました。
```css:style.css
#preview {
    position: absolute;
    border: 1px solid #ccc;
    background: #333;
    padding: 5px;
    display: none;
    color: #fff;
    z-index: 100;
  }
```