Algorithm & Coordinate Logic
Canvas座標の補正とマウス・タッチの描画処理
サインという「個人の筆跡」をデジタルで忠実に再現するためには、画面サイズに依存しない座標計算と、モバイル特有の挙動をねじ伏せる実装が必要です。
このツールの入力から出力まで
現行コードの確認日:
- 入力
- 写真ではなく、指またはマウスで描く軌跡を入力します。線色と線幅は次に描く区間へ適用します。
- 処理
- 画面上の座標を600×300pxのCanvasへ換算し、移動した2点間を線で結びます。透明な背景には描画を加えません。
- 出力
- 出力は 600×300px の透明 PNG で、Canvas 全体の余白もそのまま保存します。
まず確認する点:端を超えた線や大きな余白もそのまま画像になります。サインの外観を作る工程と、文書の本人認証・署名検証を混同しないことが大切です。
実装の確認箇所:src/pages/tool/signature/index.astro。以下のコード抜粋と出力条件は、この本番実装に基づいて説明します。
仕組みを読み進めるときは、イベントリスナーの基礎(タップやドラッグから描画へつなぐ流れ)、Canvas APIと画像処理(画像寸法、drawImage、画素と透明度の扱い)が参考になります。
1. レスポンシブ環境における「表示サイズ」と「内部解像度」のズレ補正
Canvas要素は、CSSで指定された「表示サイズ(getBoundingClientRect)」と、Canvas自体が持つ「内部解像度(width/height属性)」が異なる場合があります。この比率を考慮せずに描画を行うと、マウスの位置と実際に線が引かれる位置がズレてしまいます。
本ツールでは、描画イベントが発生するたびにスケール比(scaleX / scaleY)を算出し、座標をリアルタイムに正規化しています。これにより、PCのブラウザからスマホの小さな画面まで、等倍感覚での滑らかな描画を可能にしました。
直前の点と現在の点を線で結ぶ描画部分です。筆圧の取得や曲線への補間は行いません。
function signatureSegment(ctx, from, to, color = '#000', width = 3) {
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.beginPath(); ctx.moveTo(from.x, from.y); ctx.lineTo(to.x, to.y); ctx.stroke();
} 2. passive: false による描画中のスクロール抑制
スマートフォンでCanvasに指を置くと、通常はページ全体のスクロールが優先されてしまいます。これを防ぐために touch-action: none をCSSで指定しつつ、JavaScript側ではイベントリスナーの passive オプションを明示的に false に設定しています。
これはモダンブラウザにおける「スクロールの最適化(デフォルトでパッシブになる挙動)」をあえて無効化する処理です。描画処理(preventDefault)を確実に実行させることで、描画中のページスクロールを抑えます。端末のすべてのジェスチャーを無効化するものではありません。
出力の仕様と確認する点
線幅は Canvas 上の 1〜10px です。色や幅の変更は次に描く線へ適用され、既に描いた線をまとめて変更する機能ではありません。点をタップするだけでなく、動かした区間を線として描きます。
出力は 600×300px の透明 PNG で、Canvas 全体の余白もそのまま保存します。自動トリミング、筆圧、ベクター出力、1つ戻る機能はありません。「消す」は全体をクリアします。
手書きの画像を作るツールです。本人認証、電子証明書、タイムスタンプ、文書への署名検証を提供する仕組みではありません。作成したサインを添える文書側の要件も確認してください。