使用 HTML5 Canvas 實現簽名功能

雪旭發表於2024-11-01

在現代網頁應用中,電子簽名越來越常見,尤其是在合同簽署和表單提交中。使用 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>

相關文章