<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>test</title>
<meta charset="utf-8" />
<meta http-equiv="pragram" content="no-cache">
<meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="expires" content="0">
<meta name="viewport" content="width=device-width, user-scalable=no" />
<script src="https://unpkg.com/vue@2.6/dist/vue.min.js"></script>
<script src="https://unpkg.com/vant@2.12/lib/vant.min.js"></script>
<style>
.signature,
#sign,
.signature button {
box-sizing: border-box;
}
#sign {
position: relative;
}
.signBtn {
flex-shrink: 0;
height: 70px;
display: flex;
align-items: center;
justify-content: space-around;
}
#sign canvas {
width: 100%;
height: 100%;
}
.copyCanvas {
display: none;
}
.address {
margin: 1rem;
padding-bottom: 1rem;
margin-bottom: 0rem;
display: flex;
align-items: center;
justify-content: space-between;
}
.qianming img {
width: 1rem;
float: right;
margin-top: 4px;
}
.qianming button {
width: 1rem;
float: right;
display: flex;
justify-content: flex-end;
}
.qianming {
align-items: flex-start;
}
.signature {
background-color: #fff;
/* width: calc(100% - 2rem);
height: calc(100% - 2rem);
margin: 1rem; */
height: 100%;
width: calc(100vw - 2rem);
display: flex;
flex-direction: column;
justify-content: space-between;
}
.signature>div:first-child {
height: calc(100% - 70px - (0.6*16*2px));
border: 1px dashed #c1c1c1;
margin: 0.6rem;
}
.signature button {
color: #404040;
font-size: 1.2rem;
width: initial;
transform: rotate(90deg);
text-align: center;
width: 100%;
height: 100%;
border: none;
outline: none;
background-color: transparent;
padding: 0;
}
.mask {
position: absolute;
width: 100%;
height: 100%;
z-index: 1;
display: flex;
text-align: right;
}
canvas {
position: relative;
z-index: 2;
}
.mask div {
flex: 1;
position: relative;
}
.mask div span {
transform: rotate(90deg);
display: inline-block;
color: #c1c1c1;
position: relative;
right: 0;
top: 40px;
font-weight: 500;
}
.qianmings {
border-right: 1px dashed #c1c1c1;
}
.btns button {
padding: 0.7rem;
background-color: #5c92ff;
border-radius: 1.5rem;
font-size: 1.1rem;
box-shadow: 0px 2px 5px rgb(0 0 0 / 20%);
color: #fff;
width: 100%;
box-sizing: border-box;
margin-top: 15px;
}
.btns {
margin: 1rem;
}
.signBox {
width: calc(100vw - 2rem);
height: calc(100vh - 2rem);
overflow: hidden;
}
#copyCanvas {
display: none;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<!-- 旋转前 -->
<img src="" id="mysignature">
<!-- 旋转后 -->
<img :src="signature" id="mysignatureCopy">
<van-popup v-model="showUserSign" class="buyShow">
<user-sign :show-user-sign="showUserSign" @changepopup="changePopup" @signature="getSignature"></user-sign>
</van-popup>
</div>
</body>
<script>
/**
* 用户签名组件
*/
/* 注册全局组件 */
Vue.component('user-sign', {
template: `
<div class="signBox">
<canvas ref="copyCanvas" id="copyCanvas"></canvas>
<div class="signature">
<div id="sign" ref="fRoot">
<div class="mask">
<div class="qianmings">
<span>本人签名</span>
</div>
<div class="qmtime">
<span>签名时间</span>
</div>
</div>
</div>
<div class="signBtn">
<button @click="closeUserSign">关闭</button>
<button @click="clearCanvas">清除</button>
<button @click="saveCanvas">保存</button>
</div>
</div>
</div>
`,
props: ['showUserSign'],
data () {
return {
linewidth: 4,
color: '#404040',
background: 'transparent',
drawStatus: false,
cxt: '',
cxtCopy: '',
copy: '',
canvasStyle: {
width: '',
height: ''
}
};
},
mounted () {
this.initCanvas()
},
methods: {
closeUserSign () {
this.$emit('changepopup', false)
},
initCanvas () {
let canvas = document.createElement("canvas")
this.canvas = canvas
this.$refs.fRoot.appendChild(canvas)
let cxt = canvas.getContext("2d")
this.cxt = cxt
let width = this.$refs.fRoot.clientWidth
let height = this.$refs.fRoot.clientHeight
cxt.fillStyle = this.background;
canvas.width = width;
canvas.height = height;
this.canvasStyle.width = width;
this.canvasStyle.height = height;
// cxt.fillRect(0, 0, width, height);
cxt.strokeStyle = this.color;
cxt.lineWidth = this.linewidth;
cxt.lineCap = "round";
this.cxtCopy = this.$refs.copyCanvas.getContext("2d");
this.copy = this.$refs.copyCanvas
const offset = 24;
//开始绘制
canvas.addEventListener(
"touchstart",
function (e) {
this.drawStatus = true
cxt.beginPath();
cxt.moveTo(
e.changedTouches[0].pageX - offset,
e.changedTouches[0].pageY - offset
);
}.bind(this),
false
);
//绘制中
canvas.addEventListener(
"touchmove",
function (e) {
cxt.lineTo(
e.changedTouches[0].pageX - offset,
e.changedTouches[0].pageY - offset
);
cxt.stroke();
}.bind(this),
false
);
//结束绘制
canvas.addEventListener(
"touchend",
function () {
cxt.closePath();
}.bind(this),
false
);
},
clearCanvas () {
// 清除画布
this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.drawStatus = false
},
saveCanvas () {
// 保存图片,直接转base64
let imgBase64Copy = ''
let signature = ''
const imgBase64 = this.canvas.toDataURL();
const img = document.querySelector("#mysignature");
img.src = imgBase64;
img.onload = () => {
// 图片宽高
let iw = img.width
let ih = img.height
// canvas宽高
let cw = 145
let ch = 86
const opt = this.getXY(cw, ch, ih, iw)
this.cxtCopy.clearRect(0, 0, opt.rw, opt.rh)
this.cxtCopy.translate(0, opt.rh + opt.points[1])
this.cxtCopy.rotate(-Math.PI / 2)
this.cxtCopy.drawImage(img, opt.points[1], opt.points[0], opt.rh, opt.rw)
// 将有效部分图片截取
let frame = this.cxtCopy.getImageData(0, 0, opt.rw, opt.rh)
// 将canvas保持与图片大小相同
this.copy.height = opt.rh
this.copy.width = opt.rw
// 清除画布
this.cxtCopy.clearRect(0, 0, opt.rw, opt.rh)
// 重新绘制
this.cxtCopy.putImageData(frame, 0, 0)
imgBase64Copy = this.copy.toDataURL();
if (this.drawStatus) {
signature = imgBase64Copy;
} else {
signature = ''
}
this.drawStatus = false
this.clearCanvas()
this.$emit('signature', signature)
}
},
/**
* @description:
* @param {*} cw canvas宽度
* @param {*} ch canvas高度
* @param {*} iw img宽度
* @param {*} ih img高度
* @return {*}
*/
getXY (cw, ch, iw, ih) {
// 比较宽高比例,大的一边撑满
let li = iw / ih
let lc = cw / ch
// console.log('图片宽高比', li, 'canvas宽高比', lc);
// 需要绘制的宽高起点
let points = [0, 0]
let rw, rh
let wall = false // 是否宽度占满
if (li > lc) {
// 宽度100%,等比缩放
rw = cw
rh = rw / li
points[0] = 0
points[1] = (ch - rh) / 2
wall = true
} else {
rh = ch
rw = rh * li
points[0] = (cw - rw) / 2
points[1] = 0
wall = false
}
rw = Math.floor(rw)
rh = Math.floor(rh)
// console.log('canvas', cw, ch, 'img', iw, ih, '绘制', rw, rh);
return {
points,
rw,
rh
}
}
}
});
</script>
<!-- <script src="js/signature.js" defer="defer"></script> -->
<script>
new Vue({
el: '#app',
data () {
return {
showUserSign: true,
signature: ''
}
},
methods: {
getSignature (val) {
this.signature = val
this.showUserSign = false
},
goSign () {
this.showUserSign = true
},
changePopup (val) {
this.showUserSign = val
}
}
})
</script>
</html>
canvas实现图片旋转并保存 引用https://blog.csdn.net/qq_43585229/article/details/120045282