在現代網頁應用中,電子簽名越來越常見,尤其是在合同簽署和表單提交中。使用 HTML5 的 <canvas>
元素,我們可以輕鬆地建立一個簽名捕捉工具。本文將帶你一步步實現一個簡單的簽名應用程式。
1. 專案準備
建立基本 HTML 結構:首先,我們需要設定 HTML 頁面。我們將包含一個畫布元素用於繪製簽名,以及一個按鈕用於儲存簽名。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } .wrap { margin: 50px; width: 500px; } canvas { border: 1px solid #000; } .save-btn { width: 200px; height: 30px; line-height: 30px; font-size: 16px; color: #999; cursor: pointer; border: 1px solid; text-align: center; margin: 0 auto; } </style> </head> <body> <div class="wrap"> <canvas id="canvas"></canvas> <div class="save-btn">儲存</div> </div> </body> </html>
2. JavaScript 實現簽名功能
接下來,我們需要新增 JavaScript 程式碼,以便處理使用者的繪圖操作並儲存簽名。
初始化 Canvas
首先,我們獲取畫布元素並設定其大小和繪圖上下文:
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
canvas.width = 500; // 設定畫布寬度
canvas.height = 300; // 設定畫布高度
let isDrawing = false;
處理繪圖事件
我們將新增事件監聽器,以便使用者能夠使用滑鼠或觸控在畫布上繪製簽名。這個功能主要用到三個事件,滑鼠按下,滑鼠移動,滑鼠離開。滑鼠按下允許移動呼叫beginPath方法。在滑鼠移動事件中,先用getBoundingClientRect物件獲取canvas在檢視中的位置,計算相對座標。 lineTo方法設定繪製座標,再呼叫stroke方法進行繪製。
按下開啟一個路徑
const canvas = document.querySelector('#canvas'); const ctx = canvas.getContext('2d'); const saveBtn = document.querySelector('.save-btn'); canvas.width = 500; canvas.height = 300; let isDrawing = false; canvas.addEventListener('mousedown', (e) => { isDrawing = true; ctx.beginPath(); }) canvas.addEventListener('mousemove', (e) => { if (isDrawing) { const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.strokeStyle = 'red'; ctx.lineTo(x, y); ctx.stroke() } }) canvas.addEventListener('mouseup', () => { isDrawing = false; })
新增移動端支援
canvas.addEventListener('touchstart', (e) => { isDrawing = true; ctx.beginPath(); e.preventDefault(); // 防止觸控移動時頁面滾動 }); canvas.addEventListener('touchmove', (e) => { if (isDrawing) { const rect = canvas.getBoundingClientRect(); const x = e.touches[0].clientX - rect.left; const y = e.touches[0].clientY - rect.top; ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.strokeStyle = 'red'; ctx.lineTo(x, y); ctx.stroke(); } }); canvas.addEventListener('touchend', () => { isDrawing = false; });
儲存簽名功能
最後,我們需要實現儲存簽名的功能。我們將使用 toBlob
方法將畫布內容轉換為圖片。
const saveBtn = document.querySelector('#saveBtn'); saveBtn.addEventListener('click', () => { saveSignature(); }); function saveSignature() { canvas.toBlob((blob) => { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'signature.png'; // 指定下載檔案的名稱 a.click(); }, 'image/png'); }
3. 完整程式碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } .wrap { margin: 50px; width: 500px; } canvas { border: 1px solid #000; } .save-btn { width: 200px; height: 30px; line-height: 30px; font-size: 16px; color: #999; cursor: pointer; border: 1px solid; text-align: center; margin: 0 auto; } </style> </head> <body> <div class="wrap"> <canvas id="canvas"></canvas> <div class="save-btn">儲存</div> </div> <script> const canvas = document.querySelector('#canvas'); const ctx = canvas.getContext('2d'); const saveBtn = document.querySelector('.save-btn'); canvas.width = 500; canvas.height = 300; let isDrawing = false; // 開始繪圖 canvas.addEventListener('mousedown', (e) => { isDrawing = true; ctx.beginPath(); }) // 繪製 canvas.addEventListener('mousemove', (e) => { if (isDrawing) { const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.strokeStyle = 'red'; ctx.lineTo(x, y); ctx.stroke() } }) // 停止繪圖 canvas.addEventListener('mouseup', () => { isDrawing = false; }) // 開始繪圖 canvas.addEventListener('touchstart', (e) => { isDrawing = true; ctx.beginPath(); }) // 繪製 canvas.addEventListener('touchmove', (e) => { if (isDrawing) { const rect = canvas.getBoundingClientRect(); const x = e.touches[0].clientX - rect.left; const y = e.touches[0].clientY - rect.top; ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.strokeStyle = 'red'; ctx.lineTo(x, y); ctx.stroke() } }) // 停止繪圖 canvas.addEventListener('touchend', () => { isDrawing = false; }) saveBtn.addEventListener('click', () => { save() }) function save() { // 將畫布內容轉換為圖片 canvas.toBlob(function (blob) { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'canvas_image.png'; // 指定下載檔案的名稱 a.click() }, 'image/png'); } </script> </body> </html>