• uniapp使用Canvas实现电子签名


    来源:

    公司的一个需求,需要给新注册的会员和客商需要增加签署协议功能;

    之前的思路:
    1、使用vue-signature-pad来实现电子签名,但是安卓手机不兼容;
    2、uniapp插件市场来实现,但是对HBuilderX的版本有要求,无奈公司只能使用3.4.7版本;

    前面2种思路都不行那就用Canvas来实现

    Canvass

    canvas 是 html 的一个标签,它可以结合 JavaScript 提供的 canvasApi 来绘制各种各样的图形。canvas 主要用于绘制 2D 图形。注意:当你不设置 canvas 的宽高时,它的默认宽高是 300px、150px。

    需要实现的功能如图:
    在这里插入图片描述

    代码实现

    EctronicSignature.vue
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    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 = [];
      }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128

    推荐资料

    https://www.runoob.com/html/html5-canvas.html
    https://uniapp.dcloud.net.cn/component/canvas.html#canvas
    https://open.dingtalk.com/document/personalapp/setlinewidth

  • 相关阅读:
    git常用操作
    C++面试八股文:技术勘误
    【2023高教社杯数学建模国赛】ABCD题 问题分析、模型建立、参考文献及实现代码
    第十章 异常
    API商品接口对接使用:从理论到实践
    掌握高等数学、线性代数、概率论所需数学知识及标题建议
    我的这个c++程序到底是怎么了?(相关搜索:for循环|主线程)
    【微服务 从0开始 】Spring Cloud 配置文件
    BGP和MPLS综合实验来啦!超级详细!一看就会,附有完整源码
    外包干了3个月,技术退步明显。。。。。
  • 原文地址:https://blog.csdn.net/qq_48701993/article/details/134442828