前端实现电子签名(web、移动端)通用组件(canvas实现)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | <!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; padding: 0; } </style> </head> <body> <canvas></canvas> <div> <button onclick= "cancel()" >取消</button> <button onclick= "save()" >保存</button> </div> </body> <script> // 配置内容 const config = { width: 400, // 宽度 height: 200, // 高度 lineWidth: 5, // 线宽 strokeStyle: 'red' , // 线条颜色 lineCap: 'round' , // 设置线条两端圆角 lineJoin: 'round' , // 线条交汇处圆角 } // 获取canvas 实例 const canvas = document.querySelector( 'canvas' ) // 设置宽高 canvas.width = config.width canvas.height = config.height // 设置一个边框 canvas.style.border = '1px solid #000' // 创建上下文 const ctx = canvas.getContext( '2d' ) // 设置填充背景色 ctx.fillStyle = 'transparent' // 绘制填充矩形 ctx.fillRect( 0, // x 轴起始绘制位置 0, // y 轴起始绘制位置 config.width, // 宽度 config.height // 高度 ); // 保存上次绘制的 坐标及偏移量 const client = { offsetX: 0, // 偏移量 offsetY: 0, endX: 0, // 坐标 endY: 0 } // 判断是否为移动端 const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent)) // 初始化 const init = event => { // 获取偏移量及坐标 const { offsetX, offsetY, pageX, pageY } = mobileStatus ? event.changedTouches[0] : event // 修改上次的偏移量及坐标 client.offsetX = offsetX client.offsetY = offsetY client.endX = pageX client.endY = pageY // 清除以上一次 beginPath 之后的所有路径,进行绘制 ctx.beginPath() // 根据配置文件设置相应配置 ctx.lineWidth = config.lineWidth ctx.strokeStyle = config.strokeStyle ctx.lineCap = config.lineCap ctx.lineJoin = config.lineJoin // 设置画线起始点位 ctx.moveTo(client.endX, client.endY) // 监听 鼠标移动或手势移动 window.addEventListener(mobileStatus ? "touchmove" : "mousemove" , draw) } // 绘制 const draw = event => { // 获取当前坐标点位 const { pageX, pageY } = mobileStatus ? event.changedTouches[0] : event // 修改最后一次绘制的坐标点 client.endX = pageX client.endY = pageY // 根据坐标点位移动添加线条 ctx.lineTo(pageX , pageY ) // 绘制 ctx.stroke() } // 结束绘制 const cloaseDraw = () => { // 结束绘制 ctx.closePath() // 移除鼠标移动或手势移动监听器 window.removeEventListener( "mousemove" , draw) } // 创建鼠标/手势按下监听器 window.addEventListener(mobileStatus ? "touchstart" : "mousedown" , init) // 创建鼠标/手势 弹起/离开 监听器 window.addEventListener(mobileStatus ? "touchend" : "mouseup" , cloaseDraw) // 取消-清空画布 const cancel = () => { // 清空当前画布上的所有绘制内容 ctx.clearRect(0, 0, config.width, config.height) } // 保存-将画布内容保存为图片 const save = () => { // 将canvas上的内容转成blob流 canvas.toBlob(blob => { // 获取当前时间并转成字符串,用来当做文件名 const date = Date.now().toString() // 创建一个 a 标签 const a = document.createElement( 'a' ) // 设置 a 标签的下载文件名 a.download = `${date}.png` // 设置 a 标签的跳转路径为 文件流地址 a.href = URL.createObjectURL(blob) // 手动触发 a 标签的点击事件 a.click() // 移除 a 标签 a.remove() }) } </script> </html> |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了