想要实现一个电子签名,可以支持鼠标签名,还能类似书法效果线条有粗有细,同时可以导出成图片.
一、实现连贯的划线
1)首先需要注册鼠标下压、鼠标放开、鼠标移出和鼠标移动事件,通过鼠标下压赋值downFlag标记开始绘制
2) 鼠标移动时,将当前坐标位置传入绘制方法,通过lineTo方法实现绘制
/** * 按下鼠标启动绘制标记 **/ canvas.addEventListener('mousedown', e => { preCoord = [e.offsetX, e.offsetY, new Date().getTime()]; downFlag = true; }) /** * 鼠标松开结束绘制 **/ canvas.addEventListener('mouseup', e => { downFlag = false; }) canvas.addEventListener('mouseout', () => { downFlag = false; }) /** * 鼠标移动时绘制文字 **/ canvas.addEventListener('mousemove', e => { if (downFlag) { const coord = [e.offsetX, e.offsetY]; drawSign(coord); preCoord = [...coord, new Date().getTime()]; } })
3) 启动线的绘制,其中注释的线段
function drawSign(coord) { // 为了实现阶段性线的不同粗细程度,所以每次绘制必须重新开始一段路径 ctx.beginPath(); getColor(coord); ctx.lineTo(...preCoord); ctx.lineTo(...coord); ctx.stroke(); ctx.closePath(); }
二、为了美观,实现书法类似的效果,需要设每个线段设置不同的宽度才可以
1)根据每两个事件点的时间差计算一个倍数关系,然后乘以一个基础宽度就可以得到不同的宽度,本文实现的效果是绘制越慢线条越宽,越快线条越窄
2) 设置线的连接方式和线端点效果,使整个线条看起来更加圆滑
/** * 根据绘制时间差设置绘制线宽 **/ function getColor(coord) { if (preCoord.length === 0) { return; } // 当前是计算的每两个点的时间差是五毫秒的倍数 const tempMulti = (new Date().getTime() - preCoord[2]) / 5; if (tempMulti > multi) { multi = multi * 1.4; } else { multi = multi * 0.9; } if (multi > 5) { multi = 5; } if (multi < 1) { multi = 1; } ctx.lineWidth = 2 * multi; // 通过设置连线效果和线端点效果可以使线条看起来更圆滑 ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.strokeStyle = 'rgba(153, 153, 153, 1)'; }
三、下面奉上完整的代码和效果图
<!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>signature</title> </head> <body style="text-align: center;"> <div> <button id="output" style="margin: 10px;">导出</button> </div> <canvas id="canvas" width="800" height="800" style="width: 800px;height: 800px;border: 1px solid gray;"></canvas> </body> </html> <script type="module"> window.onload = (() => { const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); // 上一个绘制点的坐标 let preCoord = []; // 绘制启动标志 let downFlag = false; // 初始线宽 let multi = 5; /** * 按下鼠标启动绘制标记 **/ canvas.addEventListener('mousedown', e => { preCoord = [e.offsetX, e.offsetY, new Date().getTime()]; downFlag = true; }) /** * 鼠标松开结束绘制 **/ canvas.addEventListener('mouseup', e => { downFlag = false; }) canvas.addEventListener('mouseout', () => { downFlag = false; }) /** * 鼠标移动时绘制文字 **/ canvas.addEventListener('mousemove', e => { if (downFlag) { const coord = [e.offsetX, e.offsetY]; drawSign(coord); preCoord = [...coord, new Date().getTime()]; } }) document.getElementById('output').addEventListener('click', e => { const a = document.createElement('a'); a.href = canvas.toDataURL('image/png'); a.download = 'signature.png'; a.click(); }) /** * 根据绘制时间差设置绘制线宽 **/ function getColor(coord) { if (preCoord.length === 0) { return; } // 当前是计算的每两个点的时间差是五毫秒的倍数 const tempMulti = (new Date().getTime() - preCoord[2]) / 5; if (tempMulti > multi) { multi = multi * 1.4; } else { multi = multi * 0.9; } if (multi > 5) { multi = 5; } if (multi < 1) { multi = 1; } ctx.lineWidth = 2 * multi; // 通过设置连线效果和线端点效果可以使线条看起来更圆滑 ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.strokeStyle = 'rgba(153, 153, 153, 1)'; } function drawSign(coord) { // 为了实现阶段性线的不同粗细程度,所以每次绘制必须重新开始一段路径 ctx.beginPath(); getColor(coord); ctx.lineTo(...preCoord); ctx.lineTo(...coord); ctx.stroke(); ctx.closePath(); } }) </script>完整代码
标签:粗细,canvas,鼠标,ctx,multi,coord,电子签名,绘制 From: https://www.cnblogs.com/codeOnMar/p/17349988.html