あひるガアガアのタイトルロゴ

ルーペで画像の一部を拡大するJavaScript

2025年2月11日

画像の一部をルーペで拡大表示するJavaScriptです。
画像の上にマウスカーソルを乗せるとルーペが表示され、カーソル付近を拡大できます。

スマホでは、タッチ&ドラッグでルーペを操作できます。
まあ、スマホならピンチアウトで拡大できますが、「ルーペ風の演出ができる」ということでお付き合いください。

サンプル画像として、有名な錯視「ヘルマン格子」の画像を用意しました。
格子の交差点に灰色の丸い影のようなものが見えますが、ルーペで拡大すると、実際にはそのような模様が描かれていないことがよく分かります。

ヘルマン格子

コード

<!-- 全体を囲むコンテナに touch-action: none を追加して、操作中の意図しないスクロールを防止 --> <div style="display: block; text-align: center; cursor: crosshair; touch-action: none;"> <!-- 画像とルーペをひとまとめにするインライン要素 --> <span style="position: relative; display: inline-block;"> <!-- メイン画像 --> <img id="target-img" src="画像のURL" alt="画像の説明" style="display: block; width: 100%; max-width: 600px; height: auto;"> <!-- ルーペ本体 --> <div id="glass" style="position: absolute; border: 3px solid #fff; border-radius: 50%; width: 150px; height: 150px; display: none; pointer-events: none; box-shadow: 0 0 15px rgba(0,0,0,0.5); background-repeat: no-repeat; background-image: url('画像のURL'); z-index: 100;"> </div> </span> </div> <script> (function () { const img = document.getElementById('target-img'); const glass = document.getElementById('glass'); const zoom = 2; // 拡大倍率 img.addEventListener('mousemove', moveMagnifier); img.addEventListener('touchstart', moveMagnifier, { passive: false }); img.addEventListener('touchmove', moveMagnifier, { passive: false }); img.addEventListener('mouseleave', hideGlass); img.addEventListener('touchend', hideGlass); function hideGlass() { glass.style.display = 'none'; } function moveMagnifier(e) { // デフォルトのスクロール動作などを防止 if (e.cancelable) e.preventDefault(); glass.style.display = 'block'; const rect = img.getBoundingClientRect(); let x, y; // タッチかマウスかで座標取得を分岐 if (e.touches && e.touches[0]) { x = e.touches[0].clientX - rect.left; y = e.touches[0].clientY - rect.top; } else { x = e.clientX - rect.left; y = e.clientY - rect.top; } // 範囲外なら非表示にする(スマホの画面外スワイプ対策) if (x < 0 || y < 0 || x > rect.width || y > rect.height) { hideGlass(); return; } const w = glass.offsetWidth / 2; const h = glass.offsetHeight / 2; // 画像の左上(0,0)からの相対座標でセット glass.style.left = (x - w) + "px"; glass.style.top = (y - h) + "px"; // 背景処理 glass.style.backgroundSize = (img.width * zoom) + "px " + (img.height * zoom) + "px"; const posX = (x * zoom) - w; const posY = (y * zoom) - h; glass.style.backgroundPosition = `-${posX}px -${posY}px`; } })(); </script>

補足

touch-action: none: スマホで画像をなぞったときに、ルーペのがたつきやページスクロールを防止する。

display: none: マウスが乗るまで非表示

pointer-events: none; マウス操作を透過

即時実行関数(IIFE): スクリプト全体を (function() { ... })(); で囲み、同じページに他のスクリプトがあった場合に、変数名が衝突してエラーになるのを防ぐ。

{passive: false}: スマホのブラウザに対して、preventDefault を使うことを明示的に伝える。

座標取得の共通化: e.touches[0] があればスマホ、なければマウスとして座標を計算するようにして、1つの関数で両方対応できるようにする。

座標計算の微調整: e.clientX(ブラウザの表示領域からの座標)を使用し、スクロールの影響を受けにくくする。

Twitterでシェア Facebookでシェア Tumblrでシェア Redditでシェア