Canvas实现h5手写签名,看起来容易实际上一点不难

1,418 阅读4分钟

前言

在我们公司偶尔会遇到一些需要用户手写签名,用于后续签署合同/文件。本篇文章将说明一下这种效果核心的实现思路,真的非常简单!

具体实现

我们公司的产品实现效果如下图所示:

要实现这个功能我们需要借助canvas,它是HTML5提供的一种绘图API,它可以让开发者在网页中创建和操作画布,从而实现绘图和图像处理的功能。在H5手写签名的场景中,我们可以通过监听鼠标或触摸事件,在canvas上绘制用户的笔迹,记录下用户的手写签名,然后在canvas上监听用户的触摸或鼠标事件,实时绘制用户的笔迹,以便用户在手写签名时能够实时看到自己的笔迹。

开始听说 canvas 时,它给我的印象是非常困难的,但只要我们认识下面几个核心api就可以轻松完成该功能。

canvas 就是一个html标签:<canvas id="canvas"></canvas>

  1. getContext('2d'): 获取canvas的2D绘图上下文。通过调用该方法,可以获取到一个绘图上下文对象,该对象提供了一系列的方法和属性用于绘制图形。只有获取到了绘图上下文我们才可以调用下面的api。
  2. beginPath():用于开始一个新的路径,它会清除之前的路径并准备开始新的路径绘制。该方法在手指按下时触发标志着用户开始绘画了。
  3. lineTo(x, y): 绘制一条从当前位置到指定位置的线段。该方法在用户手指移动时调用,实时获取用户手指在画布移动的坐标,把坐标传给lineTo记录轨迹。
  4. stroke(): 绘制当前路径的边框,只有调用了这个方法才能真正的绘画出图案在画布上。
  5. 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如上面代码监听touchstarttouchmove,pc端则需要对应监听mousedownmousemove,否则会导致事件触发异常。

可能竖屏签名给用户的体验并不好,我们也可以支持用户旋转成横屏签名。用下面这段代码监听用户的屏幕旋转情况,从而改变样式使画面宽度更大。核心逻辑无变化就不赘述了。

    window.onorientationchange = function () {
      if (window.orientation == 90 || window.orientation == -90) {
        console.info('横屏了')
      } else {
        console.info('竖屏了')
      }
    }

结尾

本篇文章是我学习canvas的记录,代码非常简单,非常适合熟悉canvas。希望大家都能有所收获!