web前端 原生js签名板(电子签名)写字板 canvas 截图
移动端在开发的时候,可能会涉及到手写签名(电子签名)那些,在前端的思路是使用canvas 来签名,导出成图片进行保存。
仅供参考和学习。
vue版本: https://blog.csdn.net/qq_33270001/article/details/102855964
注意:在移动端使用的时候, 写竖的时候, 页面会被往下拉, 手写板动了, 写字不顺畅. 建议在移动端的touchmove事件里, 加一行防止页的滑动事件, 代码是: event.preventDefault();
<!DOCTYPE html>
<!-- saved from url=(0056)http://hao2013.cn/canvas-special-master/brush/index.html -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>签名板(支持移动端)</title>
</head>
<style type="text/css">
*{margin: 0;padding: 0;}
.canvas {
/*width: 100%;*/
display: block;
border: 1px solid red;
}
#clear,
#clear1,
#save {
margin: 0 auto;
display: inline-block;
padding: 5px 10px;
width: 50px;
height: 40px;
line-height: 40px;
border: 1px solid #eee;
background: #e1e1e1;
border-radius: 10px;
text-align: center;
margin: 20px auto;
cursor: pointer;
}
</style>
<body data-ext-version="1.4.2">
<canvas id="canvas" width="600" height="600">您的浏览器不支持canvas技术,请升级浏览器!</canvas>
<div style="text-align: center">
<span id="clear">清空</span>
<span id="save">保存</span>
</div>
</body>
<script type="text/javascript">
function WriteFont(id, options) {
var self = this;
this.canvas = document.getElementById(id);
var obj = {
canvas: this.canvas,
context: this.canvas.getContext("2d"),
isWrite: false, //是否开始
lastWriteTime: -1,
lastWriteSpeed: 0,
lastWriteWidth: 0,
canvasWidth: 600, //canvas宽高
canvasHeight: 600,
isShowBorder: true, //是否显示网格
bgColor: '#fff', //背景色
borderWidth: 2, // 网格线宽度
borderColor: "#fff", //网格颜色
lastPoint: {}, //
writeWidth: 2, //基础轨迹宽度
maxWriteWidth: 30, // 写字模式最大线宽
minWriteWidth: 1, // 写字模式最小线宽
writeColor: '#000', // 轨迹颜色
isWriteName:false //签名模式
}for(var name in options) {
obj[name] = options[name];
}/**
* 轨迹宽度
*/
this.setLineWidth = function() {
var nowTime = new Date().getTime();
var diffTime = nowTime - obj.lastWriteTime;
obj.lastWriteTime = nowTime;
var returnNum = obj.minWriteWidth + (obj.maxWriteWidth - obj.minWriteWidth) * diffTime / 30;
if(returnNum < obj.minWriteWidth) {
returnNum = obj.minWriteWidth;
} else if(returnNum > obj.maxWriteWidth) {
returnNum = obj.maxWriteWidth;
}returnNum = returnNum.toFixed(2);
//写字模式和签名模式
if(obj.isWriteName){
obj.context.lineWidth = obj.writeWidth;
}else{
obj.context.lineWidth = obj.lastWriteWidth = obj.lastWriteWidth / 4 * 3 + returnNum / 4;
}
}/**
* 绘制轨迹
*/
this.writing = function(point) {
obj.context.beginPath();
obj.context.moveTo(obj.lastPoint.x, obj.lastPoint.y);
obj.context.lineTo(point.x, point.y);
self.setLineWidth();
obj.context.stroke();
obj.lastPoint = point;
obj.context.closePath();
}/**
* 轨迹样式
*/
this.writeContextStyle = function() {
obj.context.beginPath();
obj.context.strokeStyle = obj.writeColor;
obj.context.lineCap = 'round';
obj.context.lineJoin = "round";
}/**
* 写开始
*/
this.writeBegin = function(point) {
obj.isWrite = true;
obj.lastWriteTime = new Date().getTime();
obj.lastPoint = point;
self.writeContextStyle();
}/**
* 写结束
*/
this.writeEnd = function() {
obj.isWrite = false;
}/**
* 清空画板
*/
this.canvasClear = function() {
obj.context.save();
obj.context.strokeStyle = '#fff';
obj.context.clearRect(0, 0, obj.canvasWidth, obj.canvasHeight);
if(obj.isShowBorder && !obj.isWriteName) {
obj.context.beginPath();
var size = obj.borderWidth / 2;
//画外面的框
obj.context.moveTo(size, size);
obj.context.lineTo(obj.canvasWidth - size, size);
obj.context.lineTo(obj.canvasWidth - size, obj.canvasHeight - size);
obj.context.lineTo(size, obj.canvasHeight - size);
obj.context.closePath();
obj.context.lineWidth = obj.borderWidth;
obj.context.strokeStyle = obj.borderColor;
obj.context.stroke();
//画里面的框
obj.context.moveTo(0, 0);
obj.context.lineTo(obj.canvasWidth, obj.canvasHeight);
obj.context.lineTo(obj.canvasWidth, obj.canvasHeight / 2);
obj.context.lineTo(obj.canvasWidth, obj.canvasHeight / 2);
obj.context.lineTo(0, obj.canvasHeight / 2);
obj.context.lineTo(0, obj.canvasHeight);
obj.context.lineTo(obj.canvasWidth, 0);
obj.context.lineTo(obj.canvasWidth / 2, 0);
obj.context.lineTo(obj.canvasWidth / 2, obj.canvasHeight);
obj.context.stroke();}
obj.context.restore();
}/**
* 保存图片 格式base64
*/
this.saveAsImg = function() {
var image = new Image();
image.src = this.canvas.toDataURL("image/png");
if(image.src == this.emptyCanvas) {
alert('请先书写')
} else {
console.log('提交的内容===>', image.src)
}
};/**
* 初始化画板
*/
this.canvasInit = function() {
this.canvas.width = obj.canvasWidth;
this.canvas.height = obj.canvasHeight;
this.emptyCanvas = this.canvas.toDataURL("image/png");
}/**======================事件绑定===========================**/this.canvas.addEventListener('mousedown', function(e) {
var point = {
x: e.offsetX || e.clientX,
y: e.offsetY || e.clientY
};
self.writeBegin(point);
});this.canvas.addEventListener('mouseup', function(e) {
var point = {
x: e.offsetX,
y: e.offsetY
};
self.writeEnd(point);
});this.canvas.addEventListener('mouseleave', function(e) {
var point = {
x: e.offsetX,
y: e.offsetY
};
self.writeEnd(point);
});this.canvas.addEventListener('mousemove', function(e) {
if(obj.isWrite) {
var point = {
x: e.offsetX,
y: e.offsetY
};self.writing(point);
}
});//移动端
this.canvas.addEventListener('touchstart', function(e) {
var touch = e.targetTouches[0];
var point = {
x: touch.pageX || touch.clientX,
y: touch.pageY || touch.clientY
};
self.writeBegin(point);
});
this.canvas.addEventListener('touchend', function(e) {
var touch = e.changedTouches[0];
var point = {
x: touch.pageX,
y: touch.pageY
};
self.writeEnd(point);
});
this.canvas.addEventListener('touchmove', function(e) {
var touch = e.targetTouches[0];
var point = {
x: touch.pageX,
y: touch.pageY
};
self.writeEnd(point);
});
this.canvas.addEventListener('touchmove', function(e) {
var touch = e.targetTouches[0];
var point = {
x: touch.pageX,
y: touch.pageY
};
self.writing(point);
});this.canvasInit();
this.canvasClear();this.option = obj;
obj.control = {
clearCanvas: self.canvasClear
};
}/**
* 初始化调用
* 设置参数
*/
var writeCanvas = new WriteFont('canvas', {
borderWidth: 10,
writeWidth:3,
borderColor: '#ff6666',
isWriteName:true //签名模式
});document.getElementById('clear').onclick = function() {
writeCanvas.option.control.clearCanvas();
};document.getElementById('save').onclick = function() {
writeCanvas.saveAsImg()
};
</script>
</html>
效果图如下:
保存的时候是 base 64的图片
附上demo和源码
附件地址: http://hao2013.cn/zb_users/upload/2018/07/201807291807177677029.zip
参考:http://hao2013.cn/?id=41
web前端 原生js签名板(电子签名)写字板 canvas 截图相关推荐
- 好程序员web前端分享js剪切板Clipboard.js 使用
好程序员web前端分享js剪切板Clipboard.js 使用,clipboard.js是一个用来设置剪切板的库,小巧无依赖,但用法有点诡异,必须依赖一个DOM元素. 必须要与一个DOM元素相关联,并 ...
- 好程序员web前端分享JS引擎的执行机制
好程序员web前端分享JS引擎的执行机制,请先着重牢记两点!JS是单线程语言. JS的EventLoop是JS的执行机制.深入了解JS的执行,就等于深入了解JS里的eventloop. 1.灵魂三问: ...
- Web前端-Vue.js必备框架(一)
Web前端-Vue.js必备框架(一) <!DOCTYPE html> <html lang="en"> <head><meta char ...
- js 点击闭包_【新年跳槽必备】2020最新(前端原生JS专题)面试题 速领!
最近我把每周更新的面试题 发在我们的学习群里 大家似乎都很高冷哇 难道是默默的做题去了没说话 每期面试题都是Richard老师认真准备的 真的希望能帮到大家哦 本期是前端原生JS专题 A前端原生JS专 ...
- 手机端移动端的前端原生js裁剪图片上传
手机端移动端的前端原生js裁剪图片上传 选择头像时裁剪上传,确保图片是个正方形,不会出现压扁拉伸的现象 效果图 原理很简单,其实就是用canvas截图出来而已,只是要对比例做一下处理. <!-- ...
- Web前端,JS基础之ATM取款机案例
前言 持续学习总结输出中,今天分享的是Web前端,JS基础之ATM取款机案例 需求 用户在ATM取款时可以选择存钱.取钱.查看余额和退出功能 分析 1.循环的时候,需要反复提示输入框,所以提示框写要到 ...
- Web前端-Vue.js必备框架(二)
Web前端-Vue.js必备框架(二) vue调式工具vue-devtools 过滤器:vue.js允许你自定义过滤器,可被用作一些常见的文本格式化. mustache插值和v-bind表达式. vu ...
- web前端面试 js部分
1/如何用原生js给一个按钮绑定过两个click事件 var obtn = document.getElementById('btn'); obtn.addEventListener('click', ...
- 前端原生js实现图片轮播效果,超级简单,备注详细
原生js实现简单轮播图,效果如下 纯生js实现轮播图 链接: link. 图片: 我们可以通过左右两边的箭头来播放图片,在我们的鼠标放在图片上时,自动播放结束,转化为手动播放,可以通过小圆点来点击切换 ...
- web前端培训JS 运行机制的梳理
展现形式:由于是属于系统梳理型,就没有由浅入深了,而是从头到尾的梳理知识体系, 重点是将关键节点的知识点串联起来,而不是仅仅剖析某一部分知识. 内容是:从浏览器进程,再到浏览器内核运行,再到JS引擎单 ...
最新文章
- 把企业分“三只鸟”的发展好比“三个策略”
- linux内核模块编译出现找不到include/generated/asm/unistd_32.h” 问题解决
- 启用物料账后,有两种物料价格确定方式
- 十八个超经典故事 绝对不会后悔
- numpy的基本使用2
- Python3 正则相关
- LED 将为我闪烁: 控帘 j发光二级管
- mysql复杂条件判断_MySQL复杂where条件分析
- Java中的Random()函数 【转载】
- 使用C#的后端Web API:循序渐进教程
- 让我们手动计算:深入研究Logistic回归
- 人工智能与自动驾驶汽车_自动驾驶汽车中的道德AI
- SciTE AMPL配置问题
- 机器人手眼标定原理介绍(含详细推导过程)使用Tsai-Lenz算法
- python读取同花顺数据_python爬取同花顺数据
- android修改shell串口号,[Note] 2021-01-15 Android shell/串口中使用 wpa_cli 连接Wi-Fi
- 阿德勒心理学(自我剖析)
- 金彩教育:店铺运营怎么看数据
- 如何理解图片RGB通道在python(numpy)中的数据构成
- [魔方]魔方七步初级教程