【实录】基于 Canvas 的签名板实现:支持鼠标与触摸

发布于:2025-08-30 ⋅ 阅读:(16) ⋅ 点赞:(0)

在很多场景中我们需要用户在线签署,比如:在线合同、快递确认、表单签名等。 今天我们来实现一个简单的 Canvas 签名板,它支持 PC 鼠标绘制移动端触摸绘制

需求分析

  1. 实现签名功能。
  2. 既支持鼠标操作,也支持触摸操作。
  3. 支持修改线条宽度和颜色
  4. 支持导出 PNG、SVG、JSON、点坐标等格式

核心思路

  1. 使用 Canvas API 来绘制签名:

    • ctx.beginPath() 开始绘制路径。
    • ctx.moveTo(x, y) 移动画笔到起始点。
    • ctx.lineTo(x, y) 绘制到目标点。
    • ctx.stroke() 执行绘制指令。
  2. 监听鼠标和触摸事件,将用户的手势轨迹映射到 Canvas 上。

  3. 关键点:如何将鼠标/手指在屏幕上的位置,转换为 相对于 Canvas 的坐标

    • 使用 element.getBoundingClientRect() 获取 Canvas 的偏移量。

整体思维导图

在这里插入图片描述

实现步骤

1. 封装获取坐标值的工具类(兼容鼠标和触摸事件)

function getCoordinates(e) {
    let x, y;
    if (e.type.includes('touch')) {
        const touch = e.touches[0] || e.changedTouches[0];
        const rect = canvas.getBoundingClientRect();
        x = touch.clientX - rect.left;
        y = touch.clientY - rect.top;
    } else {
        const rect = canvas.getBoundingClientRect();
        x = e.clientX - rect.left;
        y = e.clientY - rect.top;
    }return [x, y];
}

2. 创建 Canvas

<canvas id="signatureCanvas"></canvas>

3. 监听鼠标事件

// 鼠标按下
canvas.addEventListener('mousedown', startDrawing); // 开始绘制
// 鼠标移动
canvas.addEventListener('mousemove', draw); // 绘制线条
// 鼠标弹起
canvas.addEventListener('mouseup', stopDrawing); // 结束绘制
// 鼠标从元素上移出,防止用户将鼠标移出画布时意外中断绘制状态
canvas.addEventListener('mouseout', stopDrawing); // 结束绘制

4. 监听触摸事件(移动端)

canvas.addEventListener('touchstart', startDrawing); // 开始绘制
canvas.addEventListener('touchmove', draw); // 绘制线条
canvas.addEventListener('touchend', stopDrawing); // 结束绘制

5. 开始绘制 startDrawing 具体实现

function startDrawing(e) {
    isDrawing = true;
    [lastX, lastY] = getCoordinates(e);// 开始新路径
    currentPath = {
        points: [], // 点坐标列表
        color: strokeStyle, // 线条颜色
        width: lineWidth // 线条宽度
    };
}

6. 绘制中 draw 具体实现

function draw(e) {
    if (!isDrawing) return;const [x, y] = getCoordinates(e);
​
    ctx.beginPath();
    ctx.moveTo(lastX, lastY);
    ctx.lineTo(x, y);
    ctx.strokeStyle = strokeStyle;
    ctx.lineWidth = lineWidth; // 设置的线条宽度
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';
    ctx.stroke();// 记录点
    if (currentPath) {
        currentPath.points.push({x, y});
    }[lastX, lastY] = [x, y];
}

7.结束绘制 stopDrawing 具体实现

function stopDrawing() {
    if (!isDrawing) return;
​
    isDrawing = false;// 保存当前路径,便于后续撤销、重绘、导出等操作
    if (currentPath && currentPath.points.length > 0) {
        drawingData.push(currentPath);
    }
    currentPath = null;
}

8. 设置线条宽度

function setWidth() {
    lineWidth = lineWidth < 10 ? lineWidth + 1 : 1;
    widthValue.textContent = lineWidth;
}

导出图片等功能

function exportPNG() {
  const dataURL = canvas.toDataURL('image/png');
  console.log("PNG Base64:", dataURL);
  return dataURL;
}

总结

源码

通过简单的 Canvas API + 鼠标/触摸事件,我们就能实现一个跨平台的签名功能。 这类功能的关键在于 事件处理坐标转换,同时也为我们理解前端与用户交互提供了一个很好案例。

当然,实际项目中我们还可以做更多扩展,比如:

  • 增加 清空画布、撤销操作
  • 支持 保存为图片并上传服务器
  • 提供 不同颜色和笔刷粗细选择

这样,一个小小的 Canvas 签名板,就能变成实用的电子签署工具。


网站公告

今日签到

点亮在社区的每一天
去签到