pc端实现canvas签名

221 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

一、前言

今天在手机端理赔的时候,看到一个手写签名的,感觉还挺有意思的,就想着pc端来实现一下。

思路也比较简单,基本是canvas绘画,配合鼠标事件完成签名,然后触发保存方法,本项目是转base64之后,通过a标签下载到本地。若不想下载在本地,可以直接把base64放到blob文件中,传到后端服务器上进行存储。

二、过程

1、建立好元素和样式

就一个canvas元素和几个按钮标签,都定义好id,因为我使用的是原生js,所以最好通过id找到元素,来挂载相应的点击事件。

<canvas id="canvas" width="500" height="500"></canvas>
<div class="button">
  <div class="btn" id="restart">重新开始</div>
  <div class="btn"  id="save">保存图片</div>
</div>

2、获取canvas对象,同时定好绘画的各种属性

拿到canvas对象,设置好线宽和颜色(也可以整成动态变量,这样可以自定义更换颜色和线宽),声明一个变量MouseMoveStatus来判断是否进入画画模式,x,y则是来确定绘画点的位置的。

 // 获取canvas对象
var canvasdemo = document.getElementById('canvas')
var ctx = canvasdemo.getContext('2d')
// 设置画线属性
var lineWidth = 3
var lineColor = '#fff'
// 设置是否开启画画状态
var MouseMoveStatus = false
// 线条位置
var X,Y

3、页面加载完毕之后,初始化函数

原生js可以调用window.onload方法,来确定调用时机。不过当我copy进码上掘金的时候,发现这个方法失效了,所以在码上掘金里我是改用了定时器的做法,目的都是确保在页面加载完毕之后,能调用init函数,完成初始化。

// 当窗口加载完毕之后,onload周期调用init
window.onload = function () {
  init()
}

4、init函数

在init函数,我们需要定义好canvas的四个鼠标事件,一个是当鼠标按下的瞬间,我们需要开启画画模式,同时调用画线函数drawLine,来绘画,当此时只需要更新xy坐标,不需要划线,所以我们传值false

// 按下的时候,开启画画模式,同时调用drawLine画画函数
  var down = (e) => {
    MouseMoveStatus = true
    drawLine(
      event.pageX - canvasdemo.offsetLeft,
      event.pageY - canvasdemo.offsetTop,
      false
    )}
    

一个是鼠标按下时移动,那就要开始在canvas上绘画了,此时持续调用drawLine函数,同步更新绘画状态。

// 按着移动的时候,开启画画模式,同时调用drawLine画画函数
let move = (e) => {
    if (MouseMoveStatus) {
      drawLine(
        event.pageX - canvasdemo.offsetLeft,
        event.pageY - canvasdemo.offsetTop,
        true
      )
    }
}

剩下的up和leave,一个是鼠标松开左键,一个鼠标移开canvas画布,那都直接取消绘画模式。

MouseMoveStatus = false

最后再把这四个时间,添加到canvas的监听事件中去。

// 开启canvas的监听事件
  canvasdemo.addEventListener("mousedown", down)
  canvasdemo.addEventListener("mousemove", move)
  canvasdemo.addEventListener("mouseup", up)
  canvasdemo.addEventListener("mouseleave", leave)

5、drawLine函数

drawLine使我们的画线函数,原理也比较简单,基本是调用canvas原有的api,只是先确定好每次绘画的样式,然后把xy坐标传入即可,其他交给api做就好。这里有个小问题,我在本地打开此次的demo,绘画是十分流畅的,而在码上掘金里,绘画却是断断续续的,感觉是被限制了性能一样,没办法帧帧调用drawLine方法。

//画线
function drawLine(x, y, isT) {
  if (isT) {
    ctx.beginPath()
    ctx.lineWidth = lineWidth //设置线宽状态
    ctx.strokeStyle = lineColor //设置线的颜色状态
    ctx.lineCap = 'round'
    ctx.lineJoin = "round"
    ctx.moveTo(X, Y)
    ctx.lineTo(X, Y)
    ctx.stroke()
    ctx.closePath()
  }
  // 每次移动都要更新坐标位置
  X = x
  Y = y
}

6、clearCanvas函数

提供一个清空函数,画错了可以重来。

//清空画图 重新开始
function clearCanvas() {
  ctx.beginPath()
  ctx.clearRect(0, 0, canvasdemo.width, canvasdemo.height)
  ctx.closePath() // 关闭绘画路径,此处关闭只是保险起见,可以不加
}

7、save函数

一般常见的都是,canvas转base64,然后可以利用a标签进行下载到本地进行保存,平时开发项目里则一般就是转换完base64之后,用blob流的方式上传给后端。

我们利用canvas自带的toDataURL方法,可以直接转换成base64,可以选定格式,质量,宽高等等。

// 转换成a标签下载
function save() {
  // canvas转base64
  var imgURL = canvasdemo.toDataURL({format: "image/png", quality:1, width:500, height:500})
  // 新建一个a标签
  var oA = document.createElement("a");
  oA.download = '签名'// 设置下载的文件名
  oA.href = imgURL
  document.body.appendChild(oA)
  oA.click() // 模拟点击a标签
  oA.remove() // 下载之后把创建的元素删除
}

8、效果

我先放个本地的版本。

canvas签名.gif

再放个码上掘金的版本,让大家自己体验一下。

三、小结

今天简单完成了一个canvas签名的demo,虽然是pc端的,但小程序等也可以借鉴一下思路,基本都是差不多的,差别在于api而已。然后今天还试了一下码上掘金,怎么说呢,没有办法引用本地图片我不是很认可,只能做点简单的。

ps:我是地霊殿__三無,期待和你共同进步。

微信图片_20221001074313.jpg