关于手写签名的实现

Created by winston on September 14, 2020.


1、背景

​ 由于微信公众号要实现工作流流程会签,会签过程中有签到功能,因此需要一个比较容易操作的手写签名的方式。签名方式主要是通过canvas元素使用Javascript在网页上绘制图像。

2、实现

① 引入writing-pad-1.0.0.js

/**
 * 功能:签名canvas面板初始化,为writing-pad-1.0.0.js手写面板js服务。
 * 作者:李明飞
 * 日期:2020-09-14  14:30:01
 * 版本:version 1.0
 */

(function (window, document, $) {
    'use strict';

    // Get a regular interval for drawing to the screen
    window.requestAnimFrame = (function (callback) {
        return window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimaitonFrame ||
            function (callback) {
                window.setTimeout(callback, 1000 / 60);
            };
    })();

    /*
    * Plugin Constructor
    */

    var pluginName = 'jqSignature',
        defaults = {
            lineColor: '#222222',
            lineWidth: 1,
            border: '1px dashed #CCFF99',
            background: '#FFFFFF',
            width: 500,
            height: 200,
            autoFit: false
        },
        canvasFixture = '<canvas></canvas>';

    function Signature(element, options) {
        // DOM elements/objects
        this.element = element;
        this.$element = $(this.element);
        this.canvas = false;
        this.$canvas = false;
        this.ctx = false;
        // Drawing state
        this.drawing = false;
        this.currentPos = {
            x: 0,
            y: 0
        };
        this.lastPos = this.currentPos;
        // Determine plugin settings
        this._data = this.$element.data();
        this.settings = $.extend({}, defaults, options, this._data);
        // Initialize the plugin
        this.init();
    }

    Signature.prototype = {
        // Initialize the signature canvas
        init: function () {
            // Set up the canvas
            this.$canvas = $(canvasFixture).appendTo(this.$element);
            this.$canvas.attr({
                width: this.settings.width,
                height: this.settings.height
            });
            this.$canvas.css({
                boxSizing: 'border-box',
                width: this.settings.width + 'px',
                height: this.settings.height + 'px',
                border: this.settings.border,
                background: this.settings.background,
                cursor: 'crosshair'
            });
            // Fit canvas to width of parent
            if (this.settings.autoFit === true) {
                this._resizeCanvas();
            }
            this.canvas = this.$canvas[0];
            this._resetCanvas();
            // Set up mouse events
            this.$canvas.on('mousedown touchstart', $.proxy(function (e) {
                this.drawing = true;
                this.lastPos = this.currentPos = this._getPosition(e);
            }, this));
            this.$canvas.on('mousemove touchmove', $.proxy(function (e) {
                this.currentPos = this._getPosition(e);
            }, this));
            this.$canvas.on('mouseup touchend', $.proxy(function (e) {
                this.drawing = false;
                // Trigger a change event
                var changedEvent = $.Event('jq.signature.changed');
                this.$element.trigger(changedEvent);
            }, this));
            // Prevent document scrolling when touching canvas
            $(document).on('touchstart touchmove touchend', $.proxy(function (e) {
                if (e.target === this.canvas) {
                    e.preventDefault();
                }
            }, this));
            // Start drawing
            var that = this;
            (function drawLoop() {
                window.requestAnimFrame(drawLoop);
                that._renderCanvas();
            })();
        },
        // Clear the canvas
        clearCanvas: function () {
            this.canvas.width = this.canvas.width;
            this._resetCanvas();
        },
        // Get the content of the canvas as a base64 data URL
        getDataURL: function () {
            return this.canvas.toDataURL();
        },

        reLoadData: function () {
            this.$canvas.remove();
            this._data = this.$element.data();

            //for (var i in this.settings) {
            //    alert(i+":"+this.settings[i]);
            //}

            //this.settings = $.extend({}, defaults, this._data);
            this.init();
        },
        // Get the position of the mouse/touch
        _getPosition: function (event) {
            var xPos, yPos, rect;
            rect = this.canvas.getBoundingClientRect();
            event = event.originalEvent;
            // Touch event
            if (event.type.indexOf('touch') !== -1) { // event.constructor === TouchEvent
                xPos = event.touches[0].clientX - rect.left;
                yPos = event.touches[0].clientY - rect.top;
            }
            // Mouse event
            else {
                xPos = event.clientX - rect.left;
                yPos = event.clientY - rect.top;
            }
            return {
                x: xPos,
                y: yPos
            };
        },
        // Render the signature to the canvas
        _renderCanvas: function () {
            if (this.drawing) {
                this.ctx.moveTo(this.lastPos.x, this.lastPos.y);
                this.ctx.lineTo(this.currentPos.x, this.currentPos.y);
                this.ctx.stroke();
                this.lastPos = this.currentPos;
            }
        },
        // Reset the canvas context
        _resetCanvas: function () {
            this.ctx = this.canvas.getContext("2d");
            this.ctx.strokeStyle = this.settings.lineColor;
            this.ctx.lineWidth = this.settings.lineWidth;
        },
        // Resize the canvas element
        _resizeCanvas: function () {
            var width = this.$element.outerWidth();
            this.$canvas.attr('width', width);
            this.$canvas.css('width', width + 'px');
        }
    };

    /*
    * Plugin wrapper and initialization
    */

    $.fn[pluginName] = function (options) {
        var args = arguments;
        if (options === undefined || typeof options === 'object') {
            return this.each(function () {
                if (!$.data(this, 'plugin_' + pluginName)) {
                    $.data(this, 'plugin_' + pluginName, new Signature(this, options));
                }
            });
        } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
            var returns;
            this.each(function () {
                var instance = $.data(this, 'plugin_' + pluginName);
                if (instance instanceof Signature && typeof instance[options] === 'function') {
                    var myArr = Array.prototype.slice.call(args, 1);
                    returns = instance[options].apply(instance, myArr);
                }
                if (options === 'destroy') {
                    $.data(this, 'plugin_' + pluginName, null);
                }
                //if (options === 'reLoadData') {
                //    //this.$canvas.remove();
                //    $.data(this, 'plugin_' + pluginName, null);
                //    this._data = this.$element.data();
                //    this.settings = $.extend({}, defaults, options, this._data);
                //    this.init();
                //}
            });
            return returns !== undefined ? returns : this;
        }
    };

})(window, document, jQuery);

② 引入jq-signature-1.0.0.js

/**
 * 功能:使用jQuery插件来制作在线签名或涂鸦板,用户绘制的东西可以用图片的形式保存下来。
 * 作者:李明飞
 * 日期:2020-09-14 13:51:01
 * 版本:version 1.0
 */

var WritingPad = function () {

    var current = null;

    $(function () {

        initHtml();

        initTable();

        initSignature();

        if ($(".modal")) {
            $(".modal").modal("toggle");
        } else {
            alert("没用手写面板");
        }

        $(document).on("click", "#myClose,.close", null, function () {
            $('#mymodal').modal('hide');
            $("#mymodal").remove();

        });

        $(document).on("click", "#mySave", null, function () {

            var myImg = $('#myImg').empty();
            var dataUrl = $('.js-signature').jqSignature('getDataURL');
            var img = $('<img>').attr('src', dataUrl);
            console.log("imgUrl------->"+dataUrl);
            //$(myImg).append($('<p>').text("图片保存在这里"));
            $(myImg).append(img);
            // winston 动态渲染手写签名 begin
            sessionStorage.setItem('dataUrl',dataUrl);
            $('#mymodal').modal('hide');
            $("#mymodal").remove();
            window.location.reload();
            // winston 动态渲染手写签名 end
        });

        $(document).on("click", "#myEmpty", null, function () {
            $('.js-signature').jqSignature('clearCanvas');

        });

        $(document).on("click", "#myBackColor", null, function () {

            $('#colorpanel').css('left', '95px').css('top', '45px').css("display", "block").fadeIn();
            //$("canvas").css("background", "#EEEEEE");
            $("#btnSave").data("sender", "#myBackColor");
        });

        $(document).on("click", "#myColor", null, function () {
            $('#colorpanel').css('left', '205px').css('top', '45px').css("display", "block").fadeIn();
            $("#btnSave").data("sender", "#myColor");
        });

        $(document).on("mouseover", "#myTable", null, function () {

            if ((event.srcElement.tagName == "TD") && (current != event.srcElement)) {
                if (current != null) {
                    current.style.backgroundColor = current._background
                }
                event.srcElement._background = event.srcElement.style.backgroundColor;
                //$("input[name=DisColor]").css("background-color", event.srcElement.style.backgroundColor);
                //var color = event.srcElement.style.backgroundColor;
                //var strArr = color.substring(4, color.length - 1).split(',');
                //var num = showRGB(strArr);
                //$("input[name=HexColor]").val(num);
                current = event.srcElement;
            }

        });

        $(document).on("mouseout", "#myTable", null, function () {

            if (current != null) current.style.backgroundColor = current._background

        });

        $(document).on("click", "#myTable", null, function () {

            if (event.srcElement.tagName == "TD") {
                var color = event.srcElement._background;
                if (color) {
                    $("input[name=DisColor]").css("background-color", color);
                    var strArr = color.substring(4, color.length - 1).split(',');
                    var num = showRGB(strArr);
                    $("input[name=HexColor]").val(num);
                }
            }

        });

        $(document).on("click", "#btnSave", null, function () {

            $('#colorpanel').css("display", "none");
            var typeData = $("#btnSave").data("sender");
            var HexColor = $("input[name=HexColor]").val();
            var data = $(".js-signature").data();
            if (typeData == "#myColor") {
                data["plugin_jqSignature"]["settings"]["lineColor"] = HexColor;
                $('.js-signature').jqSignature('reLoadData');
            }
            if (typeData == "#myBackColor") {

                data["plugin_jqSignature"]["settings"]["background"] = HexColor;
                $('.js-signature').jqSignature('reLoadData');
            }
        });

        $("#mymodal").on('hide.bs.modal', function () {
            $("#colorpanel").remove();
            $("#mymodal").remove();
            $("#myTable").remove();
        });

    });

    function initHtml() {

        var html = '<div class="modal" id="mymodal">' +
            '<div class="modal-dialog">' +
            '<div class="modal-content">' +
            '<div class="modal-header">' +
            '<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>' +
            '<h4 class="modal-title">手写面板</h4>' +
            '</div>' +
            '<div class="modal-body">' +
            '<div class="js-signature" id="mySignature">' +
            '</div>' +
            '<div>' +
            '<button type="button" class="btn btn-default" id="myEmpty">清空面板</button>' +
            '<button type="button" class="btn btn-default" id="myBackColor">设置背景颜色</button>' +
            //'<div style="position:absolute;relative">' +
            '<button type="button" class="btn btn-default" id="myColor">设置字体颜色</button>' +
            '<div id="colorpanel" style="position:absolute;z-index:99;display:none"></div>' +
            //'</div>'+
            '</div>' +
            '</div>' +
            '<div class="modal-footer">' +

            '<button type="button" class="btn btn-default" id="myClose">关闭</button>' +
            '<button type="button" class="btn btn-primary" id="mySave">保存</button>' +

            '<div id="myImg">' +
            '<div>' +

            '</div>' +
            '</div>' +
            '</div>' +
            '</div>';

        $('body').append(html);
    }

    function initTable() {
        var colorTable = "";
        var ColorHex = new Array('00', '33', '66', '99', 'CC', 'FF');
        var SpColorHex = new Array('FF0000', '00FF00', '0000FF', 'FFFF00', '00FFFF', 'FF00FF');
        for (var i = 0; i < 2; i++) {
            for (var j = 0; j < 6; j++) {
                colorTable = colorTable + '<tr height=12>';
                colorTable = colorTable + '<td width=11 style="background-color:#000000"></td>';

                if (i == 0) {
                    colorTable = colorTable + '<td width=11 style="background-color:#' + ColorHex[j] + ColorHex[j] + ColorHex[j] + '"></td>';
                } else {
                    colorTable = colorTable + '<td width=11 style="background-color:#' + SpColorHex[j] + '"></td>';
                }

                //colorTable = colorTable + '<td width=11 style="background-color:#000000"></td>';

                for (var k = 0; k < 3; k++) {
                    for (l = 0; l < 6; l++) {
                        colorTable = colorTable + '<td width=11 style="background-color:#' + ColorHex[k + i * 3] + ColorHex[l] + ColorHex[j] + '"></td>';
                    }
                }
                colorTable = colorTable + '</tr>';


            }
        }
        colorTable =
            '<table border="1" id="myTable" cellspacing="0" cellpadding="0" style="border-collapse: collapse;cursor:pointer;" bordercolor="000000">'
            + colorTable + '</table>' +
            '<table width=225 border="0" cellspacing="0" cellpadding="0" style="border:1px #000000 solid;border-collapse: collapse;background-color:#000000">' +
            '<tr style="height:30px">' +
            '<td colspan=21 bgcolor=#cccccc>' +

            '<table cellpadding="0" cellspacing="1" border="0" style="border-collapse: collapse">' +
            '<tr>' +
            '<td width="3"><input type="text" name="DisColor" size="6" disabled style="border:solid 1px #000000;background-color:#ffff00"></td>' +
            '<td width="3"><input type="text" name="HexColor" size="7" style="border:inset 1px;font-family:Arial;" value="#000000"></td>' +
            '<td width="3"><button type="button" class="btn btn-primary btn-sm" id="btnSave">确认</button></td>' +
            '</tr>' +
            '</table>' +

            '</td>' +
            '</tr>' +
            '</table>';
        $("#colorpanel").append(colorTable);
    }

    function initSignature() {

        if (window.requestAnimFrame) {
            var signature = $("#mySignature");
            signature.jqSignature({
                width: 569,
                height: 200,
                border: '1px solid red',
                background: '#16A085',
                lineColor: '#ABCDEF',
                lineWidth: 2,
                autoFit: false
            });
            //{ width: 600, height: 200, border: '1px solid red', background: '#16A085', lineColor: '#ABCDEF', lineWidth: 2, autoFit: true }
        } else {

            alert("请加载jq-signature.js");
            return;
        }
    }

    function showRGB(arr) {
        hexcode = "#";
        for (x = 0; x < 3; x++) {
            var n = arr[x];
            if (n == "") n = "0";
            if (parseInt(n) != n)
                return alert("RGB颜色值不是数字!");
            if (n > 255)
                return alert("RGB颜色数字必须在0-255之间!");
            var c = "0123456789ABCDEF", b = "", a = n % 16;
            b = c.substr(a, 1);
            a = (n - a) / 16;
            hexcode += c.substr(a, 1) + b
        }
        return hexcode;
    }

    function init() {
    }

    return {
        init: function () {
            init();
        }
    };
}

③ 测试页面 signature.html

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
    <title>手写签名DEMO</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
    <script src="../js/wechat/jquery-1.11.1.js"></script>
    <script src="../js/bootstrap.min.js"></script>
    <script src="../js/wechat/writing-pad-1.0.0.js"></script>
    <script src="../js/wechat/jq-signature-1.0.0.js"></script>
    <link href="../css/bootstrap.min.css" rel="stylesheet" />
    <style>
        .signBtn {
            margin-top: 4%;
            margin-left: 45%;
        }
        .signDiv {
            margin-top: 2%;
            margin-left: 45%;
        }

        .signImg {
            /*margin-top: 2%;*/
            margin-left: 31%;
        }

        .signP {
            margin-top: 2%;
            margin-left: 41%;
        }
    </style>
</head>

<body>

<div class="container" id="container">
    <div class="row">
        <button id="signBtn" class="btn btn-primary signBtn" type="button" style="position:relative">手写签名</button>
    </div>
    <div class="row">
        <p class="signP">This signature test create by winston.</p>
        <!--<button class="btn btn-primary signDiv" οnclick="test();">测试图片</button>-->
        <img id="testImg" class="signImg"/>
    </div>
</div>
</body>
<script>
    autoSize();
    window.onresize = function () {
        autoSize();
    }
    function autoSize() {
        // 获取当前浏览器的视窗宽度,放在w中
        var w = document.documentElement.clientWidth;
        // 计算实际html font-size大小
        // var size = w * 100 / 375;
        var size = w * 12 / 375;
        // 获取当前页面中的html标签
        var html = document.querySelector('html');
        // 设置字体大小样式
        html.style.fontSize = size + 'px';
    }

    $(function () {
        $("#signBtn").click(function () {
            var wp = new WritingPad();
        });
    });

    test();
    function test(){
        var dataUrl = sessionStorage.getItem("dataUrl");
        $('#testImg').empty();
        var img = $('#testImg').attr('src', dataUrl);
        $("#testImg").append(img)
    }
</script>

</html>

3、测试效果

在这里插入图片描述在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值