当前位置: 首页 > article >正文

如何用HTML5 Canvas实现电子签名功能✍️

在这里插入图片描述

🤖 作者简介:水煮白菜王,一位资深前端劝退师 👻
👀 文章专栏: 前端专栏 ,记录一下平时在博客写作中,总结出的一些开发技巧和知识归纳总结✍。
感谢支持💕💕💕

🖌️电子签名作为数字化转型的重要环节,在前端领域可通过HTML5 Canvas轻松实现。本文将以HTML Demo示例🎨,手把手带您完成一个电子签名功能。

目录

  • 一、实现原理与核心技术
  • 二、核心代码实现解析
    • 2.1 画布初始化
    • 2.2 画笔样式配置
    • 2.3 设备兼容处理
    • 2.4 绘制逻辑实现
      • 起笔监听:
      • 移动绘制:
      • 收笔处理:
    • 2.5 功能按钮实现
      • 清空画布:
      • 保存签名:
      • 可加撤销功能:
  • 三、注意事项
  • 四、完整代码Demo示例
  • 五、总结

一、实现原理与核心技术

通过HTML5 Canvas的2D绘图上下文实现轨迹捕捉,结合事件监听处理完成核心绘制功能。关键技术点包括:

  1. Canvas绘图API:Path路径操作
  2. 事件系统:鼠标/触摸事件统一处理
  3. 文件导出:Canvas转Blob对象

二、核心代码实现解析

2.1 画布初始化

设置600x300画布并获取2D上下文,建议根据屏幕尺寸动态调整画布大小。

const canvas = document.querySelector('canvas');
canvas.width = 500;
canvas.height = 300;
const ctx = canvas.getContext('2d');

2.2 画笔样式配置

通过lineCap和lineJoin实现自然的手写效果。

ctx.lineWidth = 3;
ctx.strokeStyle = 'red';
ctx.lineCap = 'round'; // 圆角线头
ctx.lineJoin = 'round'; // 圆角连接

2.3 设备兼容处理

通过UA检测自动切换触摸/鼠标事件,实际项目中建议使用pointer events实现更优雅的兼容。

const mobileStatus = /Mobile|Android|iPhone/i.test(navigator.userAgent);

2.4 绘制逻辑实现

起笔监听:

function start(event) {
  const pos = mobileStatus ? event.changedTouches[0] : event;
  ctx.beginPath();
  ctx.moveTo(pos.pageX, pos.pageY);
  window.addEventListener(mobileStatus ? 'touchmove' : 'mousemove', draw);
}

移动绘制:

function draw(event) {
  const pos = mobileStatus ? event.changedTouches[0] : event;
  ctx.lineTo(pos.pageX, pos.pageY);
  ctx.stroke(); // 实时渲染路径
}

收笔处理:

function closeDraw() {
  window.removeEventListener('mousemove', draw);
}

2.5 功能按钮实现

清空画布:

function cancel() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
}

保存签名:

function save() {
  canvas.toBlob(blob => {
    const a = document.createElement('a');
    a.download = `${Date.now()}.png`;
    a.href = URL.createObjectURL(blob);
    a.click();
  });
}

可加撤销功能:

let history = [];
// 绘制时保存状态
history.push(ctx.getImageData(0,0,canvas.width,canvas.height));

function undo() {
  if(history.length > 1) {
    history.pop();
    ctx.putImageData(history[history.length-1], 0,0);
  }
}


三、注意事项

  1. 性能优化:大数据量绘制建议使用requestAnimationFrame
  2. 跨域问题:若涉及图片合成需设置crossOrigin=“anonymous”
  3. 移动端适配:添加CSS样式防止触摸滚动
canvas {
  touch-action: none;
  background: #f8f8f8;
}

四、完整代码Demo示例

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <style>
            * {
                margin: 0 auto;
                padding: 0;
            }
            button { 
                padding: 3px 5px;
                margin: 5px; 
            }
        </style>
    </head>
    <body>
        <canvas id="sign"></canvas>
        <div>
            <button onclick="cancel()">取消</button>
            <button onclick="save()">保存</button>
        </div>
    </body>
    <script>
        const canvas = document.querySelector('canvas');
        canvas.width = 600;
        canvas.height = 300;
        canvas.style.borderRadius = '5px';
        canvas.style.border = '1px solid #a6a9ad';
        const ctx = canvas.getContext('2d');

        // 高清屏适配
        const scale = window.devicePixelRatio;
        canvas.width = 600 * scale;
        canvas.height = 300 * scale;
        ctx.scale(scale, scale);

        ctx.lineWidth = 3; //线宽
        ctx.strokeStyle = 'black'; //线颜色
        ctx.lineCap = 'round'; //线条的结束端点样式
        ctx.lineJoin = 'round'; //两条线相交时,所创建的拐角类型

		// 检测移动设备
        const mobileStatus = /Mobile|Android|iPhone/i.test(navigator.userAgent);

        const start = (event) => {
            const { offsetX, offsetY, pageX, pageY } = mobileStatus
                ? event.changedTouches[0]
                : event;
            ctx.beginPath(); //起始一条路径,或重置当前路径
            ctx.moveTo(pageX, pageY); //把路径移动到画布中的指定点,不创建线条
            window.addEventListener(mobileStatus ? 'touchmove' : 'mousemove', draw);
        };

        const draw = (event) => {
            const { pageX, pageY } = mobileStatus ? event.changedTouches[0] : event;
            ctx.lineTo(pageX, pageY); //添加一个新点,然后在画布中创建从该点到最后指定点的线条
            ctx.stroke(); //绘制已定义的路径
        };
        const cloaseDraw = () => {
            window.removeEventListener('mousemove', draw);
        };

        window.addEventListener(mobileStatus ? 'touchstart' : 'mousedown', start);
        window.addEventListener(mobileStatus ? 'touchend' : 'mouseup', cloaseDraw);

        const cancel = () => {
            ctx.clearRect(0, 0, 600, 300); //在给定的矩形内清除指定的像素
        };

        const save = () => {
            canvas.toBlob((blob) => {
                const date = Date.now().toString();
                const a = document.createElement('a');
                a.download = `${date}.png`;
                a.href = URL.createObjectURL(blob);
                a.click();
                a.remove();
            });
        };
    </script>
</html>


五、总结

本文实现的电子签名方案具备以下特点:

  1. 支持移动端与PC端双平台
  2. 输出为PNG透明图片
  3. 代码精简
  4. 无第三方依赖

实际项目中需结合后端实现签名验证、添加时间戳等扩展功能。可继续丰富代码逻辑:

  1. 添加Base64导出功能
  2. 实现笔锋效果(通过速度计算线宽)
  3. 添加本地存储自动保存

Canvas的绘图能力还能延伸应用于手写笔记、电子批注等场景。

在这里插入图片描述
如果你觉得这篇文章对你有帮助,请点赞 👍、收藏 👏 并关注我!👀
在这里插入图片描述


http://www.kler.cn/a/574268.html

相关文章:

  • P8707 [蓝桥杯 2020 省 AB1] 走方格
  • 【智能体架构:Agent】LangChain智能体类型ReAct、Self-ASK的区别
  • 鸿蒙Android4个脚有脚线
  • 道可云人工智能每日资讯|亚马逊云业务部门成立智能体人工智能团队
  • Unity3D WebGL内存优化与缓存管理
  • 使用jcodec库,访问网络视频提取封面图片上传至oss
  • [BD青训项目]介绍
  • vue3中子组件获取父组件的name,父组件不做修改动作
  • 算法探秘:盛最多水的容器问题
  • Oracle数据导入导出小工具(主要用于导入导出小批量含大字段的数据)
  • 快速启动 vue 开发环境
  • 特斯拉FSD(全自动驾驶)功能概述
  • 迷你世界脚本文字板接口:Graphics
  • centos7服务器 Java和Hadoop安装教程,用VMware和finalshell
  • 【C++教程】C++中的基本数据类型
  • 【每日学点HarmonyOS Next知识】Web上传文件、监听上下左右区域连续点击、折叠悬停、字符串相关、播放沙盒视频
  • VsCode/Cursor workbench.desktop.main.js 的入口
  • VS2019,VCPKG - 为VS2019添加VCPKG
  • 【启发式算法】Dijkstra算法详细介绍(Python)
  • 高频 SQL 50 题(基础版)| 高级字符串函数 / 正则表达式 / 子句:1667. 修复表中的名字