猫の手ツール

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つ戻る機能はありません。「消す」は全体をクリアします。

手書きの画像を作るツールです。本人認証、電子証明書、タイムスタンプ、文書への署名検証を提供する仕組みではありません。作成したサインを添える文書側の要件も確認してください。