●ピンチアウト(ピンチイン)とは?
ピンチアウトとは、スマートフォンやタブレットの画面上で2本の指を広げる動作のことを指します。
この動作によって、画面の拡大や縮小を行うことができます。
逆に、2本の指を狭める動作をピンチインと呼びます。
○ピンチアウトの使い方
ピンチアウトは、Webページや画像、地図アプリなどを拡大して詳細を見たいときに便利な機能です。
たとえば、小さな文字が読みにくい場合や、画像の細部を確認したい場合などに活用できます。
具体的な使い方としては、まず拡大したい部分に親指と人差し指を置きます。
そして、2本の指を広げるようにスライドさせると、画面が拡大されていきます。
拡大率は指の間隔に応じて変化するので、好みの大きさになるまで調整できます。
○スマホ・タブレットでのピンチアウト
ほとんどのスマートフォンやタブレットでは、標準でピンチアウトによる拡大縮小機能が搭載されています。
iPhoneやiPadのSafari、AndroidのChromeブラウザなどで、特別な設定をしなくてもピンチアウトが可能です。
ただ、Webサイトによってはピンチアウトを無効化している場合もあります。
その場合は、後述する方法でピンチアウトを有効にする必要があります。
●JavaScriptでピンチアウトを実装する方法
JavaScriptを使えば、Webアプリやスマホアプリでピンチアウトによる拡大縮小機能を実装できます。
ただ、どのように実装すればよいのか、初めは戸惑ってしまうかもしれません。
そこで、ここからはJavaScriptでピンチアウトを実現するための具体的な方法を、サンプルコードを交えながら詳しく解説していきます。
touchイベントやjQuery、Hammer.jsなど、さまざまなアプローチを紹介するので、自分に合った方法を見つけてみてください。
それでは、まずはtouchイベントを使ったサンプルコードから見ていきましょう。
touchイベントとは、スマートフォンやタブレットでタッチ操作を検出するためのイベントです。
これを利用することで、ピンチアウトのジェスチャーを判定できます。
○サンプルコード1:touchイベントを使う
// 要素の取得
const element = document.getElementById('target');
// ピンチアウトのジェスチャーを検出
let startDistance = 0;
let currentDistance = 0;
let initialScale = 1;
let currentScale = 1;
element.addEventListener('touchstart', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
startDistance = getDistance(event.touches[0], event.touches[1]);
initialScale = currentScale;
}
}, false);
element.addEventListener('touchmove', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
currentDistance = getDistance(event.touches[0], event.touches[1]);
currentScale = initialScale * (currentDistance / startDistance);
setScale(currentScale);
}
}, false);
// 2点間の距離を計算する関数
function getDistance(touch1, touch2) {
const dx = touch1.clientX - touch2.clientX;
const dy = touch1.clientY - touch2.clientY;
return Math.sqrt(dx * dx + dy * dy);
}
// 要素の拡大縮小を設定する関数
function setScale(scale) {
element.style.transform = `scale(${scale})`;
}
このサンプルコードでは、touchstartイベントで2本指のタッチを検出し、指の間の距離を計算します。そして、touchmoveイベントで指の動きを追跡し、初期の距離からの変化量に応じて要素の拡大率を更新しています。
実行結果は以下のようになります。
<div id="target">
<img src="sample.jpg" alt="サンプル画像">
</div>
#target {
width: 100%;
height: auto;
transform-origin: center center;
}
上記のHTMLとCSSで要素を用意し、先ほどのJavaScriptコードを適用すると、画像をピンチアウトで拡大縮小できるようになります。
指を広げるほど画像が大きくなり、狭めるほど小さくなる挙動を実現できました。
touchイベントを使ったサンプルの説明は以上です。
touchイベントはスマートフォンやタブレット向けのアプリでよく使われる手法ですが、ピンチアウトに限らずさまざまなジェスチャーの検出に応用できます。
○サンプルコード2:jQueryを使う
つぎに、jQueryを使ってピンチアウトを実装する方法を見ていきます。
jQueryは、JavaScriptのライブラリのひとつで、よく使われる機能を簡単に呼び出せるようにしてくれます。
jQueryでピンチアウトを実現するには、pinch
というイベントを使います。
次のサンプルコードを見てみましょう。
// jQueryを読み込む
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(function() {
// 要素の取得
const $element = $('#target');
// ピンチアウトのジェスチャーを検出
$element.on('pinch', function(event) {
const scale = event.originalEvent.scale;
setScale(scale);
});
// 要素の拡大縮小を設定する関数
function setScale(scale) {
$element.css('transform', `scale(${scale})`);
}
});
</script>
jQueryを使うと、on
メソッドでイベントリスナーを簡単に登録できます。
ここでは、pinch
イベントをリッスンし、イベントオブジェクトから拡大率を取得しています。
あとは、css
メソッドで要素のスタイルを変更するだけです。
実行結果は次のようになります。
<div id="target">
<img src="sample.jpg" alt="サンプル画像">
</div>
#target {
width: 100%;
height: auto;
transform-origin: center center;
}
HTMLとCSSは先ほどと同じように用意します。jQueryのコードを適用することで、画像をピンチアウトで拡大縮小できます。
jQueryを使えば、わずか数行のコードでピンチアウトを実装できました。
jQueryは他にもさまざまなイベントやメソッドを提供しているので、覚えておくと便利です。
○サンプルコード3:Hammer.jsを使う
最後に、Hammer.jsというライブラリを使ってピンチアウトを実装する方法を紹介します。
Hammer.jsは、タッチジェスチャーを簡単に扱えるようにしてくれるライブラリです。
次のサンプルコードを見てみましょう。
// Hammer.jsを読み込む
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
<script>
// 要素の取得
const element = document.getElementById('target');
// Hammerインスタンスを作成
const hammer = new Hammer(element);
// ピンチアウトのジェスチャーを検出
hammer.get('pinch').set({ enable: true });
hammer.on('pinch', function(event) {
const scale = event.scale;
setScale(scale);
});
// 要素の拡大縮小を設定する関数
function setScale(scale) {
element.style.transform = `scale(${scale})`;
}
</script>
Hammer.jsを使うには、まずHammer
インスタンスを作成します。
引数には、ジェスチャーを検出したい要素を指定します。
そして、get
メソッドでpinch
ジェスチャーを有効化し、on
メソッドでイベントリスナーを登録します。
あとは、イベントオブジェクトから拡大率を取得し、要素のスタイルを変更するだけです。
実行結果は次のようになります。
<div id="target">
<img src="sample.jpg" alt="サンプル画像">
</div>
#target {
width: 100%;
height: auto;
transform-origin: center center;
}
HTMLとCSSは同じように用意します。
Hammer.jsのコードを適用することで、画像をピンチアウトで拡大縮小できます。
Hammer.jsを使えば、他にもさまざまなジェスチャーを簡単に扱えます。
ピンチアウトだけでなく、スワイプやタップなども検出できるので、ジェスチャーを活用したアプリ開発に役立つでしょう。
○サンプルコード5:zoomプロパティを使う
JavaScriptでピンチアウトを実装する別の方法として、CSSのzoom
プロパティを使う方法があります。
zoom
プロパティは、要素の拡大率を設定するためのものです。
JavaScriptからzoom
プロパティを操作することで、ピンチアウトによる拡大縮小を実現できます。
それでは、サンプルコードを見ていきましょう。
// 要素の取得
const element = document.getElementById('target');
// ピンチアウトのジェスチャーを検出
let startDistance = 0;
let currentDistance = 0;
let initialZoom = 1;
let currentZoom = 1;
element.addEventListener('touchstart', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
startDistance = getDistance(event.touches[0], event.touches[1]);
initialZoom = currentZoom;
}
}, false);
element.addEventListener('touchmove', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
currentDistance = getDistance(event.touches[0], event.touches[1]);
currentZoom = initialZoom * (currentDistance / startDistance);
setZoom(currentZoom);
}
}, false);
// 2点間の距離を計算する関数
function getDistance(touch1, touch2) {
const dx = touch1.clientX - touch2.clientX;
const dy = touch1.clientY - touch2.clientY;
return Math.sqrt(dx * dx + dy * dy);
}
// 要素の拡大率を設定する関数
function setZoom(zoom) {
element.style.zoom = zoom;
}
このサンプルコードは、先ほどのtouchイベントを使ったコードと似ています。
ただし、拡大率の設定にtransform
プロパティではなくzoom
プロパティを使っています。
touchstart
イベントで初期の指の距離を計算し、touchmove
イベントで現在の指の距離から拡大率を算出します。
そして、setZoom
関数で要素のzoom
プロパティを更新することで、拡大縮小を実現しているのです。
実行結果は次のようになります。
<div id="target">
<img src="sample.jpg" alt="サンプル画像">
</div>
#target {
width: 100%;
height: auto;
}
HTMLとCSSは前述の例と同じです。JavaScriptのコードを適用することで、画像をピンチアウトで拡大縮小できるようになります。
zoom
プロパティを使う利点は、transform
プロパティと比べてシンプルな記述で拡大縮小を実現できる点です。
ただし、zoom
プロパティはIE8以前のバージョンでは使えないので、注意が必要です。
○サンプルコード6:CSS transformを使う
CSSのtransform
プロパティを使って、ピンチアウトによる拡大縮小を実装することもできます。
transform
プロパティは、要素に回転や拡大縮小、移動などの変形を加えるためのものです。
次のサンプルコードを見てみましょう。
// 要素の取得
const element = document.getElementById('target');
// ピンチアウトのジェスチャーを検出
let startDistance = 0;
let currentDistance = 0;
let initialScale = 1;
let currentScale = 1;
element.addEventListener('touchstart', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
startDistance = getDistance(event.touches[0], event.touches[1]);
initialScale = currentScale;
}
}, false);
element.addEventListener('touchmove', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
currentDistance = getDistance(event.touches[0], event.touches[1]);
currentScale = initialScale * (currentDistance / startDistance);
setTransform(currentScale);
}
}, false);
// 2点間の距離を計算する関数
function getDistance(touch1, touch2) {
const dx = touch1.clientX - touch2.clientX;
const dy = touch1.clientY - touch2.clientY;
return Math.sqrt(dx * dx + dy * dy);
}
// 要素の変形を設定する関数
function setTransform(scale) {
element.style.transform = `scale(${scale})`;
}
このサンプルコードも、touchイベントを使ったコードと似ています。
ただし、拡大率の設定にzoom
プロパティではなくtransform
プロパティを使っています。
touchstart
イベントで初期の指の距離を計算し、touchmove
イベントで現在の指の距離から拡大率を算出します。
そして、setTransform
関数で要素のtransform
プロパティを更新することで、拡大縮小を実現しているのです。
実行結果は次のようになります。
<div id="target">
<img src="sample.jpg" alt="サンプル画像">
</div>
#target {
width: 100%;
height: auto;
transform-origin: center center;
}
HTMLは前述の例と同じですが、CSSでtransform-origin
プロパティを設定しています。
これは、変形の基点を要素の中心にするためです。
JavaScriptのコードを適用することで、画像をピンチアウトで拡大縮小できるようになります。
transform
プロパティを使えば、他にも回転や移動など、さまざまな変形効果を加えられます。
ただし、transform
プロパティはIE9以前のバージョンでは使えないので、注意が必要です。
また、GPUアクセラレーションが効くブラウザでは、transform
プロパティの方がzoom
プロパティよりも高速に動作します。
○サンプルコード7:iframeを使う
iframe
要素を使って、ピンチアウトによる拡大縮小を実装する方法もあります。
iframe
要素は、別のHTMLページを埋め込むためのものです。
iframe
要素のwidth
属性とheight
属性を操作することで、埋め込んだページの拡大縮小を実現できます。
次のサンプルコードを見てみましょう。
<iframe id="target" src="sample.html" width="100%" height="400px"></iframe>
// 要素の取得
const element = document.getElementById('target');
// ピンチアウトのジェスチャーを検出
let startDistance = 0;
let currentDistance = 0;
let initialWidth = element.offsetWidth;
let initialHeight = element.offsetHeight;
let currentWidth = initialWidth;
let currentHeight = initialHeight;
element.addEventListener('touchstart', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
startDistance = getDistance(event.touches[0], event.touches[1]);
}
}, false);
element.addEventListener('touchmove', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
currentDistance = getDistance(event.touches[0], event.touches[1]);
const scale = currentDistance / startDistance;
currentWidth = initialWidth * scale;
currentHeight = initialHeight * scale;
setSize(currentWidth, currentHeight);
}
}, false);
// 2点間の距離を計算する関数
function getDistance(touch1, touch2) {
const dx = touch1.clientX - touch2.clientX;
const dy = touch1.clientY - touch2.clientY;
return Math.sqrt(dx * dx + dy * dy);
}
// 要素のサイズを設定する関数
function setSize(width, height) {
element.style.width = `${width}px`;
element.style.height = `${height}px`;
}
このサンプルコードでは、iframe
要素にtouchstart
イベントとtouchmove
イベントを登録しています。
touchstart
イベントで初期の指の距離を計算し、iframe
要素の初期サイズを取得します。
touchmove
イベントで現在の指の距離から拡大率を算出し、setSize
関数でiframe
要素のwidth
とheight
を更新することで、拡大縮小を実現しているのです。
実行結果は次のようになります。
<iframe id="target" src="sample.html" width="100%" height="400px"></iframe>
iframe
要素にsample.html
を埋め込み、初期サイズを設定しています。
JavaScriptのコードを適用することで、iframe
要素をピンチアウトで拡大縮小できるようになります。
iframe
要素を使う利点は、別のページを丸ごと拡大縮小できる点です。
ただし、セキュリティ上の理由から、同一オリジン以外のページは埋め込めないので注意が必要です。
●ピンチアウトを無効にする方法
JavaScriptを使ってピンチアウトを実装する方法を見てきましたが、時にはピンチアウトを無効にしたい場合もあるでしょう。
たとえば、レイアウトが崩れてしまうようなコンテンツでは、ユーザーに意図しない拡大縮小をさせないほうがよいかもしれません。
そこで、ここではピンチアウトを無効にする方法を3つ紹介します。
HTMLやCSSを使う方法から、JavaScriptを使う方法まで、それぞれの特徴を踏まえながら解説していきますので、ぜひ参考にしてみてください。
○HTMLのmetaタグを使う
ピンチアウトを無効にする最も簡単な方法は、HTMLのmeta
タグを使うことです。
次のように、viewport
のuser-scalable
属性をno
に設定するだけです。
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
このように設定すると、ユーザーがピンチアウトで拡大縮小しようとしても、何も反応しなくなります。
ただし、この方法ではピンチアウトだけでなく、他の方法での拡大縮小も一切できなくなるので注意が必要です。
実行結果は次のようになります。
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
</head>
<body>
<div>
<img src="sample.jpg" alt="サンプル画像">
</div>
</body>
</html>
上記のHTMLを表示すると、画像をピンチアウトで拡大縮小しようとしても、何も起こりません。
シンプルに拡大縮小を禁止したい場合は、この方法が手っ取り早いでしょう。
○CSSのtouch-actionプロパティを使う
次に、CSSのtouch-action
プロパティを使う方法を見ていきます。
touch-action
プロパティは、タッチ操作をどのように処理するかを指定するためのものです。
次のように、touch-action
プロパティにpinch-zoom
を指定することで、ピンチアウトによる拡大縮小を無効にできます。
body {
touch-action: pinch-zoom;
}
この方法なら、ピンチアウト以外の操作は通常通り行えます。たとえば、ダブルタップで拡大することもできます。
実行結果は次のようになります。
<!DOCTYPE html>
<html>
<head>
<style>
body {
touch-action: pinch-zoom;
}
</style>
</head>
<body>
<div>
<img src="sample.jpg" alt="サンプル画像">
</div>
</body>
</html>
上記のHTMLとCSSを適用すると、画像をピンチアウトで拡大縮小できなくなります。
ただし、ダブルタップでの拡大は可能です。
touch-action
プロパティを使えば、ピンチアウトだけを無効にしつつ、他の操作は許可するといった細かい制御ができるので便利です。
ただし、このプロパティはIE11以前のバージョンでは使えないので注意が必要です。
○JavaScriptでタッチイベントを無効にする
最後に、JavaScriptを使ってタッチイベントを無効にする方法を紹介します。
具体的には、touchstart
イベントとtouchmove
イベントのデフォルトの動作をキャンセルすることで、ピンチアウトを無効化します。
次のサンプルコードを見てみましょう。
// タッチイベントを無効にする関数
function disableTouchEvent(event) {
if (event.touches.length > 1) {
event.preventDefault();
}
}
// タッチイベントのリスナーを登録
document.addEventListener('touchstart', disableTouchEvent, { passive: false });
document.addEventListener('touchmove', disableTouchEvent, { passive: false });
このサンプルコードでは、disableTouchEvent
関数を定義し、touchstart
イベントとtouchmove
イベントのリスナーとして登録しています。
disableTouchEvent
関数内では、event.touches.length
でタッチ点の数を判定し、2点以上の場合にevent.preventDefault()
を呼び出してイベントのデフォルト動作をキャンセルしています。
これにより、ピンチアウトが無効化されるのです。
実行結果は次のようになります。
<!DOCTYPE html>
<html>
<head>
<script>
// タッチイベントを無効にする関数
function disableTouchEvent(event) {
if (event.touches.length > 1) {
event.preventDefault();
}
}
// タッチイベントのリスナーを登録
document.addEventListener('touchstart', disableTouchEvent, { passive: false });
document.addEventListener('touchmove', disableTouchEvent, { passive: false });
</script>
</head>
<body>
<div>
<img src="sample.jpg" alt="サンプル画像">
</div>
</body>
</html>
上記のHTMLとJavaScriptを適用すると、画像をピンチアウトで拡大縮小できなくなります。
ただし、ダブルタップでの拡大は可能です。
JavaScriptを使う利点は、柔軟にイベントをコントロールできる点です。
たとえば、特定の条件下でだけピンチアウトを無効にするといったことも可能です。
ただし、addEventListener
の第3引数で{ passive: false }
を指定している点に注意が必要です。
これは、preventDefault()
を呼び出すために必要な設定ですが、パフォーマンスに影響を与える可能性があります。
●よくあるエラーと対処法
JavaScriptでピンチアウトを実装する際、思わぬエラーに遭遇することがあります。
初心者の方は特に、どこに問題があるのかわからず、頭を抱えてしまうかもしれません。
ここでは、ピンチアウトに関するよくあるエラーとその対処法を3つ紹介します。
これを押さえておけば、つまずきを減らし、スムーズに実装できるでしょう。
それでは、具体的なエラーとその解決方法を見ていきましょう。
きっと、みなさんが抱えている悩みにも答えがあるはずです。
一緒に、JavaScriptのスキルアップを目指していきましょう!
○ピンチアウトができない場合
ピンチアウトを実装したつもりでも、動作しないことがあります。
その原因のひとつが、タッチイベントの設定ミスです。
たとえば、次のようなコードを書いたとします。
// 要素の取得
const element = document.getElementById('target');
// ピンチアウトのジェスチャーを検出
element.addEventListener('touchstart', function(event) {
// 処理を記述
}, false);
element.addEventListener('touchmove', function(event) {
// 処理を記述
}, false);
このコードでは、touchstart
イベントとtouchmove
イベントのリスナーを登録していますが、肝心の処理が記述されていません。
これでは、ピンチアウトが動作しないのも当然です。
正しくは、次のように処理を記述する必要があります。
// 要素の取得
const element = document.getElementById('target');
// ピンチアウトのジェスチャーを検出
let startDistance = 0;
let currentDistance = 0;
let initialScale = 1;
let currentScale = 1;
element.addEventListener('touchstart', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
startDistance = getDistance(event.touches[0], event.touches[1]);
initialScale = currentScale;
}
}, false);
element.addEventListener('touchmove', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
currentDistance = getDistance(event.touches[0], event.touches[1]);
currentScale = initialScale * (currentDistance / startDistance);
setScale(currentScale);
}
}, false);
// 2点間の距離を計算する関数
function getDistance(touch1, touch2) {
const dx = touch1.clientX - touch2.clientX;
const dy = touch1.clientY - touch2.clientY;
return Math.sqrt(dx * dx + dy * dy);
}
// 要素の拡大縮小を設定する関数
function setScale(scale) {
element.style.transform = `scale(${scale})`;
}
このように、touchstart
イベントで初期の指の距離を計算し、touchmove
イベントで現在の指の距離から拡大率を算出します。
そして、setScale
関数で要素の拡大縮小を設定しています。
処理を正しく記述することで、ピンチアウトが動作するようになります。
コードを書く際は、イベントリスナーの登録だけでなく、中身の処理もきちんと記述しましょう。
○ズームが固定されてしまう場合
ピンチアウトを実装したら、次は拡大率の制限を設けたくなるかもしれません。
でも、うっかりコードを書き間違えると、ズームが固定されて動かなくなってしまうことがあります。
たとえば、次のようなコードを書いたとします。
// 要素の取得
const element = document.getElementById('target');
// ピンチアウトのジェスチャーを検出
let startDistance = 0;
let currentDistance = 0;
let initialScale = 1;
let currentScale = 1;
element.addEventListener('touchstart', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
startDistance = getDistance(event.touches[0], event.touches[1]);
initialScale = currentScale;
}
}, false);
element.addEventListener('touchmove', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
currentDistance = getDistance(event.touches[0], event.touches[1]);
currentScale = initialScale * (currentDistance / startDistance);
// 拡大率を1倍に固定
currentScale = 1;
setScale(currentScale);
}
}, false);
// 2点間の距離を計算する関数
function getDistance(touch1, touch2) {
const dx = touch1.clientX - touch2.clientX;
const dy = touch1.clientY - touch2.clientY;
return Math.sqrt(dx * dx + dy * dy);
}
// 要素の拡大縮小を設定する関数
function setScale(scale) {
element.style.transform = `scale(${scale})`;
}
このコードでは、touchmove
イベントの処理の中で、currentScale
を常に1に設定しています。
その結果、拡大率が1倍に固定され、ピンチアウトが機能しなくなってしまいます。
正しくは、次のように拡大率の範囲を制限する必要があります。
element.addEventListener('touchmove', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
currentDistance = getDistance(event.touches[0], event.touches[1]);
currentScale = initialScale * (currentDistance / startDistance);
// 拡大率の範囲を制限
currentScale = Math.min(Math.max(currentScale, 0.5), 2);
setScale(currentScale);
}
}, false);
このように、Math.min
とMath.max
を使って拡大率の最小値と最大値を設定することで、拡大率を制限しつつピンチアウトを機能させることができます。
拡大率を制限する際は、固定値を設定するのではなく、適切な範囲を指定するようにしましょう。
また、アプリの要件に合わせて、最小値と最大値を調整するのも大切です。
○意図しない拡大縮小が発生する場合
ピンチアウトを実装すると、意図しない拡大縮小が発生することがあります。
たとえば、要素内のテキストを選択しようとしたときに、うっかりピンチアウトが動作してしまうようなケースです。
これを防ぐには、ピンチアウトのジェスチャーを適切に判定する必要があります。
次のように、touchstart
イベントとtouchmove
イベントの両方で、タッチ点の数をチェックするのがポイントです。
// 要素の取得
const element = document.getElementById('target');
// ピンチアウトのジェスチャーを検出
let startDistance = 0;
let currentDistance = 0;
let initialScale = 1;
let currentScale = 1;
element.addEventListener('touchstart', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
startDistance = getDistance(event.touches[0], event.touches[1]);
initialScale = currentScale;
}
}, false);
element.addEventListener('touchmove', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
currentDistance = getDistance(event.touches[0], event.touches[1]);
currentScale = initialScale * (currentDistance / startDistance);
setScale(currentScale);
}
}, false);
// 2点間の距離を計算する関数
function getDistance(touch1, touch2) {
const dx = touch1.clientX - touch2.clientX;
const dy = touch1.clientY - touch2.clientY;
return Math.sqrt(dx * dx + dy * dy);
}
// 要素の拡大縮小を設定する関数
function setScale(scale) {
element.style.transform = `scale(${scale})`;
}
このように、touchstart
イベントとtouchmove
イベントの両方でevent.touches.length
をチェックし、2本指でタッチされている場合のみ処理を実行するようにします。
こうすることで、1本指での操作時はピンチアウトが動作しなくなるので、意図しない拡大縮小を防ぐことができます。
ユーザビリティの観点からも、適切なジェスチャー判定は欠かせません。
また、状況によってはtouchend
イベントやtouchcancel
イベントでも処理を記述し、ジェスチャーの終了時に拡大率をリセットするなどの工夫も必要でしょう。
●ピンチアウトの応用例
ここまで、JavaScriptでピンチアウトを実装する方法やエラー対処法について詳しく見てきました。
でも、実際のアプリ開発では、ピンチアウトをどのように活用すればよいのでしょうか?
そこで、ここからはピンチアウトの応用例を3つ紹介します。
画像ビューワーや地図アプリ、プレゼンテーションアプリなど、実践的なサンプルコードを交えながら解説していきますので、ぜひ参考にしてみてください。
これまで学んだ知識を活かして、より実用的なアプリ開発に挑戦してみましょう。
きっと、JavaScriptのスキルアップにつながるはずです。それでは、早速見ていきましょう!
○サンプルコード9:画像ビューワーを作る
まずは、ピンチアウトを使った画像ビューワーを作ってみましょう。
ユーザーが画像をピンチアウトで拡大縮小できるようにすることで、より直感的な操作性を実現できます。
次のサンプルコードを見てみましょう。
<div id="viewer">
<img src="sample.jpg" alt="サンプル画像">
</div>
#viewer {
width: 100%;
height: 400px;
overflow: hidden;
}
#viewer img {
width: 100%;
height: 100%;
object-fit: contain;
transform-origin: center center;
}
// 要素の取得
const viewer = document.getElementById('viewer');
const image = viewer.querySelector('img');
// ピンチアウトのジェスチャーを検出
let startDistance = 0;
let currentDistance = 0;
let initialScale = 1;
let currentScale = 1;
viewer.addEventListener('touchstart', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
startDistance = getDistance(event.touches[0], event.touches[1]);
initialScale = currentScale;
}
}, false);
viewer.addEventListener('touchmove', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
currentDistance = getDistance(event.touches[0], event.touches[1]);
currentScale = initialScale * (currentDistance / startDistance);
setScale(currentScale);
}
}, false);
// 2点間の距離を計算する関数
function getDistance(touch1, touch2) {
const dx = touch1.clientX - touch2.clientX;
const dy = touch1.clientY - touch2.clientY;
return Math.sqrt(dx * dx + dy * dy);
}
// 画像の拡大縮小を設定する関数
function setScale(scale) {
image.style.transform = `scale(${scale})`;
}
このサンプルコードでは、#viewer
要素内にimg
要素を配置し、画像を表示しています。
そして、#viewer
要素にtouchstart
イベントとtouchmove
イベントを登録し、ピンチアウトのジェスチャーを検出しています。
touchstart
イベントで初期の指の距離を計算し、touchmove
イベントで現在の指の距離から拡大率を算出します。
算出した拡大率は、setScale
関数でimg
要素のtransform
プロパティに設定されます。
実行結果
<div id="viewer">
<img src="sample.jpg" alt="サンプル画像">
</div>
#viewer {
width: 100%;
height: 400px;
overflow: hidden;
}
#viewer img {
width: 100%;
height: 100%;
object-fit: contain;
transform-origin: center center;
}
上記のHTMLとCSSを適用し、JavaScriptのコードを動作させると、画像をピンチアウトで拡大縮小できるようになります。
overflow: hidden
を設定することで、拡大時に画像がはみ出ないようにしています。
このように、ピンチアウトを使えば、シンプルな画像ビューワーを実装できます。
画像のサイズや配置を調整することで、より見やすいビューワーに仕上げていきましょう。
○サンプルコード10:地図アプリを作る
つぎに、ピンチアウトを使った地図アプリを作ってみましょう。
GoogleマップなどのWeb地図サービスでは、ピンチアウトによる地図の拡大縮小が一般的です。
次のサンプルコードを見てみましょう。
<div id="map"></div>
#map {
width: 100%;
height: 400px;
}
// 地図の初期化
function initMap() {
const map = new google.maps.Map(document.getElementById('map'), {
center: { lat: 35.6809591, lng: 139.7673068 },
zoom: 12
});
// ピンチアウトのジェスチャーを検出
let startDistance = 0;
let currentDistance = 0;
let initialZoom = map.getZoom();
let currentZoom = initialZoom;
map.addListener('touchstart', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
startDistance = getDistance(event.touches[0], event.touches[1]);
initialZoom = currentZoom;
}
});
map.addListener('touchmove', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
currentDistance = getDistance(event.touches[0], event.touches[1]);
currentZoom = initialZoom + Math.log2(currentDistance / startDistance);
map.setZoom(currentZoom);
}
});
// 2点間の距離を計算する関数
function getDistance(touch1, touch2) {
const dx = touch1.clientX - touch2.clientX;
const dy = touch1.clientY - touch2.clientY;
return Math.sqrt(dx * dx + dy * dy);
}
}
このサンプルコードでは、Google Maps APIを使って地図を表示しています。
initMap
関数内で、google.maps.Map
コンストラクタを使って地図を初期化し、東京の座標を中心に表示しています。
そして、地図にtouchstart
イベントとtouchmove
イベントを登録し、ピンチアウトのジェスチャーを検出しています。
touchstart
イベントで初期の指の距離とズームレベルを取得し、touchmove
イベントで現在の指の距離から新しいズームレベルを算出します。
算出したズームレベルは、map.setZoom
メソッドで地図に設定されます。
ズームレベルの計算には、Math.log2
を使って対数を求めています。
これにより、指の距離の変化に応じて滑らかにズームできます。
実行結果は次のようになります。
<div id="map"></div>
#map {
width: 100%;
height: 400px;
}
上記のHTMLとCSSを適用し、JavaScriptのコードを動作させると、地図をピンチアウトで拡大縮小できるようになります。
ズームレベルに応じて、地図の詳細度が変化するのが確認できるでしょう。
このように、ピンチアウトを使えば、直感的な操作性を備えた地図アプリを実装できます。
実際のアプリ開発では、マーカーの表示や経路検索など、さまざまな機能を組み合わせていくことになります。
今回のサンプルコードを参考に、オリジナルの地図アプリ開発に挑戦してみてはいかがでしょうか。
Google Maps APIの公式ドキュメントも参照しながら、理解を深めていきましょう。
○サンプルコード11:プレゼンテーションアプリを作る
最後に、ピンチアウトを使ったプレゼンテーションアプリを作ってみましょう。
スライドをピンチアウトで拡大縮小できるようにすることで、プレゼンテーションの自由度が高まります。
次のサンプルコードを見てみましょう。
<div id="presentation">
<div class="slide">
<h2>スライド1</h2>
<p>ここにスライドの内容を記述します。</p>
</div>
<div class="slide">
<h2>スライド2</h2>
<p>ここにスライドの内容を記述します。</p>
</div>
<div class="slide">
<h2>スライド3</h2>
<p>ここにスライドの内容を記述します。</p>
</div>
</div>
#presentation {
width: 100%;
height: 400px;
overflow: hidden;
position: relative;
}
.slide {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
opacity: 0;
transition: opacity 0.5s;
transform-origin: center center;
}
.slide.active {
opacity: 1;
}
// 要素の取得
const presentation = document.getElementById('presentation');
const slides = presentation.querySelectorAll('.slide');
// 初期スライドを表示
let currentIndex = 0;
slides[currentIndex].classList.add('active');
// ピンチアウトのジェスチャーを検出
let startDistance = 0;
let currentDistance = 0;
let initialScale = 1;
let currentScale = 1;
presentation.addEventListener('touchstart', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
startDistance = getDistance(event.touches[0], event.touches[1]);
initialScale = currentScale;
}
}, false);
presentation.addEventListener('touchmove', function(event) {
// 2本指でタッチされている場合のみ処理
if (event.touches.length === 2) {
currentDistance = getDistance(event.touches[0], event.touches[1]);
currentScale = initialScale * (currentDistance / startDistance);
setScale(currentScale);
}
}, false);
// 2点間の距離を計算する関数
function getDistance(touch1, touch2) {
const dx = touch1.clientX - touch2.clientX;
const dy = touch1.clientY - touch2.clientY;
return Math.sqrt(dx * dx + dy * dy);
}
// スライドの拡大縮小を設定する関数
function setScale(scale) {
slides[currentIndex].style.transform = `scale(${scale})`;
}
// スライドを切り替える関数
function changeSlide(index) {
slides[currentIndex].classList.remove('active');
currentIndex = index;
slides[currentIndex].classList.add('active');
currentScale = 1;
setScale(currentScale);
}
// スライドの切り替えイベントを設定
presentation.addEventListener('click', function() {
const nextIndex = (currentIndex + 1) % slides.length;
changeSlide(nextIndex);
}, false);
このサンプルコードでは、#presentation
要素内に複数の.slide
要素を配置し、スライドを表現しています。
初期状態では、最初のスライドにactive
クラスを付与し、表示しています。
そして、#presentation
要素にtouchstart
イベントとtouchmove
イベントを登録し、ピンチアウトのジェスチャーを検出しています。
touchstart
イベントで初期の指の距離を計算し、touchmove
イベントで現在の指の距離から拡大率を算出します。
算出した拡大率は、setScale
関数で現在のスライドのtransform
プロパティに設定されます。
また、click
イベントを登録し、クリックされたらスライドを切り替えるようにしています。
実行結果
<div id="presentation">
<div class="slide">
<h2>スライド1</h2>
<p>ここにスライドの内容を記述します。</p>
</div>
<div class="slide">
<h2>スライド2</h2>
<p>ここにスライドの内容を記述します。</p>
</div>
<div class="slide">
<h2>スライド3</h2>
<p>ここにスライドの内容を記述します。</p>
</div>
</div>
#presentation {
width: 100%;
height: 400px;
overflow: hidden;
position: relative;
}
.slide {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
opacity: 0;
transition: opacity 0.5s;
transform-origin: center center;
}
.slide.active {
opacity: 1;
}
上記のHTMLとCSSを適用し、JavaScriptのコードを動作させると、スライドをピンチアウトで拡大縮小できるようになります。
クリックするとスライドが切り替わり、それぞれのスライドで拡大縮小が可能です。
まとめ
JavaScriptを使ったピンチアウトの実装方法について、詳しく見てきましたが、いかがでしたか?
最初は戸惑うこともあったかもしれませんが、サンプルコードを参考に、少しずつ理解が深まったのではないでしょうか。
この記事が、みなさんのJavaScriptの学習に少しでも役立てば幸いです。
ピンチアウトを始めとする、さまざまなUI操作の実装に挑戦し、ユーザーにとって使いやすく価値のあるアプリを開発していきましょう。