美文网首页
笔锋签字页移植微信小程序

笔锋签字页移植微信小程序

作者: Demonskp | 来源:发表于2020-01-17 13:04 被阅读0次

    签字页移植微信小程序

    最近领导提出了一个在手机上签字的需求,而且考虑其他的因素比较适合放到微信小程序当中去实现。因此对小程序端的签字canvas进行了一系列的研究。

    获取web端的签字

    web端的签字页面之前是写过的,不过当时需求简单就很简单写了。这次是领导的需求,因此还是做个效果比较好的。不重复造轮子,就直接在网上找了一个签字程序(现在忘了出自那里了)。

    sign-web.gif

    效果还是很不错的,相比于之前我自己简单写的版本,加入了通过速度控制笔锋大小,以及回撤功能。

    <!doctype html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <meta name="viewport" content="width=400">
        <title> canvas手写毛笔字效果 </title>
        <style type="text/css">
            body {
                margin: 0;
                padding: 0;
                text-align: center;
                background-color: #936;
            }
    
            #canvasId {
                background-color: #FFd;
            }
    
            .button {
                width: 140px;
                height: 60px;
                font-size: 20px;
            }
    
        </style>
    </head>
    
    <body>
        <h1>手写毛笔字效果-手机版</h1>
        <canvas id="canvasId" width="400" height="500"></canvas><br />
        <input type="button" value="全部清除" class="button" onclick="hw.clear();" />
        <input type="button" value="清除最后一笔" class="button" onclick="hw.historyBack();" />
        <script type="text/javascript">
            function Handwriting(id) {
                this.canvas = document.getElementById(id);
                this.ctx = this.canvas.getContext("2d");
                var on = ("ontouchstart" in document) ? {
                    start: "touchstart",
                    move: "touchmove",
                    end: "touchend"
                } : {
                    start: "mousedown",
                    move: "mousemove",
                    end: "mouseup"
                };
                this.canvas.addEventListener(on.start, this.downEvent.bind(this), false);
                this.canvas.addEventListener(on.move, this.moveEvent.bind(this), false);
                this.canvas.addEventListener(on.end, this.upEvent.bind(this), false);
                this.canvas.addEventListener("contextmenu", function (e) {
                    e.preventDefault()
                }, false);
                this.moveFlag = false;
                this.upof = {};
                this.radius = 0;
                this.has = [];
                this.startOf = null;
                this.lineMax = 30;
                this.lineMin = 3;
                this.linePressure = 1;
                this.smoothness = 80;
                this.history = [];
                this.setColor("rgba(0,0,0,0.25)");
            }
    
            Handwriting.prototype.clear = function () {
                this.history = [];
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
            }
    
            Handwriting.prototype.historyBack = function () {
                this.history.pop();
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                for (var i = 0; i < this.history.length; i++) {
                    var h = this.history[i];
                    for (var j = 0; j < h.length; j += 3) {
                        this.ctx.beginPath();
                        this.ctx.arc(h[j], h[j + 1], h[j + 2], 0, 2 * Math.PI, true);
                        this.ctx.fill();
                    }
                }
            }
    
            Handwriting.prototype.downEvent = function (e) {
                this.moveFlag = true;
                this.has = [];
                this.upof = this.getXY(e);
                this.startOf = this.upof;
            }
    
            Handwriting.prototype.moveEvent = function (e) {
                if (!this.moveFlag)
                    return;
                e.preventDefault();
                var of = this.getXY(e);
                var up = this.upof;
                var ur = this.radius;
                this.has.unshift({
                    time: new Date().getTime(),
                    dis: this.distance(up, of )
                });
                var dis = 0;
                var time = 0;
                for (var n = 0; n < this.has.length - 1; n++) {
                    dis += this.has[n].dis;
                    time += this.has[n].time - this.has[n + 1].time;
                    if (dis > this.smoothness)
                        break;
                }
                var or = Math.min(time / dis * this.linePressure + this.lineMin, this.lineMax) / 2;
                this.radius = or;
                this.upof = of ;
                if (dis < 7)
                    return;
                if (this.startOf) {
                    up = this.startOf;
                    ur = or;
                    this.startOf = null;
                    this.history.push([]);
                }
                var len = Math.ceil(this.distance(up, of ) / 2);
                for (var i = 0; i < len; i++) {
                    var x = up.x + ( of .x - up.x) / len * i;
                    var y = up.y + ( of .y - up.y) / len * i;
                    var r = ur + (or - ur) / len * i;
                    this.ctx.beginPath();
                    this.ctx.arc(x, y, r, 0, 2 * Math.PI, true);
                    this.ctx.fill();
                    this.history[this.history.length - 1].push(x, y, r);
                }
            }
    
            Handwriting.prototype.upEvent = function (e) {
                this.moveFlag = false;
            }
    
            Handwriting.prototype.getXY = function (e) {
                var et = e.touches ? e.touches[0] : e;
                var x = et.clientX;
                var y = et.clientY;
                return {
                    x: x - this.canvas.offsetLeft + (document.body.scrollLeft || document.documentElement.scrollLeft),
                    y: y - this.canvas.offsetTop + (document.body.scrollTop || document.documentElement.scrollTop)
                }
            }
    
            Handwriting.prototype.distance = function (a, b) {
                var x = b.x - a.x,
                    y = b.y - a.y;
                return Math.sqrt(x * x + y * y);
            }
    
            Handwriting.prototype.setColor = function (c) {
                this.ctx.fillStyle = c;
            }
    
            var hw = new Handwriting("canvasId");
            hw.setColor("rgba(0,0,210,0.4)"); //设置画笔颜色
            hw.lineMax = 10; //设置画笔最大线宽
            hw.lineMin = 4; //设置画笔最小线宽
            hw.linePressure = 1.2; //设置画笔笔触压力
            hw.smoothness = 30; //设置画笔笔触大小变化的平滑度。
        </script>
    </body>
    
    </html>
    

    移植到小程序端

    看源码大家就知道,很明显这份代码是没有办法直接移植到小程序端运行的。需要做一些改造。

    拆分代码

    按照微信小程序的规范,CSS,html,js文件都是拆分开放在不同的地方。因此我们第一步就是先将代码拆分出来。

    对于CSS部分来说,直接放到微信小程序是没有什么问题的,只要注意将body标签的样式,转化为一个类的样式就好了。

    修改代码

    首先对于html文件,修改很简单,将不支持的标签替换掉就可以了。

    内容:

    
    // 原内容
    
    <h1>手写毛笔字效果-手机版</h1>
    <canvas id="canvasId" width="400" height="500"></canvas>
    <br/>
    <input type="button" value="全部清除" class="button" onclick="hw.clear();" />
    <input type="button" value="清除最后一笔" class="button" onclick="hw.historyBack();" />
    
    // 修改后内容
    
    <!--pages/sign/sign.wxml-->
    <view id="body">
    <view>手写毛笔字效果-手机版</view>
    <canvas id="canvasId" type="2d" canvas-id="canvasId" bindtouchstart="downEvent" bindtouchmove="moveEvent" bindtouchend="upEvent"></canvas>
    <i-button bind:click="clear">全部清除</i-button>
    <i-button bind:click="historyBack">清除最后一笔</i-button>
    </view> 
    
    

    首先div标签转化为view标签,button我换成了iview的按钮(为了美观),另一个值得注意的是canvas这个对象:

    在微信小程序当中的canvas对象和H5里面的canvas是不一样的:

    1.首先支持的版本比较靠后,因此需要注意选择基础库版本。
    
    2.其次,其上的事件是不一样的,也需要修改。
    在web版本当中,事件是在JS当中手动根据当前平台是PC还是移动来动态绑定的。在小程序中我们不需要考虑这个,因此直接写在标签上。
    

    对于JS内容:

    // 原内容
    
        <script type="text/javascript">
            function Handwriting(id) {
                this.canvas = document.getElementById(id);
                this.ctx = this.canvas.getContext("2d");
                var on = ("ontouchstart" in document) ? {
                    start: "touchstart",
                    move: "touchmove",
                    end: "touchend"
                } : {
                    start: "mousedown",
                    move: "mousemove",
                    end: "mouseup"
                };
                this.canvas.addEventListener(on.start, this.downEvent.bind(this), false);
                this.canvas.addEventListener(on.move, this.moveEvent.bind(this), false);
                this.canvas.addEventListener(on.end, this.upEvent.bind(this), false);
                this.canvas.addEventListener("contextmenu", function (e) {
                    e.preventDefault()
                }, false);
                this.moveFlag = false;
                this.upof = {};
                this.radius = 0;
                this.has = [];
                this.startOf = null;
                this.lineMax = 30;
                this.lineMin = 3;
                this.linePressure = 1;
                this.smoothness = 80;
                this.history = [];
                this.setColor("rgba(0,0,0,0.25)");
            }
    
            Handwriting.prototype.clear = function () {
                this.history = [];
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
            }
    
            Handwriting.prototype.historyBack = function () {
                this.history.pop();
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                for (var i = 0; i < this.history.length; i++) {
                    var h = this.history[i];
                    for (var j = 0; j < h.length; j += 3) {
                        this.ctx.beginPath();
                        this.ctx.arc(h[j], h[j + 1], h[j + 2], 0, 2 * Math.PI, true);
                        this.ctx.fill();
                    }
                }
            }
    
            Handwriting.prototype.downEvent = function (e) {
                this.moveFlag = true;
                this.has = [];
                this.upof = this.getXY(e);
                this.startOf = this.upof;
            }
    
            Handwriting.prototype.moveEvent = function (e) {
                if (!this.moveFlag)
                    return;
                e.preventDefault();
                var of = this.getXY(e);
                var up = this.upof;
                var ur = this.radius;
                this.has.unshift({
                    time: new Date().getTime(),
                    dis: this.distance(up, of )
                });
                var dis = 0;
                var time = 0;
                for (var n = 0; n < this.has.length - 1; n++) {
                    dis += this.has[n].dis;
                    time += this.has[n].time - this.has[n + 1].time;
                    if (dis > this.smoothness)
                        break;
                }
                var or = Math.min(time / dis * this.linePressure + this.lineMin, this.lineMax) / 2;
                this.radius = or;
                this.upof = of ;
                if (dis < 7)
                    return;
                if (this.startOf) {
                    up = this.startOf;
                    ur = or;
                    this.startOf = null;
                    this.history.push([]);
                }
                var len = Math.ceil(this.distance(up, of ) / 2);
                for (var i = 0; i < len; i++) {
                    var x = up.x + ( of .x - up.x) / len * i;
                    var y = up.y + ( of .y - up.y) / len * i;
                    var r = ur + (or - ur) / len * i;
                    this.ctx.beginPath();
                    this.ctx.arc(x, y, r, 0, 2 * Math.PI, true);
                    this.ctx.fill();
                    this.history[this.history.length - 1].push(x, y, r);
                }
            }
    
            Handwriting.prototype.upEvent = function (e) {
                this.moveFlag = false;
            }
    
            Handwriting.prototype.getXY = function (e) {
                var et = e.touches ? e.touches[0] : e;
                var x = et.clientX;
                var y = et.clientY;
                return {
                    x: x - this.canvas.offsetLeft + (document.body.scrollLeft || document.documentElement.scrollLeft),
                    y: y - this.canvas.offsetTop + (document.body.scrollTop || document.documentElement.scrollTop)
                }
            }
    
            Handwriting.prototype.distance = function (a, b) {
                var x = b.x - a.x,
                    y = b.y - a.y;
                return Math.sqrt(x * x + y * y);
            }
    
            Handwriting.prototype.setColor = function (c) {
                this.ctx.fillStyle = c;
            }
    
            var hw = new Handwriting("canvasId");
            hw.setColor("rgba(0,0,210,0.4)"); //设置画笔颜色
            hw.lineMax = 10; //设置画笔最大线宽
            hw.lineMin = 4; //设置画笔最小线宽
            hw.linePressure = 1.2; //设置画笔笔触压力
            hw.smoothness = 30; //设置画笔笔触大小变化的平滑度。
        </script>
    
    // 修改后
    
    // pages/sign/sign.js
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        canvas: null,
        ctx: null,
        moveFlag: false,
        upof: {},
        radius: 0,
        has: [],
        startof: null,
        lineMax: 10,
        lineMin: 4,
        linePressure: 1.2,
        smoothness: 30,
        history: []
      },
    
      /**
       * 生命周期函数--监听页面显示
       */
      onShow: function() {
        wx.createSelectorQuery()
          .select('#canvasId')
          .fields({
            node: true,
            size: true,
          })
          .exec(this.init.bind(this))
      },
      init: function(res){
        const canvas = res[0].node
        const ctx = canvas.getContext('2d');
    
        this.data.canvas = canvas;
        this.data.ctx = ctx;
    
        const dpr = wx.getSystemInfoSync().pixelRatio
        canvas.width = res[0].width * dpr
        canvas.height = res[0].height * dpr
        ctx.scale(dpr, dpr)
    
        // ctx.fillRect(0, 0, 100, 100)
      },
      downEvent: function(e) {
        this.data.moveFlag = true;
        this.data.has = [];
        this.data.upof = this.getXY(e);
        this.data.startOf = this.data.upof;
      },
      getXY: function(e) {
        var et = e.touches ? e.touches[0] : e;
        var x = et.x;
        var y = et.y;
        return {
          x: x,
          y: y,
        }
      },
      distance: function(a, b) {
        var x = b.x - a.x,
          y = b.y - a.y;
        return Math.sqrt(x * x + y * y);
      },
      moveEvent: function(e) {
        if (!this.data.moveFlag){
          return;
        }
        // e.preventDefault();
        var of = this.getXY(e);
        var up = this.data.upof;
        var ur = this.data.radius;
        this.data.has.unshift({
          time: new Date().getTime(),
          dis: this.distance(up, of )
        });
        var dis = 0;
        var time = 0;
        for (var n = 0; n < this.data.has.length - 1; n++) {
          dis += this.data.has[n].dis;
          time += this.data.has[n].time - this.data.has[n + 1].time;
          if (dis > this.data.smoothness)
            break;
        }
        var or = Math.min(time / dis * this.data.linePressure + this.data.lineMin, this.data.lineMax) / 2;
        this.data.radius = or;
        this.data.upof = of ;
        if (dis < 7)
          return;
        if (this.data.startOf) {
          up = this.data.startOf;
          ur = or;
          this.data.startOf = null;
          this.data.history.push([]);
        }
        var len = Math.ceil(this.distance(up, of ) / 2);
        for (var i = 0; i < len; i++) {
          var x = up.x + ( of .x - up.x) / len * i;
          var y = up.y + ( of .y - up.y) / len * i;
          var r = ur + (or - ur) / len * i;
          this.data.ctx.beginPath();
          this.data.ctx.arc(x, y, r, 0, 2 * Math.PI, true);
          this.data.ctx.fillStyle = '#1aad19'
          this.data.ctx.strokeStyle = 'rgba(1,1,1,0)'
          this.data.ctx.fill()
          this.data.ctx.stroke()
          this.data.history[this.data.history.length - 1].push(x, y, r);
        }
      },
      upEvent: function (e) {
        this.data.moveFlag = false;
      },
      clear: function () {
        this.data.history = [];
        this.data.ctx.clearRect(0, 0, this.data.canvas.width, this.data.canvas.height);
      },
      historyBack: function () {
        this.data.history.pop();
        this.data.ctx.clearRect(0, 0, this.data.canvas.width, this.data.canvas.height);
        for (var i = 0; i < this.data.history.length; i++) {
          var h = this.data.history[i];
          for (var j = 0; j < h.length; j += 3) {
            this.data.ctx.beginPath();
            this.data.ctx.arc(h[j], h[j + 1], h[j + 2], 0, 2 * Math.PI, true);
            this.data.ctx.fill();
          }
        }
      },
    })
    

    首先对于canvas的一些属性,原web是用一个类(function)来模拟,而在微信小程序端,我们把它都放到data里面去,然后再将方法里对这些数据的引用也修改一下。同时小程序中并没有document对象,所有用到document对象的地方替换成小程序中相同的获取方式。

    完成后的样子

    这只是一个测试的Demo,因此十分丑陋大家可以根据自己的需要再完善:

    sign-weixin.gif

    微信端源代码:

    wxml:

    // sign.wxml
    
    <!--pages/sign/sign.wxml-->
    <view id="body">
    <view>手写毛笔字效果-手机版</view>
    <canvas id="canvasId" type="2d" canvas-id="canvasId" bindtouchstart="downEvent" bindtouchmove="moveEvent" bindtouchend="upEvent"></canvas>
    <i-button bind:click="clear">全部清除</i-button>
    <i-button bind:click="historyBack">清除最后一笔</i-button>
    </view> 
    

    js:

    // sign.js
    
    // pages/sign/sign.js
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        canvas: null,
        ctx: null,
        moveFlag: false,
        upof: {},
        radius: 0,
        has: [],
        startof: null,
        lineMax: 10,
        lineMin: 4,
        linePressure: 1.2,
        smoothness: 30,
        history: []
      },
    
      /**
       * 生命周期函数--监听页面显示
       */
      onShow: function() {
        wx.createSelectorQuery()
          .select('#canvasId')
          .fields({
            node: true,
            size: true,
          })
          .exec(this.init.bind(this))
      },
      init: function(res){
        const canvas = res[0].node
        const ctx = canvas.getContext('2d');
    
        this.data.canvas = canvas;
        this.data.ctx = ctx;
    
        const dpr = wx.getSystemInfoSync().pixelRatio
        canvas.width = res[0].width * dpr
        canvas.height = res[0].height * dpr
        ctx.scale(dpr, dpr)
    
        // ctx.fillRect(0, 0, 100, 100)
      },
      downEvent: function(e) {
        this.data.moveFlag = true;
        this.data.has = [];
        this.data.upof = this.getXY(e);
        this.data.startOf = this.data.upof;
      },
      getXY: function(e) {
        var et = e.touches ? e.touches[0] : e;
        var x = et.x;
        var y = et.y;
        return {
          x: x,
          y: y,
        }
      },
      distance: function(a, b) {
        var x = b.x - a.x,
          y = b.y - a.y;
        return Math.sqrt(x * x + y * y);
      },
      moveEvent: function(e) {
        if (!this.data.moveFlag){
          return;
        }
        // e.preventDefault();
        var of = this.getXY(e);
        var up = this.data.upof;
        var ur = this.data.radius;
        this.data.has.unshift({
          time: new Date().getTime(),
          dis: this.distance(up, of )
        });
        var dis = 0;
        var time = 0;
        for (var n = 0; n < this.data.has.length - 1; n++) {
          dis += this.data.has[n].dis;
          time += this.data.has[n].time - this.data.has[n + 1].time;
          if (dis > this.data.smoothness)
            break;
        }
        var or = Math.min(time / dis * this.data.linePressure + this.data.lineMin, this.data.lineMax) / 2;
        this.data.radius = or;
        this.data.upof = of ;
        if (dis < 7)
          return;
        if (this.data.startOf) {
          up = this.data.startOf;
          ur = or;
          this.data.startOf = null;
          this.data.history.push([]);
        }
        var len = Math.ceil(this.distance(up, of ) / 2);
        for (var i = 0; i < len; i++) {
          var x = up.x + ( of .x - up.x) / len * i;
          var y = up.y + ( of .y - up.y) / len * i;
          var r = ur + (or - ur) / len * i;
          this.data.ctx.beginPath();
          this.data.ctx.arc(x, y, r, 0, 2 * Math.PI, true);
          this.data.ctx.fillStyle = '#1aad19'
          this.data.ctx.strokeStyle = 'rgba(1,1,1,0)'
          this.data.ctx.fill()
          this.data.ctx.stroke()
          this.data.history[this.data.history.length - 1].push(x, y, r);
        }
      },
      upEvent: function (e) {
        this.data.moveFlag = false;
      },
      clear: function () {
        this.data.history = [];
        this.data.ctx.clearRect(0, 0, this.data.canvas.width, this.data.canvas.height);
      },
      historyBack: function () {
        this.data.history.pop();
        this.data.ctx.clearRect(0, 0, this.data.canvas.width, this.data.canvas.height);
        for (var i = 0; i < this.data.history.length; i++) {
          var h = this.data.history[i];
          for (var j = 0; j < h.length; j += 3) {
            this.data.ctx.beginPath();
            this.data.ctx.arc(h[j], h[j + 1], h[j + 2], 0, 2 * Math.PI, true);
            this.data.ctx.fill();
          }
        }
      },
    })
    

    wxss:

    /* pages/sign/sign.wxss */
    
    #canvasId {
      width: 100%;
      height: 500px;
      background-color: #ffd;
    }
    
    #body {
      margin: 0;
      padding: 0;
      text-align: center;
      background-color: #936;
    }
    
    

    注意有坑:

    1. canvas标签在微信当中必须要有canvas-id属性,否则这个标签会被自动隐藏。

    2. 注意调试基础库,如果版本过低,不支持canvas标签还没啥显著提示。

    3. 打开真机调试无法调试canvas,但是预览中可以生鲜。调试时它不会生效。这并不仅仅是我自己的问题,论坛里同样有人在问,不知道此时是否已经解决。

    相关文章

      网友评论

          本文标题:笔锋签字页移植微信小程序

          本文链接:https://www.haomeiwen.com/subject/azuczctx.html