H5手写板电子签名开发

article/2025/7/2 9:47:40

 

如图所示:前端实现H5+canvas手写板电子签名:<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /><title>签名</title><!-- 引入 Vue 和 Vant 的 JS 文件 --><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vant@2.9/lib/index.css" /><!-- 引入 Vue 和 Vant 的 JS 文件 --><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script><script src="https://cdn.jsdelivr.net/npm/vant@2.9/lib/vant.min.js"></script><style>body,html {margin: 0 auto;width: 100%;padding: 0;height: 100%;}.appview{display: flex;flex: 1;margin: 0 auto;width: 95%;padding: 10px 0px;}
#app{position: relative;text-align: center;width: 100%;margin: 0 auto;/* margin-top: 10px; */
}#canvas {border:1px solid #333;}#canvas-btn {display: block;margin: 0;/* padding: 0.3rem; */}#clear_btn {width:40px;/* background: #999; */margin: auto;text-align: center;line-height: 1rem;margin-top: 0.27rem;height: 86px;margin-top: 80px;line-height: 86px;color: #fff;border-radius:5px;clear: both;}#save_btn {width:43px;/* background: #2b85e4; */margin: auto;text-align: center;line-height: 1rem;height: 86px;line-height: 86px;margin-top: 0.27rem;color: #fff;border-radius:5px;clear: both;}.span{-moz-transform: rotate(90deg);-webkit-transform: rotate(90deg);display: block;position: absolute;  left: 10px;       filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)}</style>
</head><body><div id="app"><div class="appview"><div id="canvas-btn"><!-- <div id="clear_btn" class="op_btn"></div> --><img src="./img/btn1.png" id="clear_btn" class="op_btn"><!-- <div id="save_btn" class="save_btn"><span class="span">完成签名</span> --><img src="./img/btn2.png" id="save_btn" class="save_btn"><!-- </div> --><div class="cleaerfix"></div></div><canvas id='canvas'></canvas></div></div><script src="./js/config.js"></script><script type="text/javascript" src="./js/jquery.min.js"></script><script type="text/javascript" src="./js/flexible.debug.js"></script><script type="text/javascript" src="./js/zepto.js"></script><script type="text/javascript" src="./js/touch.js"></script><script type="text/javascript" src="./js/flexible.debug.js"></script><script type="text/javascript" src="./js/flexible_css.debug.js"></script><script>//获取页面尺寸  var canvasWidth = document.body.clientWidth;var canvasHeight = 600;//声明canvas  var canvas = document.getElementById('canvas');var context = canvas.getContext('2d');//设置canvas尺寸  canvas.width = canvasWidth * 0.8;canvas.height = canvasHeight;//画笔颜色  var strokeColor = "#333";//鼠标  isMouseDown = false;//上一次绘制的的坐标  var lastLoc = { x: 0, y: 0 };//初始记录事件  var lastTimestamp = 0;//上一次线条宽度  var lastLineWidth = -1;//var   var maxV = 10;var minV = 0.1;var maxLineWidth = 5;var minLineWidth = 1;//点击色块切换画笔颜色  $(".colorBtn").on("click", function (e) {$(".colorBtn").removeClass('colorBtnBorder');$(this).addClass("colorBtnBorder");strokeColor = $(this).css("");})//清除  $('#clear_btn').on('click', function (e) {context.clearRect(0, 0, canvasWidth, canvasHeight);});//保存画图$('#save_btn').on('click', function (e) {var image = canvasToImage(canvas);console.log("image", image)console.log(image);});//获取canvas 坐标 x,y 分别代表相对window内的xy  function windowToCanvas(x, y) {//canvas提供的方法返回canvas 距 他外围包围盒子的距离left,top值  var bbox = canvas.getBoundingClientRect();//返回的就是canvas 内的坐标值  return { x: Math.round(x - bbox.left), y: Math.round(y - bbox.top) }}//封装 事件  function beginStroke(point) {isMouseDown = true;//第一次用户画的坐标初始值  lastLoc = windowToCanvas(point.x, point.y);//获取首次点击鼠标 事件戳  lastTimestamp = new Date().getTime();}function endStroke() {isMouseDown = false;}function moveStroke(point) {//开始绘制直线  var curLoc = windowToCanvas(point.x, point.y);//路程  var s = calcDistance(curLoc, lastLoc);//结束时间  var curTimestamp = new Date().getTime();//时间差  var t = curTimestamp - lastTimestamp;//绘制线条粗细  var lineWidth = calcLineWidth(t, s);//绘制context.beginPath();context.moveTo(lastLoc.x, lastLoc.y);context.lineTo(curLoc.x, curLoc.y);context.strokeStyle = strokeColor;context.lineWidth = lineWidth;context.lineCap = "round";context.lineJoin = "round";context.stroke();//给lastLoc赋值维护  lastLoc = curLoc;//时间更新  lastTimestamp = curTimestamp;lastLineWidth = lineWidth;}//pc鼠标事件  canvas.onmousedown = function (e) {e.preventDefault();beginStroke({ x: e.clientX, y: e.clientY });}canvas.onmouseup = function (e) {e.preventDefault();endStroke();}canvas.onmouseout = function (e) {e.preventDefault();endStroke();}canvas.onmousemove = function (e) {e.preventDefault();if (isMouseDown) {moveStroke({ x: e.clientX, y: e.clientY });}}//移动端  canvas.addEventListener("touchstart", function (e) {e.preventDefault();touch = e.touches[0]; //限制一根手指触碰屏幕  beginStroke({ x: touch.pageX, y: touch.pageY });});canvas.addEventListener("touchend", function (e) {e.preventDefault();endStroke();});canvas.addEventListener("touchmove", function (e) {e.preventDefault();if (isMouseDown) {touch = e.touches[0];moveStroke({ x: touch.pageX, y: touch.pageY });}});//速度 = 路程 / 时间     用来计算书写速度来改变线条粗细  function calcDistance(loc1, loc2) {//返回 数的平方根  return Math.sqrt((loc1.x - loc2.x) * (loc1.x - loc2.x) + (loc1.y - loc2.y) * (loc1.y - loc2.y));}//线条宽度  function calcLineWidth(t, s) {var v = s / t;var resultLineWidth;if (v <= minV) {resultLineWidth = maxLineWidth;} else if (v >= maxV) {resultLineWidth = minLineWidth;} else {resultLineWidth = maxLineWidth - (v - minV) / (maxV - minV) * (maxLineWidth - minLineWidth);}if (lastLineWidth == -1) {return resultLineWidth;} else {return lastLineWidth * 2 / 3 + resultLineWidth * 1 / 3;}}// 将canvas转换成画布function canvasToImage(canvas) {var image = new Image();console.log("----", canvas.toDataURL("image/png"));var that = this;var formData = new FormData();formData.append("file", canvas.toDataURL("image/png"));// return;// 请求登录接口$.ajax({url: config.upBase64Pic+"?appid=7",async: false,type: "POST",data: formData,dataType: "json",processData: false,contentType: false,// dataType: 'json',success: function (data) {console.log("上传==》", data)if (data.code == 200) {localStorage.setItem("fast", data.fast);localStorage.setItem("local", data.local);window.location.href="./agreement.html"} else {vant.Toast({message: "上传异常~",forbidClick: true,});}},error: function (data, res, res2) {console.log(data, res, res2)vant.Toast({message: '网络忙',forbidClick: true,});}});image.src = canvas.toDataURL("image/png");// console.log("")return image;}</script>
</body></html>

 


http://chatgpt.dhexx.cn/article/y2SEcy0D.shtml

相关文章

uniapp - 实现微信小程序电子签名板,横屏手写姓名签名专用写字画板(详细运行示例,一键复制开箱即用)

效果图 实现了在uniapp项目中,微信小程序平台流畅的写字签名板(也可以绘图)功能源码,复制粘贴,改改样式几分钟即可搞定! 支持自动横屏、持预览,真机运行测试非常流畅不卡顿。 基础模板 如下代码所示。 <template><view class=

Vue Canvas 实现电子签名 手写板

直接上代码 <template><section class"signature"><div class"signatureBox"><div class"canvasBox" ref"canvasHW"><canvas ref"canvasF" touchstarttouchStart touchmovetouchMove touchendt…

锁---一些锁学习

1、java锁之公平锁和非公平锁 公平锁 是指多个线程按照申请的顺序来获取&#xff0c;类似排队打饭&#xff0c;先来后到。 非公平锁 是指多个线程获取锁的顺序并不是按照申请锁的顺序&#xff0c;有可能后申请的线程比先申请的线程优先获取锁&#xff0c;在高并发的情况下&a…

C# 实现锁屏

首先&#xff0c;将窗体的FormBorderStyle设置为none&#xff0c;WindowState设为Maximized 让窗体占据整个页面。 form窗体代码&#xff1a; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using …

win11中睡眠唤醒后如何禁止锁屏界面及登录界面

第一步禁止锁屏界面 gpedit.msc 不显示锁屏-》已启用 第二步&#xff1a;不显示登陆框 netplwiz 经过以上设置以后&#xff0c;打开笔记本就可以直接显示桌面了。

办公计算机锁屏方法,电脑快速锁屏,办公室神技能,再也不怕别人看我的电脑了!...

原标题&#xff1a;电脑快速锁屏&#xff0c;办公室神技能&#xff0c;再也不怕别人看我的电脑了&#xff01; 现在快节奏的社会&#xff0c;电脑的更方面性能与功能是非常之大&#xff0c;我们对电脑的使用频率也越来越高&#xff0c;可见它对我们生活越来越重要。在我们平时使…

Android锁屏的解锁(九个点),使用画的方式,大致的步骤

这篇博客是全部代码(没有解释,纯代码): https://blog.csdn.net/weixin_44614751/article/details/103101104 效果: 第一步:添加背景 第二步:创建九个点 先读取每一个点的图片: creatDot 创建九个点: initNin

ubuntu 18.04取消自动锁屏功能

有时候几分钟不用Ubuntu&#xff0c;系统就自动锁屏了&#xff0c;这是一种安全措施&#xff0c;防止别人趁你不在时使用你的系统。但对于大部分人而言&#xff0c;这是没有必要的&#xff0c;尤其是Ubuntu虚拟机&#xff0c;里面没啥重要的东西&#xff0c;每次锁屏后需要重新…

Android 通知栏,锁屏播放音乐,类似音乐播放器

项目中需要用到播放音频的功能&#xff0c;想做一个类似酷狗、酷我这样的音频播放功能&#xff0c;在通知栏和锁屏时都可以操控音乐&#xff0c;开发中发现oppo reno手机在锁屏时不显示通知栏&#xff0c;研究了整整一天终于解决&#xff0c;特作记录&#xff0c;给遇到同样问题…

Android自定义锁屏实现----仿正点闹钟滑屏解锁

本文原创&#xff0c;转载请注明出处&#xff1a;http://blog.csdn.net/qinjuning 前几周看了下解锁的框架&#xff0c;基本上算是弄了个脸熟。看着别人花哨的解锁界面&#xff0c;心里也很痒痒的。于是&#xff0c;画了一天时间&#xff0c; 捣鼓出了这个成果----仿正点闹钟解…

易安卓打开Android系统中的解锁方式选择页面(锁屏方式选择)

感谢名单 感谢fylfyl2写的https://blog.csdn.net/fyilun/article/details/21257595 E4A打开锁屏方式页面 Intent intent new Intent(); ComponentName cm new ComponentName("com.android.settings","com.android.settings.ChooseLockGeneric"); inte…

Android锁屏的解锁(九个点),使用画的方式

一、效果展示: 这篇博客有解释大概的步骤: https://blog.csdn.net/weixin_44614751/article/details/103101199 二、代码部分: MainActivity.java中的代码: package com.example.drawunlock1;import androidx.appcompat.app.AppCompatActivity;import android.content.re…

让电脑不被锁屏的方法,亲测有效

通过JS来控制键盘&#xff0c;定时按下SCROLLLOCK键&#xff0c;达到电脑不会被锁屏的效果。 通常公司电脑都会自动锁屏&#xff0c;只是时间有长短。有时候闲着了不用电脑&#xff0c;但是却不想让电脑锁屏。那么可以用js代码来控制键盘的按键循环按下实现不锁屏的效果&#x…

android 强制锁屏app,自制力app强制锁屏

自制力app强制锁屏非常适合在学习工作中没有自律性的用户们&#xff0c;当打开app后开启锁屏状态&#xff0c;手机就打不开了&#xff0c;重启也不可能解除锁屏&#xff1b;在此期间&#xff0c;就可以免于手机的打扰&#xff0c;专注学习&#xff1b;感兴趣的小伙伴们快来下载…

android系统密码设置功能,手机锁屏密码怎么设置 三种安卓手机锁屏方式推荐

手机中有很多应用都是与金钱挂钩&#xff0c;特别是微信与支付宝等等既涉及到隐私又与财产关联&#xff0c;这是后手机的安全就尤为重要的&#xff0c;而手机的锁屏密码就是一道最基本的防护措施&#xff0c;那么手机锁屏密码怎么设置?来看看小编推荐的三种安卓手机锁屏方式吧…

Mac锁屏的几种方式

刚换了工作&#xff0c;公司里给配了MacBook&#xff0c;第一次使用&#xff0c;很多常见操作都不知道快捷键&#xff0c;今天来记录下锁屏的几种方式&#xff1a;电脑为MacBook Pro&#xff0c;OS为MacOS Sierra 10.12.3 1. ctrl shift 右上角开关机键 2. option comm…

C语言for循环结构经典练习

文章目录 一、for循环基本知识二、经典例题及解析1.水仙花数2.求规定范围内的完数3.求规定范围内质数4.计算阶乘之和5.计算55555555555555(类型)6.计算112123123412345(类型)7.判断用户输入正整数的位数8.判断某正整数是否为回文数9.九九乘法表10.统计用户输入的字符中&#xf…

Java基础语法——循环结构

每日正能量 趁你现在还有时间&#xff0c;尽你自己最大的努力&#xff0c;努力做成你最想做的那件事&#xff0c;成为你最想成为的那种人&#xff0c;过着你最想过的那种生活。这个世界永远比你想的要更精彩&#xff0c;不要败给生活。 循环结构 【本章内容】1. while循环 2. d…

Python - 循环结构

循环结构 &#x1f40d;While循环&#x1f40d;While…else…循环&#x1f40d;for循环&#x1f40d;for…else…循环&#x1f40d;循环体结束语句&#x1f40d;嵌套循环 本次主要介绍的是程序的循环结构逻辑。 循环就是按照一定的条件重复的去做一件事情&#xff0c;当条件不成…

While循环结构

1.while循环语句 1.1循环概念 循环是程序设计语言中反复执行某些代码的一种计算机处理过程 1.2 while循环的作用 重复执行某些代码 1.3 while循环的基本语法 while 条件&#xff1a; ____反复执行的代码 …… while及while中的代码块就是while循环代码块。看以下示例&#…