html移动端实现手写签名,signature手写签名实现,微信公众号浏览器html手写签名实现

news2025/4/9 5:25:54

前言

html移动端手写自动横竖签名实现,并base64图片格式获取;
横竖根据屏幕宽高自动平铺。

效果图

图一

在这里插入图片描述

图二

在这里插入图片描述

实现

如下代码直接复制成.html文件打开即可预览效果

<!DOCTYPE html>
<html>
    <head>
        <title>手写签名</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
        <style>
            html,body {
                padding:0;
                margin:0;
                width: 100%;
                height: 100%;
            }
            .text-center {
			    text-align: center;
			}
			#signature-button {
			    display: block;
			    margin: 0 auto;
			    border: 1px solid #6680ff;
			    background: #6680ff;
			    color: #fff;
			    border-radius: 4px;
			    padding: 8px 10px;
			    font-size: 16px;
			    cursor: pointer;
			}
			#signature-button:hover {
				opacity: 0.8;
			}
			#signature-img {
			    width: 100%;
			    margin: 10px auto;
			    display: none;
			}
			#signature-pop {
			    position: fixed;
			    background-color: #fff;
			    top:0;
			    left:0;
			    bottom:0;
			    right:0;
			    width: 100%;
			    height: 100%;
			    display: none;
			}
			#signature-container {
			    width: 100%;
			    height: 100%;
			}
			.demo-top-info {
			    position: absolute;
			    top: 0;
			    left: 0;
			    width: 100%;
			    height: 40px;
			    background: #7b8bff;
			    box-sizing: border-box;
			    text-align: center;
			    color: #fff;
			}
			.demo-top-info .return {
			    padding-left: 5px;
			    height: 40px;
			    line-height: 40px;
			    position: absolute;
			    left: 10px;
			    display: inline-block;
			    cursor: pointer;
			}
			.signature-title {
			    height: 40px;
			    line-height: 40px;
			    display: inline-block;
			}
			.canvas-container {
			    width: 100%;
			    height: 100%;
			    background-color: #ffffff;
			    box-sizing: border-box;
			    padding: 40px 0 50px 0;
			}
			.canvas-parent {
			    width: 100%;
			    height: 100%;
			}
			.demo-bottom-info {
			    position: absolute;
			    bottom: 0;
			    left: 0;
			    width: 100%;
			    height: 50px;
			    background: #ffffff;
			    padding: 0 2%;
			    box-sizing: border-box;
			    overflow: hidden;
			    /* box-shadow: #efefef 0 -2px 5px 0; */
			    border-top: 1px solid #efefef;
			}
			#clean_canvas {
			    float: left;
			    font-size: 16px;
			    margin-top: 5px;
			    /* background: #f8f8f8; */
			    border: 1px solid #ddd;
			    padding: 8px 10px;
			    border-radius: 4px;
			    color: #323232;
			    cursor: pointer;
			}
			#sure_canvas {
			    float: right;
			    padding: 3px 0;
			    background: #7b8bff;
			    padding: 8px 10px;
			    border: 1px solid #7b8bff;
			    border-radius: 4px;
			    color: #fff;
			    margin-top: 5px;
			    cursor: pointer;
			}
			#clean_canvas:hover,
			#sure_canvas:hover{
				opacity: 0.8;
			} 
			#canvas2 {
			    position: absolute;
			    top: 0;
			    left:0;
			    z-index: 999;
			    margin-left: 40px;
			}
        </style>
    </head>
    <body>
    	
        <div class="app-container" style="padding-top: 100px;">
            <button id="signature-button">开始手写签名</button>
            <div class="signature-result__img">
                <img src="" id="signature-img" alt="手写签名图片预览"/>
            </div>
        </div>
        
        <!-- 注意核心块 -->
        <div id="signature-pop">
            <div id="signature-container">
                <div class="demo-top-info" id="rotate-container">
                    <div class="return" id="return">返回</div>
                    <div class="signature-title text-center">手写签名</div>
                </div>
                <div class="canvas-container">
                    <div class="canvas-parent">
                        <canvas id="canvas"></canvas>
                    </div>
                </div>
                <div class="demo-bottom-info">
                    <div id="clean_canvas">清空</div>
                    <div id="sure_canvas">确认</div>
                </div>
            </div>
            <canvas id="canvas2"></canvas>
        </div>
        
    </body>
    <script type="text/javascript">
        
        // 手绘签名类
		var SignatureClass = (function(){
		    //获取当前位置(返回px)
		    function getStyle(obj, attr) {
		        if (obj.currentStyle) {
		            return obj.currentStyle[attr];
		        } else {
		            return getComputedStyle(obj, false)[attr];
		        }
		    }
		    
		    function Signatrue(options) {
		        this.cavnas = null;
		        this.ctx = null;
		        this.maxparams = {};
		        this.minparams = {};
		        this.entershuping = true; //是否是竖屏 true=是
		        this.firstTouch = true; // 第一次点击或touch
		        this.allowSubmit = false; // 是否手写了内容 是=才能提交 否=不能提交
		        if(options === void 0) {
		            options = {};
		        }
		        this.options = options;
		    }
		    
		    // 初始化
		    Signatrue.prototype.init = function() {
		        var self = this;
		        console.log(getStyle(document.getElementById("rotate-container"), "height")); // 不知道为什么加,否则有些Apple出问题
		        this.hengshuping();
		        this.clear();
		        this.submit();
		        
		        window.addEventListener('resize',function() {
		            self.hengshuping();
		        },false);
		    }
		    
		    // 判断横竖屏
		    Signatrue.prototype.hengshuping = function() {
		        if (window.orientation == 90 || window.orientation == -90) {
		            this.entershuping = false; // 横屏
		            document.getElementById("canvas2").style.display = "none";
		            document.getElementById("canvas").style.display = "block";
		            this.canvas = document.getElementById("canvas");
		            this.ctx = this.canvas.getContext("2d");
		            this.ctx.lineWidth = 2; // 画线的大小
		            this.ctx.strokeStyle = "#000000";
		            this.drawEvent();
		            document.querySelector("#signature-container").style.width = window.innerWidth + "px";
		            document.querySelector("#signature-container").style.height = window.innerHeight + "px";
		            this.canvas.height = parseInt(getStyle(document.getElementById("canvas").parentNode, 'height'));
		            this.canvas.width = parseInt(getStyle(document.getElementById("canvas").parentNode, 'width'));
		            document.querySelector("#signature-container").style.transform = "rotate(0deg)";
		            document.querySelector("#signature-container").style.transformOrigin = "0 0";
		            document.querySelector("#signature-container").style.marginLeft = "0px";
		        } else { // 竖屏
		            this.entershuping = true;
		            document.getElementById("canvas").style.display = "none";
		            document.getElementById("canvas2").style.display = "block";
		            this.canvas = document.getElementById("canvas2");
		            this.ctx = this.canvas.getContext("2d");
		            this.canvas.height = window.innerHeight;
		            this.canvas.width = window.innerWidth - 40 - 40;
		            this.ctx.lineWidth = 2;// 画线的大小
		            this.ctx.strokeStyle = "#000000";
		            this.drawEvent();
		            document.querySelector("#signature-container").style.width = window.innerHeight + "px";
		            document.querySelector("#signature-container").style.height = window.innerWidth + "px";
		            document.querySelector("#signature-container").style.transform = "rotate(90deg)";
		            document.querySelector("#signature-container").style.transformOrigin = "0 0";
		            document.querySelector("#signature-container").style.marginLeft = window.innerWidth + "px";
		        }
		    }
		    
		    // 绘画事件
		    Signatrue.prototype.drawEvent = function() {
		        var self = this;
		        this.canvas.addEventListener("touchstart", function(evt) {
		            var oEvent = evt || event;
		            oEvent.preventDefault();
		            var position = self.pos(oEvent);
		            self.ctx.beginPath();
		            self.ctx.moveTo(position.x, position.y);
		            if (self.firstTouch) {
		                self.minparams = {
		                    x: position.x,
		                    y: position.y
		                };
		                self.maxparams = {
		                    x: position.x,
		                    y: position.y
		                };
		                self.firstTouch = false;
		            } else {
		                self.judgeSize(position);
		            }
		            self.canvas.addEventListener("touchmove", touchmove, false)
		        
		            function touchmove(evt) {
		                var oEvent = evt || event;
		                oEvent.preventDefault();
		                var position = self.pos(oEvent);
		                self.ctx.lineTo(position.x, position.y);
		                self.judgeSize(position);
		                self.ctx.stroke();
		            }
		            document.addEventListener("touchend", touchend, false)
		        
		            function touchend(evt) {
		                var oEvent = evt || event;
		                oEvent.preventDefault();
		                self.allowSubmit = true;
		                self.canvas.removeEventListener("touchmove", touchmove);
		                document.removeEventListener("touchend", touchend);
		            }
		        })
		    }
		    
		    // 清空画笔
		    Signatrue.prototype.clear = function() {
		        var self = this;
		        document.getElementById("clean_canvas").addEventListener("click", function() {
		            self.ctx.clearRect(0, 0, self.canvas.width, self.canvas.height);
		            self.allowSubmit = false;
		        })
		    }
		    
		    // 提交画笔内容
		    Signatrue.prototype.submit = function() {
		        var self = this;
		        document.getElementById("sure_canvas").addEventListener("click", function() {
		            if (self.allowSubmit) {
		                var imgSRC = self.canvas.toDataURL('image/png', 1);
		                var img = new Image();
		                img.src = imgSRC;
		                self.ctx.clearRect(0, 0, self.canvas.width, self.canvas.height);
		                img.onload = function() {
		                    var width = self.maxparams.x - self.minparams.x;
		                    var height = self.maxparams.y - self.minparams.y;
		                    var targetWidth = 200;
		                    var targetHeight = 100;
		                    var clipCanvas = document.createElement("canvas");
		                    clipCanvas.width = targetWidth;
		                    clipCanvas.height = targetHeight;
		                    var ctx2 = clipCanvas.getContext("2d");
		                    if (self.entershuping) {
		                        ctx2.translate(0, targetHeight);
		                        ctx2.rotate(-90 * Math.PI / 180);
		                        ctx2.drawImage(img, self.minparams.x, self.minparams.y, width, height, 0, 0, targetHeight, targetWidth);
		                    } else {
		                        ctx2.drawImage(img, self.minparams.x, self.minparams.y, width, height, 0, 0, targetWidth, targetHeight);
		                    }
		                    var imgSRC2 = clipCanvas.toDataURL('image/png', 1);
		                    if(self.options && self.options.callback && typeof self.options.callback == 'function') {
		                        self.options.callback(imgSRC2);
		                        // imgSRC2 这就是base64返回值了
		                    }
		                    self.canvas = null;
		                    self.ctx = null;
		                    ctx2 = null;
		                    clipCanvas = null;
		                    
		                }
		            } else {
		                alert("没有手写签名,不能提交!")
		            }
		        })
		    }
		    
		    
		    // 获取当前位置
		    Signatrue.prototype.pos = function(event) {
		        var x = event.touches[0].pageX - event.target.offsetLeft;
		        var y = event.touches[0].pageY - event.target.offsetTop;
		        return {
		            x: x,
		            y: y
		        };
		    }
		    
		    // 优化画笔界限,去掉空白区域
		    Signatrue.prototype.judgeSize = function(value) {
		        if (this.minparams.x > value.x) {
		            this.minparams.x = value.x;
		        }
		        if (this.maxparams.x < value.x) {
		            this.maxparams.x = value.x;
		        }
		        if (this.minparams.y > value.y) {
		            this.minparams.y = value.y;
		        }
		        if (this.maxparams.y < value.y) {
		            this.maxparams.y = value.y;
		        }
		    }
		    
		    return Signatrue;
		})();
        
        // 【使用方式-参数接收】
        // 点击去手写签名-展示手写签名弹框
        document.getElementById('signature-button').addEventListener('click',function(){
            document.getElementById('signature-pop').style.display = 'block';
            var signatrueDraw = new SignatureClass({
                callback: function(base64) {
                	// base64就是这个图片的值了【注意:这里得到值】
                    document.getElementById('signature-img').src = base64;
                    document.getElementById('signature-pop').style.display = 'none';
                    document.getElementById('signature-img').style.display = 'block';
                }
            });
            signatrueDraw.init();

        },false);
        
        // 点击弹框返回
        document.getElementById('return').addEventListener('click',function(){
            document.getElementById('signature-pop').style.display = 'none';
        },false);
        
        
    </script>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/10659.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

适合中小企业的ERP管理软件如何选择?

在选择ERP系统时&#xff0c;我们可以按照这三个维度&#xff0c;然后再按照需求去选择ERP系统。 市面上ERP软件大概可以分为三大类&#xff1a; ① 标准ERP应用&#xff1a;功能比较固定&#xff0c;难以满足个性化需求&#xff0c;二次开发难度很高&#xff1b; ② 找外包/…

SQL 的执行流程是什么样的

在选择存储引擎时&#xff0c;应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统&#xff0c;还可以根据实际情况选择多种存储引擎进行组合。 以下是几种常用的存储引擎的使用环境。 InnoDB : 是 Mysql 的默认存储引擎&#xff0c;用于事务处理应用程序&#xf…

浅谈薄膜行业MES解决方案

随着国家节能减排的号召&#xff0c;新能源电动汽车蓬勃发展&#xff0c;带动整个锂电行业的崛起&#xff0c;锂电池的结构中&#xff0c;隔膜是关键的内层组件之一。隔膜的性能决定了电池的界面结构、内阻等&#xff0c;直接影响电池的容量、循环以及安全性能等特性&#xff0…

数据中台选型必读(四):要想中台建的好,数据模型得做好

在数据中台构建之前&#xff0c;分析师经常发现自己没有可以复用的数据集&#xff0c;不得不使用原始数据依次进行数据的清洗、加工、计算指标。 重复进行原始数据的清洗加工 由于业务部门的分析师大多是非技术出身&#xff0c;写的SQL可能比较差&#xff0c;多层嵌套对后台的…

【教学类-13-02】20221115《数字色块图5*7*8横板》(中班主题《》)

效果展示 背景需求&#xff1a; 前期中3班制作5*7 *9张数字图&#xff0c;发现三个问题&#xff1a; 1、数量太多&#xff0c;填不完——每人9张调整为每人4张&#xff08;一张A4两份作业&#xff09; 2、数字太浅&#xff0c;看不清——5*7的提示数字是灰色&#xff0c;数字…

WeNet更新:喜马拉雅团队在 WeNet 中支持 Squeezeformer

WeNet在正式发布两年的时间里&#xff0c;成为非常热门的ASR生产工具&#xff0c;其面向生产的属性更是深受工业界的好评。近期&#xff0c;喜马拉雅团队在WeNet中支持了Squeezeformer的相关工作。本文由喜马拉雅珠峰智能实验室撰写&#xff0c;介绍了Squeezeformer论文的复现细…

vant_vant引入

目录vant官网使用vant[1]导入vant 的所有组件[2] 按需引入组件[3]自动按需引入组件使用过程中遇到的问题[1]问题1-版本冲突vant官网 vant2.0官网 使用vant 参考vant官网–>快速上手–>通过npm安装/引入组件 [1]导入vant 的所有组件 [1] 安装 vant &#xff1a;npm i va…

基于matlab的MRC最大合并比误码率仿真,包括维特比译码,MRC,中继

目录 1.算法概述 2.仿真效果预览 3.核心MATLAB代码预览 4.完整MATLAB程序 1.算法概述 最大比合并&#xff08;Maximal Ratio Combining&#xff0c;MRC&#xff09;是分集合并技术中的最优选择&#xff0c;相对于选择合并和等增益合并可以获得最好的性能&#xff0c;其性能…

STC51单片机29——汇编语言 取表法 流水灯

汇编语言编写流水灯 ORG 0 START: MOV DPTR,#TABLE LOOP: CLR A MOVC A,ADPTR CJNE A,#01H,LOOP1 //假如A等于01H &#xff0c;则执行下一句 JMP START LOOP1: MOV P1,A MOV R3,#20 LCALL DELAY INC DPTR //指针自加1 JMP LOOP DELAY: MOV R4,#20 D1: MOV R5,#24…

【6-Git安装与配置过程、Gitee码云上创建项目、IDEA关联克隆的项目】

一.知识回顾 【0.三高商城系统的专题专栏都帮你整理好了&#xff0c;请点击这里&#xff01;】 【1-系统架构演进过程】 【2-微服务系统架构需求】 【3-高性能、高并发、高可用的三高商城系统项目介绍】 【4-Linux云服务器上安装Docker】 【5-Docker安装部署MySQL和Redis服务】…

异常检测 | MATLAB实现BiLSTM(双向长短期记忆神经网络)数据异常检测

异常检测 | MATLAB实现BiLSTM(双向长短期记忆神经网络)数据异常检测 目录 异常检测 | MATLAB实现BiLSTM(双向长短期记忆神经网络)数据异常检测效果一览基本介绍模型准备模型设计参考资料效果一览 基本介绍 训练一个双向 LSTM 自动编码器来检测机器是否正常工作。 自动编码器接受…

一文教你搞懂Go中栈操作

LInux 进程在内存布局 多任务操作系统中的每个进程都在自己的内存沙盒中运行。在 32 位模式下&#xff0c;它总是 4GB 内存地址空间&#xff0c;内存分配是分配虚拟内存给进程&#xff0c;当进程真正访问某一虚拟内存地址时&#xff0c;操作系统通过触发缺页中断&#xff0c;在…

前后端必知必会的HTTP,这份全彩版图解手册可算是给讲透了

HTTP HTTP (HyperText Transfer Protocol)&#xff0c;即超文本运输协议。是互联网上应用最为广泛的一种网络协议&#xff0c;是一个客户端和服务器端请求和应答的标准&#xff08;TCP&#xff09;&#xff0c;用于从WWW服务器传输超文本到本地浏览器的传输协议&#xff0c;它…

基础15:npm、yarn、pnpm

npm2 用 node 版本管理工具把 node 版本降到 4&#xff0c;那 npm 版本就是 2.x 了。 执行 npm init&#xff0c; npm install express&#xff0c;可以看到node_modules目录如下&#xff1a; 可以看到&#xff0c;npm2的node_modules是嵌套的。 这种方式的优点就是模块依赖关…

NDIR二氧化碳传感器原理介绍

文章目录1. 引言2. 分类3. 红外气体传感原理3.1 朗伯-比尔定律3.2 非分光红外&#xff08;NDIR&#xff09;法检测原理3.3 浓度、温湿度标定3.4 响应时间研究4. 参考文献1. 引言 环境领域&#xff1a;近些年&#xff0c;二氧化碳是引起温室效应的主要气体&#xff0c;因此引起…

项目可交付成果的质量管理该怎么做?

通往项目最终服务或产品的道路往往是由许多临时可交付成果铺就的。每一个可交付成果本身都必须完整、质量合适并与所有其他可交付成果协调&#xff0c;同时确保&#xff1a; ● 保持客户和主要利益相关者所要求的质量水平。 ● 项目可交付成果是根据客户的规格和项目目标开发…

使用jenkins自动打包构建Maven项目

1.Jenkins是什么&#xff08;借鉴官网&#xff09; Jenkins是一款开源 CI&CD 软件&#xff0c;用于自动化各种任务&#xff0c;包括构建、测试和部署软件。 Jenkins 支持各种运行方式&#xff0c;可通过系统包、Docker 或者通过一个独立的 Java 程序 2.Jenkins下载安装 …

指纹和虚拟机哪个好用?两者之间的区别是什么?

2022年了&#xff0c;相信大家对指纹浏览器都不陌生了&#xff0c;很多做跨境电商、海外社媒营销、联盟营销的企业都会借助指纹浏览器来多账号批量管理。而在指纹浏览器没出现之前&#xff0c;大部分企业都会使用虚拟机来解决浏览器环境安全问题。所以指纹浏览器和虚拟机到底哪…

EN 14967:防水沥青防潮层—CE认证

防水沥青防潮层CE认证&#xff08;欧盟强制认证&#xff09;&#xff0d;简介 在欧盟市场“CE”标志属强制性认证标志&#xff0c;以表明产品符合欧盟《技术协调与标准化新方法》指令的基本要求。这是欧盟法律对产品提出的一种强制性要求。 在防水沥青防潮层上加贴CE标志不但可…

2021年全国职业院校技能大赛高职组“软件测试”赛项—“阶段二竞赛任务书”

2021年全国职业院校技能大赛高职组 “软件测试”赛项—“阶段二竞赛任务书” 2021年6月 软测讨论611474045 一、竞赛时间、内容及成绩组成 &#xff08;一&#xff09;竞赛时间 本阶段竞赛时间共为3小时&#xff0c;参赛选手自行安排任务进度&#xff0c;休息、饮水、如厕…