前言
在我们公司偶尔会遇到一些需要用户手写签名,用于后续签署合同/文件。本篇文章将说明一下这种效果核心的实现思路,真的非常简单!
具体实现
我们公司的产品实现效果如下图所示:
要实现这个功能我们需要借助canvas,它是HTML5提供的一种绘图API,它可以让开发者在网页中创建和操作画布,从而实现绘图和图像处理的功能。在H5手写签名的场景中,我们可以通过监听鼠标或触摸事件,在canvas上绘制用户的笔迹,记录下用户的手写签名,然后在canvas上监听用户的触摸或鼠标事件,实时绘制用户的笔迹,以便用户在手写签名时能够实时看到自己的笔迹。
开始听说 canvas 时,它给我的印象是非常困难的,但只要我们认识下面几个核心api就可以轻松完成该功能。
canvas 就是一个html标签:<canvas id="canvas"></canvas>
getContext('2d'): 获取canvas的2D绘图上下文。通过调用该方法,可以获取到一个绘图上下文对象,该对象提供了一系列的方法和属性用于绘制图形。只有获取到了绘图上下文我们才可以调用下面的api。beginPath():用于开始一个新的路径,它会清除之前的路径并准备开始新的路径绘制。该方法在手指按下时触发标志着用户开始绘画了。lineTo(x, y): 绘制一条从当前位置到指定位置的线段。该方法在用户手指移动时调用,实时获取用户手指在画布移动的坐标,把坐标传给lineTo记录轨迹。stroke(): 绘制当前路径的边框,只有调用了这个方法才能真正的绘画出图案在画布上。clearRect(x, y, width, height): 清除指定矩形区域内的内容。
h5端手写签名dome代码,在pc端测试的时候需要f12模拟手机。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="box" style="width: 100%;height: 200px;border: 1px solid #ccc;">
<canvas id="canvas"></canvas>
</div>
<button id="rewrite">重写</button>
<button id="confirm">确定</button>
<div style="margin-top: 100px;">
<h3>
生成的签名
</h3>
<img src="">
</div>
<script>
var sign = '' //用于存储最后生成的签名
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//因为touchstart/touchmove只能获取到相对于屏幕的位置,无法直接获取当前手指相对于画布的位置。
//而ctx.lineTo()则需要传相对于画布的位置,所以需要用手指相对于屏幕-offsetLeft得到相对于画布的位置。
var canvasOffsetLeft = canvas.offsetLeft;
var canvasOffsetTop = canvas.offsetTop;
canvas.width = box.offsetWidth // 画布的宽
canvas.height = box.offsetHeight // 画布的高
// 移动端需要监听touchstart,如果是pc则可以监听鼠标的事件mousedown
document.querySelector('canvas').addEventListener('touchstart', (event) => { // 移动端需要监听touchstart,如果是pc则可以监听鼠标的事件mousedown 直接e.offsetX
event.preventDefault() // 防止书写过程中页面抖动
ctx.beginPath()
})
// 移动端需要监听touchmove,如果是pc则可以监听鼠标的事件mousemove
document.querySelector('canvas').addEventListener('touchmove', (event) => { // 移动端需要监听touchmove,如果是pc则可以监听鼠标的事件mousemove 直接e.offsetX
event.preventDefault() // 防止书写过程中页面抖动
// 计算出手指相对与画布的位置
ctx.lineTo(event.touches[0].pageX - canvasOffsetLeft, event.touches[0].pageY - canvasOffsetTop);
ctx.stroke();// 只有调用该方法才会真实的绘制出线条
})
// 重写
document.querySelector('#rewrite').addEventListener('click', () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);// 清空绘制的内容
})
// 确定
document.querySelector('#confirm').addEventListener('click', () => {
sign = canvas.toDataURL();// 把绘制完成的canvas转换为base64
document.querySelector('img').src = sign
console.log(sign)
})
</script>
</body>
</html>
实现效果如下图所示:
需要注意的是在pc和h5需要监听不同的事件,h5如上面代码监听touchstart和touchmove,pc端则需要对应监听mousedown和mousemove,否则会导致事件触发异常。
可能竖屏签名给用户的体验并不好,我们也可以支持用户旋转成横屏签名。用下面这段代码监听用户的屏幕旋转情况,从而改变样式使画面宽度更大。核心逻辑无变化就不赘述了。
window.onorientationchange = function () {
if (window.orientation == 90 || window.orientation == -90) {
console.info('横屏了')
} else {
console.info('竖屏了')
}
}
结尾
本篇文章是我学习canvas的记录,代码非常简单,非常适合熟悉canvas。希望大家都能有所收获!