手机竖屏
手机横屏
<template>
<div style="width:100%;height:100%;padding:0.1rem;">
<div v-if="direction=='horizontal'" class="mydraw2">
<div class="cont buttonDiv2 commoBtn2">
<yd-button @click.native="clear">
<span>清除</span>
</yd-button>
<yd-button @click.native="save" :loading="saveLoading">
<span>保存</span>
</yd-button>
</div>
<div class="cont canvasDiv2">
<canvas
id="canvas"
ref="mycanvas"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
>Canvas画板</canvas>
</div>
<div class="cont signLabelDiv2">
<p>签 字</p>
</div>
</div>
<div v-else style='text-align: center'>
<div>
<p style='font-size: 0.3rem;height: 30px;margin-top: 10px;'>签 字</p>
<div class="cont canvasDiv" style="width: 100%">
<canvas
id="canvas"
ref="mycanvas"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
>Canvas画板</canvas>
</div>
<div style="margin-top: 10px">
<yd-button @click.native="clear">
<span>清除</span>
</yd-button>
<yd-button @click.native="save" :loading="saveLoading" style='margin-left: 10px'>
<span>保存</span>
</yd-button>
</div>
</div>
</div>
</div>
</template>
<script>
import html2canvas from '../../node_modules/html2canvas'
import { getSignature } from '@/api/auth'
import Util from '@/libs/util.js'
export default {
data() {
return {
direction: 'vertical', // 画板方向 vertical horizontal
colors: [
{ color: 'black', active: true },
{ color: 'red', active: false },
{ color: 'blue', active: false }
], // 可选颜色
ctx: '', // canvas对象
stage_info: '', // mycanvas的大小及其相对于视口的位置
canvasWidth: '', // canvas宽度
canvasHeight: '', // canvas高度
lineColor: 'black', // 线条的颜色
lineWidth: 5, // 线条宽度
url: '', // 图片展示路径
signData: {
// 提交签名需要的内容
lawCaseId: '',
litigantId: '',
lawyerId: '',
image: ''
},
saveLoading: false // 保存按钮加载状态
}
},
created() {
// 阻止默认微信系统字体大小的影响
if (
typeof WeixinJSBridge == 'object' &&
typeof WeixinJSBridge.invoke == 'function'
) {
handleFontSize()
} else {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', handleFontSize, false)
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', handleFontSize)
document.attachEvent('onWeixinJSBridgeReady', handleFontSize)
}
}
function handleFontSize() {
// 设置网页字体为默认大小
WeixinJSBridge.invoke('setFontSizeCallback', {
fontSize: 0
})
// 重写设置网页字体大小的事件
WeixinJSBridge.on('menu:setfont', function() {
WeixinJSBridge.invoke('setFontSizeCallback', {
fontSize: 0
})
})
}
},
mounted() {
// 初始化获取链接参数
this.signData.lawCaseId = Util.GetUrlParam('lawCaseId')
this.signData.litigantId = Util.GetUrlParam('litigantId')
this.signData.lawyerId = Util.GetUrlParam('lawyerId')
console.log('this.signData', this.signData)
// 检查横竖屏
this.checkScreen()
// 初始化画板
this.writeName()
// 监听屏幕旋转
this.orientationchange()
// 监听窗体大小改变
this.onSizeChange()
},
methods: {
// 点击签名,初始化画板
writeName() {
this.url = ''
this.$nextTick(() => {
this.initCanvas()
})
},
/**
* 初始化画板,获取canvas节点对象,设置画板的宽高
* 不能在此方法中设置线条宽度样式,否则无效
*/
initCanvas() {
// 获取到当前canvas节点的信息,包含宽,高,top,left等
var mycanvas = this.$refs.mycanvas // 获取canvas元素
this.canvasWidth = mycanvas.clientWidth - 1 // 获取画板宽度
this.canvasHeight = mycanvas.clientHeight - 1 // 获取画板高度
// 设置canvas自适应的宽高到标签上(重要,canvas一定要遭标签上标识宽高,否则坐标获取不准确)
console.log('clientWidth', this.canvasWidth)
console.log('clientHeight', this.canvasHeight)
mycanvas.width = this.canvasWidth
mycanvas.height = this.canvasHeight
// canvas基础设置,线条设置
this.ctx = mycanvas.getContext('2d')
// 获取mycanvas的大小及其相对于视口的位置
this.stage_info = mycanvas.getBoundingClientRect()
console.log('stage_info', this.stage_info)
this.ctx.beginPath()
},
/**
* 绘制笔触
*/
handleDraw(targetX, targetY) {
console.log(targetX, targetY)
this.ctx.lineTo(targetX, targetY) // 将笔触移到当前点击点
this.ctx.stroke()
},
/**
* 触摸开始
* 获取当前点击点的坐标
* 设置线条颜色,宽度,样式等
*/
onTouchStart(e) {
let targetX = e.changedTouches[0].clientX - this.stage_info.left // 计算起始点X坐标
let targetY = e.changedTouches[0].clientY - this.stage_info.top // 计算起始点Y坐标
console.log(
'clientX',
e.changedTouches[0].clientX,
'stage.top',
this.stage_info.top
)
console.log(
'clientY',
e.changedTouches[0].clientY,
'stage.left',
this.stage_info.left
)
e.preventDefault()
this.ctx.beginPath()
this.ctx.strokeStyle = this.lineColor // 设置线条颜色
this.ctx.lineWidth = this.lineWidth // 设置线条的宽度
this.ctx.lineCap = 'round' // 设置线条的端点的样式,设为圆弧形
this.ctx.lineJoin = 'round' // 设置线条的连接点的样式,设为弧形
this.handleDraw(targetX, targetY)
},
/**
* 触摸过程中
* 获取并计算当前点击点的坐标,绘制线条
*/
onTouchMove(e) {
let targetX = e.changedTouches[0].clientX - this.stage_info.left // 计算起始点X坐标
let targetY = e.changedTouches[0].clientY - this.stage_info.top // 计算起始点Y坐标
e.preventDefault()
this.handleDraw(targetX, targetY)
},
/**
* 触摸结束
*/
onTouchEnd(e) {
e.preventDefault()
},
/**
* 颜色模块点击事件,切换点击的颜色状态
*/
clickColorItem(e) {
this.colors.forEach(item => {
item.active = false
})
e.active = true
this.lineColor = e.color // 设置当前笔触颜色
},
/**
* 重写按钮点击事件,清空画板内容
*/
clear() {
// 清空图片
this.url = ''
// 清空画板
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
// 重新设置canvas画板节点对象,否则绘画会出问题,这里异步操作,否则绘画有误
this.$nextTick(() => {
this.initCanvas()
})
},
// 监听屏幕旋转
// 用此事件获取改变后的屏幕尺寸需要注意:
// 1).iphone,可立即获取改变后的屏幕尺寸。
// 2).android,获取的尺寸是改变前的。需要设置setTimeout在一段时间后再获取。iScroll4是200ms,建议设成300ms.
orientationchange() {
window.addEventListener(
'orientationchange',
() => {
this.$nextTick(() => {
this.checkScreen() // 检查横竖屏
})
},
false
)
},
checkScreen() {
// 检查横竖屏
switch (window.orientation) {
case 90:
case -90:
console.log('横屏') // 这里是横屏
this.direction = 'horizontal'
break
default:
console.log('竖屏') // 这里是竖屏
this.direction = 'vertical'
break
}
this.$nextTick(() => {
this.clear() // 重置画板
})
},
// 监听窗体大小改变
onSizeChange() {
window.onresize = () => {
console.log('窗体大小改变') // 这里是横屏
this.clear() // 重置画板
}
},
// 保存签名
save() {
this.url = this.$refs.mycanvas.toDataURL()
this.submitText()
},
// 提交签名图片
submitText() {
if (this.url != '') {
// 追加base64签名图片,转换角度(横屏不需要旋转图片角度)
this.rotateBase64Img(
this.url,
this.direction == 'horizontal' ? 360 : 270,
base64data => {
this.signData.image = base64data
// this.$dialog.loading.open('正在提交签名...');
this.saveLoading = true
// getSignature(this.signData).then(res => {
// // this.$dialog.loading.close();//关闭加载提示
// this.saveLoading = false
// if (res.data.state == 100) {
// this.$dialog.toast({
// mes: '提交成功',
// icon: 'success',
// timeout: 1500
// })
// this.$router.push({
// name: 'handDrawSuccess'
// })
// } else {
// this.$dialog.toast({
// mes: '提交失败,' + res.data.message,
// timeout: 1500
// })
// }
// })
}
)
} else {
this.$dialog.toast({
mes: '请先签名才能提交!',
timeout: 1500
})
}
},
// 旋转base64图片
rotateBase64Img(src, edg, callback) {
// 旋转base64图片
var canvas = document.createElement('canvas')
var ctx = canvas.getContext('2d')
var imgW // 图片宽度
var imgH // 图片高度
var size // canvas初始大小
if (edg % 90 != 0) {
console.error('旋转角度必须是90的倍数!')
throw '旋转角度必须是90的倍数!'
}
edg < 0 && (edg = (edg % 360) + 360)
const quadrant = (edg / 90) % 4 // 旋转象限
const cutCoor = { sx: 0, sy: 0, ex: 0, ey: 0 } // 裁剪坐标
var image = new Image()
image.crossOrigin = 'anonymous'
image.src = src
image.onload = function() {
imgW = image.width
imgH = image.height
size = imgW > imgH ? imgW : imgH
canvas.width = size * 2
canvas.height = size * 2
switch (quadrant) {
case 0:
cutCoor.sx = size
cutCoor.sy = size
cutCoor.ex = size + imgW
cutCoor.ey = size + imgH
break
case 1:
cutCoor.sx = size - imgH
cutCoor.sy = size
cutCoor.ex = size
cutCoor.ey = size + imgW
break
case 2:
cutCoor.sx = size - imgW
cutCoor.sy = size - imgH
cutCoor.ex = size
cutCoor.ey = size
break
case 3:
cutCoor.sx = size
cutCoor.sy = size - imgW
cutCoor.ex = size + imgH
cutCoor.ey = size + imgW
break
}
ctx.translate(size, size)
ctx.rotate((edg * Math.PI) / 180)
ctx.drawImage(image, 0, 0)
var imgData = ctx.getImageData(
cutCoor.sx,
cutCoor.sy,
cutCoor.ex,
cutCoor.ey
)
if (quadrant % 2 == 0) {
canvas.width = imgW
canvas.height = imgH
} else {
canvas.width = imgH
canvas.height = imgW
}
ctx.putImageData(imgData, 0, 0)
callback(canvas.toDataURL())
}
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
body {
-webkit-text-size-adjust: 100% !important;
text-size-adjust: 100% !important;
-moz-text-size-adjust: 100% !important;
}
.cont {
display: inline-block;
vertical-align: middle;
}
.cont p {
transform: rotate(90deg);
-moz-transform: rotate(90deg);
-webkit-transform: rotate(90deg);
}
.buttonDiv {
width: 15vh;
}
.buttonDiv2 {
height: 15vh;
-moz-transform: rotate(180deg);
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
.commoBtn button {
transform: rotate(90deg);
-moz-transform: rotate(90deg);
-webkit-transform: rotate(90deg);
margin: 20px 0px;
}
.commoBtn2 button {
display: inline-block;
margin: 10px;
}
.canvasDiv {
width: 70vh;
height: 100%;
position: relative;
}
.canvasDiv2 {
height: 70vh;
width: 100%;
position: relative;
transform: rotate(180deg);
}
.signLabelDiv {
width: 12vh;
font-size: 0.3rem;
}
.signLabelDiv2 {
height: 12vh;
font-size: 0.3rem;
transform: rotate(90deg);
margin-left: -4.5%;
}
h1,
h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
#canvas {
background: #fff;
cursor: default;
border: 1px dashed rgb(204, 204, 204);
/* 判断方向旋转辅助线 */
/* border-bottom: 1px solid red; */
height: 100%;
width: 100%;
}
.mydraw {
height: 100%;
width: 100%;
}
.mydraw2 {
height: 100%;
width: 100%;
transform: rotate(180deg);
-moz-transform: rotate(180deg);
-webkit-transform: rotate(180deg);
}
</style>