uniapp+canvas实现手写签字

借鉴文章

<template>
  <view @touchmove.stop.prevent="moveHandle">
    <view class="signature" v-show="showCanvas">
      <canvas
        class="mycanvas"
        canvas-id="mycanvas"
        @touchstart="touchstart"
        @touchmove="touchmove"
        @touchend="touchend"
      ></canvas>
      <view class="footer">
        <view class="left" @click="finish">确认上传</view>
        <view class="right" @click="clear">清除笔迹</view>
      </view>
    </view>
  </view>
</template>

<script>
import Util from "@/utils/httpUtil.js";
import Local from "@/utils/local.js";
var x = 20;
var y = 20;
export default {
  data() {
    return {
      showCanvas: false,
      ctx: "", //绘图图像
      points: [], //路径点集合
      signature: ""
    };
  },
  mounted() {},
  onShow() {
    this.createCanvas();
    let that = this;
    setTimeout(function() {
      // 笔迹反显
      if (Local.local.getItem("canvasPath")) {
        let imgPath = Local.local.getItem("canvasPath");
        const sInfo = uni.getSystemInfoSync();
        that.ctx.drawImage(
          imgPath,
          0,
          0,
          sInfo.windowWidth,
          sInfo.windowHeight
        );
        that.ctx.draw(true);
      }
    }, 500);
  },
  methods: {
    moveHandle() {},
    //关闭并清空画布
    close: function() {
      this.showCanvas = false;
      this.clear();
    },
    //创建并显示画布
    createCanvas: function() {
      this.showCanvas = true;

      this.ctx = uni.createCanvasContext("mycanvas", this); //创建绘图对象

      //设置画笔样式
      this.ctx.lineWidth = 4;
      this.ctx.lineCap = "round";
      this.ctx.lineJoin = "round";
    },
    //触摸开始,获取到起点
    touchstart: function(e) {
      let startX = e.changedTouches[0].x;
      let startY = e.changedTouches[0].y;
      let startPoint = { X: startX, Y: startY };
      this.points.push(startPoint);
      //每次触摸开始,开启新的路径
      this.ctx.beginPath();
    },

    //触摸移动,获取到路径点
    touchmove: function(e) {
      let moveX = e.changedTouches[0].x;
      let moveY = e.changedTouches[0].y;
      let movePoint = { X: moveX, Y: moveY };
      this.points.push(movePoint); //存点
      let len = this.points.length;
      if (len >= 2) {
        this.draw(); //绘制路径
      }
    },

    // 触摸结束,将未绘制的点清空防止对后续路径产生干扰
    touchend: function() {
      this.points = [];
    },

    /* ***********************************************
        #   绘制笔迹
        #   1.为保证笔迹实时显示,必须在移动的同时绘制笔迹
        #   2.为保证笔迹连续,每次从路径集合中区两个点作为起点(moveTo)和终点(lineTo)
        #   3.将上一次的终点作为下一次绘制的起点(即清除第一个点)
        ************************************************ */
    draw: function() {
      let point1 = this.points[0];
      let point2 = this.points[1];
      this.points.shift();
      this.ctx.moveTo(point1.X, point1.Y);
      this.ctx.lineTo(point2.X, point2.Y);
      this.ctx.stroke();
      this.ctx.draw(true);
    },

    //清空画布
    clear: function() {
      let that = this;
      uni.getSystemInfo({
        success: function(res) {
          let canvasw = res.windowWidth;
          let canvash = res.windowHeight;
          that.ctx.clearRect(0, 0, canvasw, canvash);
          that.ctx.draw(true);
        }
      });
    },
    //完成绘画并保存到本地
    finish: function() {
      let that = this;
      uni.canvasToTempFilePath({
        canvasId: "mycanvas",
        success: function(res) {
          console.log(res);
          Local.local.setItem("canvasPath", res.tempFilePath);
          uni.uploadFile({
            url: Util.fileUrl + "/file/objects", //仅为示例,非真实的接口地址
            filePath: res.tempFilePath,
            name: "file",
            header: {
              authorization: Local.local.getItem("token")
            },
            success: uploadFileRes => {
              let data = JSON.parse(uploadFileRes.data).data;
              console.log(data);

              Local.local.setItem("signImg", data.uri);
              that.clear();
              that.$Common.user.linkBack(1);
            }
          });
        }
      });
    }
  }
};
</script>

<style>
.signature {
  position: fixed;
  top: 10px;
  left: 2%;
  z-index: 999;
  width: 96%;
}
page {
  background: #fff;
}
.container {
  padding: 20rpx 0 120rpx 0;
  box-sizing: border-box;
}
.title {
  height: 50upx;
  line-height: 50upx;
  font-size: 16px;
}
.mycanvas {
  width: 100%;
  height: calc(100vh - 220upx);
  background-color: #ececec;
}
.footer {
  font-size: 14px;
  height: 150upx;
  display: flex;
  justify-content: space-around;
  align-items: center;
}
.left,
.right{
  line-height: 100upx;
  height: 100upx;
  width: 300upx;
  text-align: center;
  font-weight: bold;
  color: white;
  border-radius: 5upx;
}
.left {
  background: #007aff;
}
.right {
  background: orange;
}
</style>

// httpUtil.js
const host = `https://xxx/`;
let fileUrl = 'https://xxx/'; //文件服务
let imageUrl = 'https://xxx/'; //图片文件服务
let caseHost = "https://xxx/"
const fingerPkg = 'com.xxx' // 指纹采集包名

const reportBook = imageUrl + "xx" // 告知书地址

const androidPkgUrl = imageUrl + "xxxx" // 安卓安装包地址


const pageSize = 10;


var quanliyiwugaozhishu = 'https://xxx' // 权利义务告知书
var shigurendingshu = 'https://xxx' //事故认定书
var searchLetter = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
import Local from '@/utils/local.js';
import Common from '@/utils/common.js';
let httpUtil = {
    getData: (url, data, method, callBack, msg) => {
        // 检测网络是否可用
        uni.getNetworkType({
            success: function (res) {
                let networkType = res.networkType;
                if (networkType == 'none') {
                    // 无网络
                    uni.showToast({
                        title: '无网络',
                        icon: 'none',
                        duration: 500
                    })
                } else {
                    var header = {
                        'Content-Type': 'application/json'
                    }

                    var urlString = "", dataNew = '';
                    if ((method == 'get' || method == 'GET') && url.indexOf('getWxConfig') < 0) {
                        // get 请求讲请求数据拼接在url上
                        for (var key in data) {
                            if (urlString != '') {
                                urlString = urlString + '&' + key + '=' + data[key]
                            } else {
                                urlString = urlString + '?' + key + '=' + data[key]
                            }
                        }
                        if (urlString == '') {
                            urlString = url;
                        } else {
                            urlString = url + urlString
                        }
                    } else {
                        dataNew = JSON.stringify(data)
                        urlString = url;
                    }

                    if (url.indexOf('getWxConfig') < 0 && url.indexOf('oauth2wx') < 0) {
                        if (Local.local.getItem("token") != '' && Local.local.getItem("token") != undefined) {
                            header.Authorization = Local.local.getItem("token")
                        }

                    }

                    uni.request({
                        method: method,
                        url: urlString,
                        data: dataNew,
                        header: header,
                        success: res => {
                            console.log(res)
                            if (msg == '更新') {
                                callBack(res.data)
                                return
                            }
                            if (urlString.indexOf('qywx/oauth2wx') >= 0) {
                                callBack(res.data)
                            }
                            if (res.header.token != '' && res.header.token != undefined) {
                                // 更新token
                                Local.local.setItem("token", res.header.token)
                            }
                            if (res.data.success == true) {
                                callBack(res.data)
                            } else {
                                if (url.indexOf("getWxConfig") >= 0) {
                                    Local.local.removeItem('perm')
                                    callBack("error")
                                } else {

                                    if (res.data.errMessage != null && res.data.errMessage != "" && res.data.errMessage != undefined) {
                                        uni.showToast({
                                            title: res.data.errMessage,
                                            icon: 'none',
                                            duration: 2000
                                        })
                                    }

                                    if (res.data.errCode == "InvalidToken") {
                                        // token 过期到登录界面
                                        // #ifdef APP-PLUS
                                        wx.clearStorage()
                                        setTimeout(function () {
                                            uni.redirectTo({
                                                url: "/pages/app/login/login"
                                            })
                                        }, 1000)
                                        // #endif
                                    }

                                }
                                return;
                            }
                        },
                        fail: err => {
                            uni.showToast({
                                title: err.message,
                                icon: 'none',
                                duration: 2000
                            })
                        }
                    })
                }
            }
        })
    }
}

// 输出
module.exports = {
    host: host,
    httpUtil: httpUtil,
    imageUrl: imageUrl,
    caseHost: caseHost,
    pageSize: pageSize,
    fileUrl: fileUrl,
    searchLetter: searchLetter,
    fingerPkg: fingerPkg,
    reportBook: reportBook,
    androidPkgUrl: androidPkgUrl,
    quanliyiwugaozhishu: quanliyiwugaozhishu,
    shigurendingshu: shigurendingshu
}
// local.js
let local = {
    // 同步获取存储数据
    getItem:key =>{
        return wx.getStorageSync(key);
    },
    // 异步获取存储数据
    getItemAsyn:(key,callBck) =>wx.getStorage({
        key: key,
        success:function(res){
            callBck(res.data)
        }
    }),
    // 异步设置存储数据
    setItem:(key,value) =>wx.setStorage({
      key: key,
      data: value,
    }),
    setItemNow:(key,value)=>wx.setStorageSync(key, value),
    // 情况缓存
    clear:() => wx.clearStorage(),
    // 删除异步存储数据
    removeItem:key => {
        let guard;
        wx.removeStorage({
            key: key,
            success: () => guard = true,
            fail:  () => guard = false,
        })
        return guard;
    },
    // 异步获取storage信息
    getSize:() =>{
        let size;
        wx.getStorageInfo({
            success: res => size = res.currentSize
        })
    },
}

module.exports = {
    local: local
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351