ピンチズームのキャンバス
2本指のピンチで拡大・縮小し、1本指でパンする地図風キャンバス。ダブルタップで 2 倍と等倍を往復、PC ではホイールで拡大・ドラッグで移動。倍率は 1〜4 倍に制限。
プレビュー
ドラッグ
操作ドラッグ/スワイプで操作できます(PC・スマホ対応)。
仕様書
- 向く場面
- 地図・図面・大きな画像を指で拡大して見る
- 拡大の中心を指の間(カーソル位置)に固定したい場面
- ダブルタップで 2 倍⇄等倍を往復させたいビューア
- 避ける場面
- 文字主体の本文(ブラウザのズームで足りる)
- 縦スクロールの途中に置く(touch-action:none で止まる)
- 倍率制限が要らない無限キャンバス
- 構成要素
- ステージ
- キャンバス(SVG)
- 倍率表示
- 拡大/縮小/リセットボタン
- 操作ヒント
- 持っている状態
- 通常
- フォーカス
- 押下中
- キーボード
Tab でキャンバスへ入り、矢印で 40px ずつ移動、+/− で拡大縮小、0 でリセット。続く Tab で拡大/縮小/リセットのボタンへ、Enter/Space で操作
- 支援技術
キャンバスは tabindex=0+role=group+操作を含む aria-label。倍率は aria-live=polite で読まれる。ボタンは aria-label「拡大/縮小」。地図の SVG は aria-hidden。reduced-motion で補間を停止
- 動き
ボタンとダブルタップは 280ms ease-out で補間、ピンチ・ドラッグ・ホイールは無遅延で追従。倍率 1〜4 倍に制限
デザインの要点
- 拡大の中心は画面中央ではなく指の間(PC はカーソル位置)。見ていた場所が指の下から逃げないことがズームの本質
- 倍率は上限と下限を決める。等倍より縮ませない・4 倍以上にしないと、迷子になる操作を最初から作らない
- ダブルタップは「2 倍⇄等倍」の往復に固定する。1 回の操作で確実に戻れる道を用意する
- キャンバスには touch-action: none を指定してブラウザのズームとスクロールを止め、指の動きを全部受け取る
コード(コピーして使えます)
<div class="pzc-wrap">
<div class="pzc-stage" id="pzc-stage" tabindex="0" role="group" aria-label="地図(ピンチで拡大。キーボードは矢印で移動、+ − で拡大縮小)">
<div class="pzc-canvas" id="pzc-canvas">
<svg viewBox="0 0 400 300" width="100%" height="100%" aria-hidden="true">
<defs><pattern id="pzc-grid" width="20" height="20" patternUnits="userSpaceOnUse"><path d="M20 0H0V20" fill="none" stroke="#e3ddd0" stroke-width="1"/></pattern></defs>
<rect width="400" height="300" fill="#f7f3ea"/>
<rect width="400" height="300" fill="url(#pzc-grid)"/>
<path d="M0 120 C80 100 120 160 200 140 S320 90 400 110" fill="none" stroke="#bcd6ea" stroke-width="14" stroke-linecap="round"/>
<path d="M60 0 L90 300" stroke="#fff" stroke-width="10"/><path d="M60 0 L90 300" stroke="#e0d8c8" stroke-width="12" stroke-dasharray="0" opacity="0.4"/>
<path d="M0 220 H400" stroke="#fff" stroke-width="10"/>
<rect x="120" y="170" width="70" height="40" rx="4" fill="#dfe8d2"/>
<rect x="230" y="30" width="90" height="60" rx="4" fill="#e6e0f0"/>
<rect x="300" y="240" width="60" height="40" rx="4" fill="#f2dfd0"/>
<circle cx="200" cy="150" r="8" fill="#2b50c7"/><circle cx="200" cy="150" r="14" fill="none" stroke="#2b50c7" stroke-width="2" opacity="0.4"/>
<text x="212" y="146" font-size="12" font-weight="700" fill="#2c2823">ミナト工房</text>
<text x="126" y="195" font-size="11" fill="#5b6b4c">中央公園</text>
<text x="236" y="65" font-size="11" fill="#5b4c7a">市民ホール</text>
<text x="306" y="264" font-size="11" fill="#7a5a44">港南駅</text>
</svg>
</div>
<div class="pzc-hud">
<span class="pzc-scale" id="pzc-scale" aria-live="polite">1.0×</span>
<div class="pzc-btns">
<button class="pzc-btn" type="button" id="pzc-in" aria-label="拡大">+</button>
<button class="pzc-btn" type="button" id="pzc-out" aria-label="縮小">−</button>
<button class="pzc-btn pzc-btn-text" type="button" id="pzc-reset">リセット</button>
</div>
</div>
</div>
<p class="pzc-hint">ピンチで拡大・ドラッグで移動・ダブルタップで 2×⇄1×(PC はホイール、キーボードは矢印と + −)</p>
</div>