来源:
公司的一个需求,需要给新注册的会员和客商需要增加签署协议功能;
之前的思路:
1、使用vue-signature-pad来实现电子签名,但是安卓手机不兼容;
2、uniapp插件市场来实现,但是对HBuilderX的版本有要求,无奈公司只能使用3.4.7版本;
前面2种思路都不行那就用Canvas来实现
Canvass
canvas 是 html 的一个标签,它可以结合 JavaScript 提供的 canvasApi 来绘制各种各样的图形。canvas 主要用于绘制 2D 图形。注意:当你不设置 canvas 的宽高时,它的默认宽高是 300px、150px。
需要实现的功能如图:
代码实现
EctronicSignature.vue
<template>
<view class="ectronic-signature">
<canvas
class="board-canvas"
canvas-id="drawCanvas"
disable-scroll="true"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
></canvas>
<view class="btn">
<u-button type="success" @click="saveImage" text="保存" class="btnItem"></u-button>
<u-button @click="clearDrawBoard" text="清空" class="btnItem"></u-button>
</view>
</view>
</template>
<style lang="scss" scoped>
……
</style>
EctronicSignature.ts
curDrawArr: any = [];
startX: any = 0;
startY: any = 0;
ctx: any = {};
begin: Boolean = false;
bgColor: String = 'white'; //背景色
lineWidth: Number = 4; //画笔宽度
penMode: Boolean = true; //打开画笔 开关
currentTab: any = 1;
currentIndex: any = 0;
selectPointer: any = []; //所有选中的线
cache: any = '';
points: any = [];
onReady() {
this.ctx = uni.createCanvasContext('drawCanvas', this); // 获取canvas上下文对象 vue的写法是先获取,之后通过.getContext("2d")来获取上下文
this.cache = new Map(); // 缓存
this.ctx.setLineWidth(this.lineWidth); // 设置画笔的粗细
}
// ctx.draw()绘制结果呈现在canvas
// isReverse: 是否保留之前的像素
draw(isReverse = false, cb) {
this.ctx.draw(isReverse, () => {
if (cb && typeof cb == 'function') {
cb();
}
});
}
// 绘画 开始
touchStart(e) {
console.log('绘画开始', e.touches[0].x, e.touches[0].y);
// customPrint('我能够进行绘制');
if (this.penMode) {
this.lineBegin(e.touches[0].x, e.touches[0].y);
this.lineAddPoint(e.touches[0].x, e.touches[0].y);
this.draw(true, ''); // 呈现画面
}
this.points.push([e.touches[0].x, e.touches[0].y]); // 存储绘制的点
this.selectPointer.push([[e.touches[0].x, e.touches[0].y]]);
}
// 开始绘制线条
lineBegin(x, y) {
this.begin = true; // 作为一个标记代表开始绘画
this.ctx.beginPath(); // 开始创建一个路径
this.startX = x;
this.startY = y;
this.ctx.moveTo(this.startX, this.startY); // 将路径移动到画布中的指定点
this.lineAddPoint(x, y); // 绘制线条中间添加
}
// 绘画 移动
touchMove(e) {
console.log('绘画移动', e.touches[0].x, e.touches[0].y);
if (this.begin) {
if (this.penMode) {
this.lineAddPoint(e.touches[0].x, e.touches[0].y);
this.draw(true, '');
}
this.points.push([e.touches[0].x, e.touches[0].y]);
this.selectPointer[this.selectPointer.length - 1].push([e.touches[0].x, e.touches[0].y]);
}
}
// 绘制线条中间添加点
lineAddPoint(x, y) {
this.ctx.moveTo(this.startX, this.startY);
this.ctx.lineTo(x, y); // 增加一个新的点,然后创建一条从上次指定点到目标点的线
this.ctx.stroke(); // 画出当前路径的边框
this.startX = x;
this.startY = y;
}
// 绘画 结束
touchEnd(e) {
if (this.penMode) {
// this.curDrawArr = [];
this.points = [];
this.lineEnd();
}
}
// 绘制线条结束
lineEnd() {
this.ctx.closePath(); // 关闭一个路径,关闭路径会连接起点和终点
this.begin = false;
}
// 检验画布是否为空
isCanvasBlank(canvas) {
const blank = document.createElement('canvas'); //系统获取一个空canvas对象
blank.width = canvas.width;
blank.height = canvas.height;
return canvas.toDataURL() == blank.toDataURL(); // .toDataURL()将canvas对象转换为base64位编码
}
// 保存 图片数据
saveImage() {
const _this = this;
uni.canvasToTempFilePath({
canvasId: 'drawCanvas',
success: function(res) {
console.log('res ==>', res);
// 在H5平台下,tempFilePath 为 base64
// this.uploadimage(res.tempFilePath,"save",page.currentTab)
const canvas = document.getElementsByTagName('canvas')[0];
if (_this.isCanvasBlank(canvas)) {
uni.showToast({
title: '请签字!!!',
icon: 'none',
});
return false;
}
},
});
}
//清除
clearDrawBoard() {
this.ctx.draw();
this.selectPointer = [];
}
}
推荐资料
https://www.runoob.com/html/html5-canvas.html
https://uniapp.dcloud.net.cn/component/canvas.html#canvas
https://open.dingtalk.com/document/personalapp/setlinewidth