【Panzoom】ピンチインピンチアウトで拡大縮小を実装

初めまして。
中途採用のMMと申します。
フロントエンドエンジニアの区分で働いております。

MM

フロントエンドエンジニア

MM

この記事を書いている現在
まだまだ三寒四温といった様子で
炬燵の電源に手が伸びる朝と夜を過ごしておりますが
公開される頃には過ごしやすい気温だといいなぁ

MM

フロントエンドエンジニア

MM

先日手がけたサイトにて
「スマートフォンレイアウト時は地図をピンチインピンチアウトで拡大縮小してほしい」
という要望をいただき実装したので使用したパッケージのお話をしようと思います。

Panzoomパッケージ

割と直球そのままなパッケージ名ですが、panのほうが移動、zoomが拡大縮小ですね。
撮影用語でカメラ位置を固定し水平に振るカメラワークをパンといいますが、そのパンです。

公式サンプルサイト
https://timmywil.com/panzoom/demo/

サンプルサイト右上アイコンからGitHubのリポジトリにもアクセスできます。
これから記載する導入方法もリポジトリのreadmeに書かれています……英語で。

私が探す限り日本語で使い方を説明しているページは見当たらなかったため、今回記事を書いてみた次第です。
似たパッケージもあったのですが試した結果当時は使いづらかったということでこちらを使用しました。

導入方法

(CDNでの導入も本家には書かれていますが、動作確認ができなかったためnpmのみ記載します)

npmでのインストールの場合

$ npm install --save @panzoom/panzoom

yarnを使っていれば

$ yarn add @panzoom/panzoom

でパッケージを追加できます

使用するときの読み込みは

import Panzoom from '@panzoom/panzoom'

で行うとGIThubのREADMEや公式サンプルに記載されている記述が割とそのまま試せます。

通常反映

See the Pen panzoom反映 by MM (@mm_logical-studio) on CodePen.

弊社マスコットキャラクター・ロージーに見本になっていただきました。
PCでもズームが確認できるようにボタンを用意しました。
タッチデバイスならピンチインピンチアウトの動作でもズームイン、ズームアウトが可能です
cssは主に画像の大きさ、位置の初期状態と「どのエリアがpanzoomの対象になるのか」がわかりやすいように背景色などを設定しています。

jsの実行コードの説明

const elem = document.querySelector('.js-panzoom');
const panzoom = Panzoom(elem);

動かしたい要素を取得(今回は.js-panzoomというクラスを付けたimg要素)
取得した要素を引数に設定して実行します。
実行すると、動かしたい要素ががマウスのドラッグアンドドロップやスワイプ動作で動かせるようになります。
さらにピンチインピンチアウトで拡大縮小ができるようになります!目的達成!
(デフォルトでは親要素にoverflow: hiddenがかかるため親要素の領域からはみ出すとはみ出した分は非表示になります。)

カスタマイズがしたい

さて、これだけでもいいのですが、
「拡大は〇倍までにしたい」
「親のエリアからはみ出して見えない部分が出ないでほしい」
などの希望があったりすると思います。
そんな時はオプションを設定することで実現が可能になる場合もあります。

panzoomで用意されているオプションやオブジェクトをいくつか紹介します。

オプション

このような形式で指定します。

const panzoom = Panzoom(elem, {key: value});
オプションキー 値の形式 デフォルト値 何のための値か
startX number 初期の表示位置(横(X)方向)の指定(単位は「px」)
startY number 初期の表示位置(縦(Y)方向)の指定(単位は「px」)
startScale number 初期の拡大率(単位は「倍」)
disablePan boolean false pan(移動)機能をtrueで無効化する
disableXAxis boolean false 横(X)方向の移動をtrueで無効化する
disableYAxis boolean false 縦(Y)方向の移動をtrueで無効化する
disableZoom boolean false zoom(拡大(縮小))機能をtrueで無効化する
minScale number 0.125 最小拡大(縮小)率を指定。単位は「倍」
maxScale number 4 最大拡大率を指定。単位は「倍」
exclude Element[] [] panzoomの要素内で、イベント処理から除外する要素を指定
※公式デモのサンプル
excludeClass string “panzoom-exclude” panzoomの要素内で、イベント処理から除外するclassを指定
※公式デモのサンプル
contain ‘inside’ | ‘outside’ 親要素の内接範囲内で拡縮・移動するか(親要素をはみ出さない)、外接までで拡縮・移動するかの選択(親要素より小さくならない、親要素とpanzoom要素の間に隙間ができない)
※公式デモのサンプル
cursor string “move” 領域内のカーソルの種類を指定(cssでのカーソル種類設定)

上記で機能説明していないものもありますが、以下のオプションが設定されています

共通オプション(MiscOptions)
animate、canvas、duration、easing、exclude、excludeClass、force、handleStartEvent、noBind、origin、overflow、pinchAndPan、setTransform、silent、startX、startY、startScale、touchAction
panのみのオプション(PanOnlyOptions)
contain、cursor、disablePan、disableXAxis、disableYAxis、relative、panOnlyWhenZoomed、roundPixels
zoomのみのオプション(ZoomOnlyOptions)
disableZoom、focal、minScale、maxScale、step

後述するオブジェクトの引数で使用できるオプションはこれらの組み合わせからなっています。

※各オプションについて詳しくは公式GitHubのsrc/types.tsをご覧ください

オブジェクト(一部抜粋)

このような形式で使用します。

const panzoom = Panzoom(elem);

zoomInBtn.addEventListener('click', panzoom.zoomIn);

panBtn.addEventListener('click', (e) => {
  panzoom.pan(100,100, { relative: true });
})
オブジェクト名 引数 動作
zoom scale: number, zoomOptions?: ZoomOptions=MiscOptions とZoomOnlyOptions panzoom要素を指定されたスケールに拡縮する
zoomIn zoomOptions?: ZoomOptions=MiscOptions とZoomOnlyOptions panzoomのオプションで指定された所定の増分を使用してズームイン処理を行う
zoomOut zoomOptions?: ZoomOptions=MiscOptions とZoomOnlyOptions panzoomのオプションで指定された所定の増分を使用してズームアウト処理を行う
zoomWithWheel event: WheelEvent, zoomOptions?: ZoomOptions=MiscOptions とZoomOnlyOptions マウスホイールの操作で拡縮する
※公式デモのサンプル
pan x: number | string, y: number | string, panOptions?: PanOptions=MiscOptions とPanOnlyOptions 指定された座標へpanzoom要素を移動する。
オプションとしてrelatibe:trueを指定したりすると同じ移動方向距離でどんどん移動する
reset resetOptions?: PanzoomOptions=ptions とPanOnlyOptionsとZoomOnlyOptions panzoom要素を初期状態に戻す
getPan なし panzoomのx,y値のオブジェクトを返す
{ x: number; y: number }
getScale なし panzoomの倍率を数値で返す
getOptions なし panzoomに設定されているオプションをオブジェクト形式で返す
destroy なし panzoomのイベントを無効化する(移動、拡縮をできなくする)

こちらも紹介していないオブジェクトがありますので、「こんな機能ないかな?」と思ったら公式デモサイトか公式GitHubを確認してみるのがいいかと思います。

おわりに

以上、dom要素を拡縮、移動できるpanzoomプラグインについてお話ししました。

  • 実装が比較的容易なnpm提供パッケージ
  • オプションやオブジェクトが用意されておりある程度カスタマイズがしやすい
  • (実は入れ子にすることも可能(公式デモにサンプルあり))
  • スマートフォン端末で滑らかにピンチインピンチアウトができる

と今回制作時にとても助かったので、選択肢の一つにいかがでしょうか。

ところで

弊社ロジカルスタジオでは、一緒に働く仲間を募集しております!
下記リンクからぜひご応募ください!