canvas图片旋转扩展出原生JS实现移动端横竖屏手写签名示例
前提知识
canvas是提供了各种各样的接口去控制画布,比如旋转rotate方法。
这里的旋转并不是真的把这个画布旋转了,例如ctx.rotate(90 * Math.PI / 180)顺时针旋转90°了,并不是说我们在页面上就会看到canvas旋转了90°。我们可以理解为其实canvas是有两个部分组成的,一个是肉眼看得到的画布,一个是用于操作的虚拟画布,我们所有在虚拟画布上的动作都会映射到真实画布中去。
旋转画布的原点默认画布的左上角(0,0)点,如图:

总结下,常用画布相关的知识点:
- 1.旋转画布的原点默认画布的左上角(0,0)点,可以使用ctx.translate(x, y)方法移动画布原点;
- 2.ctx.rotate(90 * Math.PI / 180)顺时针旋转90°,ctx.rotate(-90 * Math.PI / 180)逆时针旋转90°;
- 3.context.drawImage方法的使用,如下:
语法一-在画布上定位图像:
context.drawImage(img,x,y);
语法二-在画布上定位图像,并规定图像的宽度和高度:
context.drawImage(img,x,y,width,height);
语法三-剪切图像,并在画布上定位被剪切的部分:
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
参数值:
| 参数 | 描述 |
|---|---|
| img | 规定要使用的图像、画布或视频。 |
| sx | 可选。开始剪切的 x 坐标位置。 |
| sy | 可选。开始剪切的 y 坐标位置。 |
| swidth | 可选。被剪切图像的宽度。 |
| sheight | 可选。被剪切图像的高度。 |
| x | 在画布上放置图像的 x 坐标位置。 |
| y | 在画布上放置图像的 y 坐标位置。 |
| width | 可选。要使用的图像的宽度。(伸展或缩小图像) |
| height | 可选。要使用的图像的高度。(伸展或缩小图像) |
参考地址:《HTML5 canvas drawImage() 方法》。
- 4.会使用canvas的save和restore方法。
save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。 restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。
示例:
ar canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
context.lineWidth = "10";
context.strokeStyle = "#fe9901";
context.translate(canvas.width / 2, canvas.height / 2);
context.rotate( 30 / 180 * Math.PI);
context.beginPath();
context.moveTo(0, -180);
context.lineTo(0, -200);
context.stroke();
context.rotate( 30 / 180 * Math.PI);
context.beginPath();
context.moveTo(0, -140);
context.lineTo(0, -160);
context.stroke();
没有使用save,restore,第一次绘制时画布旋转30度,然后按照坐标绘制直线,第二次绘制在第一次基础上继续绘制,旋转30度,实际上相对于起点,旋转了60. 所以画出来两条直线不在一条指线上。
context.save();
context.rotate( 30 / 180 * Math.PI);
context.beginPath();
context.moveTo(0, -180);
context.lineTo(0, -200);
context.stroke();
context.restore(); context.rotate( 30 / 180 * Math.PI);
context.beginPath();
context.moveTo(0, -140);
context.lineTo(0, -160);
context.stroke();
第二次绘制加入save和restore, 再第一次绘制后,resore到起始状态,也就是现在画布又回到了0度位置,而不是30度,所以第二次绘制是从0度开始绘制,绘制出来应该和第一次的直线在一条指线上。
canvas移动与旋转示例
首先我们用如下图片绘制到canvas画布中,然后我们要保存旋转后的图片,如图所示。
画布图片:

旋转后保存的图片:

demo代码:
<!DOCTYPE html>
<html>
<head>
<title>canvas移动与旋转</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%;
}
.canvasparent {
width: 100px;
height: 200px;
margin: 100px auto 20px;
border: 1px solid #cccccc;
box-sizing: content-box;
position: relative;
}
#canvas {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 200px;
border-top-left-radius: 30px;
} </style>
</head>
<body>
<div class="canvasparent" id="canvasparent">
<canvas id="canvas"></canvas>
</div>
<img src="" id="img" style="border: 1px solid #ccc"/>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 100;
canvas.height = 200;
var img = new Image();
img.src = './images/1.jpg';
img.onload = function() {
ctx.drawImage(img,0,0,100,200);
var imgSRC = canvas.toDataURL('image/png', 1);
var img2 = new Image();
img2.src = imgSRC;
img2.onload = function() {
var clipCanvas = document.createElement("canvas");
var ctx2 = clipCanvas.getContext('2d');
clipCanvas.width = 200;
clipCanvas.height = 100;
ctx2.translate(0,100);
ctx2.rotate(-90 * Math.PI / 180);
ctx2.drawImage(img2,0,0,100,200);
var imgSRC2 = clipCanvas.toDataURL('image/png', 1);
document.getElementById('img').src = imgSRC2;
}
}
</script>
</html>
当然上面使用了translate和rotate,我们只有rotate和drawImage也是可以的,修改的JS代码如下:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 100;
canvas.height = 200;
var img = new Image();
img.src = './images/1.jpg';
img.onload = function() {
ctx.drawImage(img,0,0,100,200);
var imgSRC = canvas.toDataURL('image/png', 1);
var img2 = new Image();
img2.src = imgSRC;
img2.onload = function() {
var clipCanvas = document.createElement("canvas");
var ctx2 = clipCanvas.getContext('2d');
clipCanvas.width = 200;
clipCanvas.height = 100;
ctx2.rotate(-90 * Math.PI / 180);
ctx2.drawImage(img2,-100,0,100,200);
var imgSRC2 = clipCanvas.toDataURL('image/png', 1);
document.getElementById('img').src = imgSRC2;
}
}
手写签名demo
html代码:
<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>
CSS代码:
html,body {
padding:0;
margin:0;
width: 100%;
height: 100%;
}
.text-center {
text-align: center;
}
#signature-button {
display: block;
margin: 0 auto;
}
#signature-img {
width: 200px;
height: 100px;
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: #cccccc;
box-sizing: border-box;
text-align: center;
}
.demo-top-info .return {
padding-left: 5px;
height: 40px;
line-height: 40px;
position: absolute;
left: 10px;
display: inline-block;
}
.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 40px 0;
}
.canvas-parent {
width: 100%;
height: 100%;
}
.demo-bottom-info {
position: absolute;
bottom:0;
left:0;
width: 100%;
height: 40px;
background: #cccccc;
padding: 0 2%;
box-sizing: border-box;
overflow: hidden;
}
#clean_canvas {
float: left;
font-size: 18px;
margin-top: 2px;
background: #f8f8f8;
border: 1px solid #ddd;
padding: 5px 10px;
border-radius: 4px;
}
#sure_canvas {
float: right;
padding: 3px 0;
background: #00005F;
padding: 5px 10px;
border: 1px solid #00005F;
border-radius: 4px;
color: #fff;
margin-top: 3px;
}
#canvas2 {
position: absolute;
top: 0;
left:0;
z-index: 999;
margin-left: 40px;
}
JS代码:
// 手绘签名类
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 = 1;
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 = 1;
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);
}
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) {
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);
完整的demo代码:
<!DOCTYPE html>
<html>
<head>
<title>手写签名demo</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;
}
#signature-img {
width: 200px;
height: 100px;
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: #cccccc;
box-sizing: border-box;
text-align: center;
}
.demo-top-info .return {
padding-left: 5px;
height: 40px;
line-height: 40px;
position: absolute;
left: 10px;
display: inline-block;
}
.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 40px 0;
}
.canvas-parent {
width: 100%;
height: 100%;
}
.demo-bottom-info {
position: absolute;
bottom:0;
left:0;
width: 100%;
height: 40px;
background: #cccccc;
padding: 0 2%;
box-sizing: border-box;
overflow: hidden;
}
#clean_canvas {
float: left;
font-size: 18px;
margin-top: 2px;
background: #f8f8f8;
border: 1px solid #ddd;
padding: 5px 10px;
border-radius: 4px;
}
#sure_canvas {
float: right;
padding: 3px 0;
background: #00005F;
padding: 5px 10px;
border: 1px solid #00005F;
border-radius: 4px;
color: #fff;
margin-top: 3px;
}
#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 = 1;
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 = 1;
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);
}
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) {
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>
canvas图片旋转扩展出原生JS实现移动端横竖屏手写签名示例的更多相关文章
- 【原】js检测移动端横竖屏
摘要:上周做了一个小项目,但是要放到我们的app上,然而需要横竖屏使用不同的样式.横屏一套,竖屏一套.调用了手机APP那里的api,可是他们那里ios和安卓返回的不一样. 各种头疼.于是用了css3的 ...
- JS检测移动端横竖屏
(function () { var supportOrientation = (typeof window.orientation == ...
- HTML 5 +CSS3 + 原生js 做(雪花全屏飘落 + 3d旋转图)
原文:HTML 5 +CSS3 + 原生js 做(雪花全屏飘落 + 3d旋转图) 3d旋转图:主要用css3中transform属性中的rotate,translate;以及用来做舞台效果的 pers ...
- 用js实现web端录屏
用js实现web端录屏 原创2021-11-14 09:30·无意义的路过 随着互联网技术飞速发展,网页录屏技术已趋于成熟.例如可将录屏技术运用到在线考试中,实现远程监考.屏幕共享以及录屏等:而在我们 ...
- canvas画布实现手写签名效果
最近项目中涉及到移动端手写签名的功能需求,将实现代码记录于此,供小伙伴们参考指摘哦~ HTML代码: <!--手写区--> <div class="mSign_signMa ...
- js判断手机的横竖屏调整样式
在移动端,我们经常遇到横竖屏的问题,所以我们改如何判断或针对横竖屏来写代码呢.首先需要在head中加入如下代码: <meta name="viewport" content= ...
- Blazor组件自做二 : 使用JS隔离制作手写签名组件
Blazor组件自做二 : 使用JS隔离制作手写签名组件 本文相关参考链接 JavaScript 模块中的 JavaScript 隔离 Viewer.js工程 Blazor组件自做一 : 使用JS隔离 ...
- uni-app通过canvas实现手写签名
分享一个uni-app实现手写签名的方法 具体代码如下: <template> <view > <view class="title">请在下面 ...
- js移动端横竖屏检测
方法一:用resize事件来判断,利用屏幕的宽高比,来判断横竖屏 (兼容性较好) (function () { var updateOrientation = function () { var or ...
- 原生 JS 实现移动端 Touch 滑动反弹
什么是 Touch滑动?就是类似于 PC端的滚动事件,但是在移动端是没有滚动事件的,所以就要用到 Touch事件结合 js去实现,效果如下: 1. 准备工作 什么是移动端的 Touch事件?在移动端 ...
随机推荐
- sheetjs导出表格时间错误问题
最近使用sheetjs,前端web去导出生成excel,xlsx表格.其中遇到一种问题,那就是时间出错了!比如多出8小时43秒,少了43秒.看到这种问题的时候,我也一脸懵逼.先上图! 不过在有些人电脑 ...
- jQuery 插件autocomplete 应用
项目中有时会用到自动补全查询,就像Google搜索框.淘宝商品搜索功能,输入汉字或字母,则以该汉字或字母开头的相关条目会显示出来供用户选择, autocomplete插件就是完成这样的功能. auto ...
- Centos7 安装 rabbitmq-server-3.7.7 图文教程
下载 rabbitmq-server wget https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.7.7/rabbitmq-server-3. ...
- 数据仓库建模工具之一——Hive学习第二天
Hive的概述 1.Hive基本概念 1.1 Hive简介 Hive本质是将SQL转换为MapReduce的任务进行运算,底层由HDFS来提供数据存储,说白了hive可以理解为一个将SQL转换为Map ...
- [oeasy]python0016_在vim中直接运行python程序
回忆上次内容 上次 置换 esc 和 caps lock 任何操作 都可以在 不移动 手腕的状态下完成了 每次都要 退出vim编辑器 才能 在shell中 运行python程序 有点麻烦 想要 不退出 ...
- C#/.NET/.NET Core优秀项目和框架2024年7月简报
前言 公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍.功能特点.使用方式以及部分功能截图 ...
- 5、SpringMVC之域对象共享数据
5.1.域对象简介 请求域(request):一次请求范围内有效 会话域(session):一次会话范围内有效 应用域(application):整个应用范围内有效 5.2.环境搭建 5.2.1.右击 ...
- 【MySQL】字符联合主键过长 Specified key was too long; max key length is 767 bytes
MySQL版本: 这个情况在 8.0.28版本没有出现 报错如图 建表SQL: DROP TABLE IF EXISTS `pt_dict_common`; CREATE TABLE `pt_dict ...
- 【Scala】01 基础了解
Features 特性 1.基于JVM,完全兼容Java 2.同样具有跨平台,可移植,垃圾回收 3.比Java更加的面向对象[完全面向对象] 4.函数式编程 5.面向大数据处理,对集合容器框架有一定的 ...
- 【Mybatis】12 复杂关联查询
一对多 & 多对一 关联查询 数据库准备: 一个班级表,字段:班级ID + 班级名称 一个学生表,字段:学生ID + 学生姓名 + 所属的班级ID # 班级表 班级ID+班级名称 CREATE ...