持续创作,加速成长!这是我参与「掘金日新计划 · 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签名的demo,虽然是pc端的,但小程序等也可以借鉴一下思路,基本都是差不多的,差别在于api而已。然后今天还试了一下码上掘金,怎么说呢,没有办法引用本地图片我不是很认可,只能做点简单的。
ps:我是地霊殿__三無,期待和你共同进步。