微信小程序可以通過canvas實現(xiàn)手寫簽名的效果,本文中使用的是微信小程序Canvas 2D接口
本示例中繪制的是橫屏簽名的效果,效果圖如下:
這里我們需要調(diào)整canvas的物理寬高,默認物理寬高為300*150px,物理寬高調(diào)整通過css樣式即可,本文中需要根據(jù)屏幕高度進行動態(tài)調(diào)整,使用的是行內(nèi)樣式
頁面布局:
<template>
<view class="sign-page" :style="{paddingTop: top + 'px'}">
<view class="canvas-box">
<view class="left-pane">
<view class="f28 text-gray6 left-text">請簽字確認</view>
<view class="right-box">
<view class="left-button" @click="clearContext">
<text class="ic ic-delete text-gray6"></text>
<text class="f30 text-gray6 ml5">清空</text>
</view>
<button class="right-button" @click="confirm">完成</button>
</view>
</view>
<!-- canvas的物理寬高可通過樣式調(diào)整 -->
<canvas
class="canvas"
disable-scroll
type="2d"
id="myCanvas"
@touchstart="handleTouchstart"
@touchmove="handleTouchmove"
:style="{
width: canvasWidth + 'px',
height: canvasHeight + 'px'}">
</canvas>
<view class="right-pane">
<view class="dis-flex back-button" @click="back">
<text class="ic ic-left text-gray6"></text>
<text class="text-gray6 ml15">取消</text>
</view>
<view class="title">
<text class="text text-gray6">{{title || '檢測人員'}}</text>
</view>
</view>
</view>
<canvas
class="canvas2"
disable-scroll
type="2d"
id="myCanvas2"
:style="{
width: canvasHeight + 'px',
height: canvasWidth + 'px'}">
</canvas>
</view>
</template>
js代碼:canvas的物理寬高調(diào)整后,canvas的邏輯寬高也需要進行調(diào)整,默認邏輯寬高是300*150px,(小程序Canvas 2D接口支持修改邏輯寬高),具體參考本文中的initCanvas方法
<script>
export default {
data() {
return {
canvasWidth: 300,
canvasHeight: 150,
top: 0,
canvas: null,
title: ''
}
},
onLoad() {
const menuData = uni.getMenuButtonBoundingClientRect()
uni.getSystemInfo({
success: (res) => {
let navPadding = menuData.top - res.statusBarHeight
// 頂部高度 = 狀態(tài)欄高度 + 膠囊按鈕行高度 + 膠囊按鈕上下的padding
let navHeight = res.statusBarHeight + navPadding * 2 + menuData.height
// 設(shè)置canvas的物理寬高
this.canvasWidth = res.windowWidth - 100
this.canvasHeight = res.windowHeight - navHeight - 20
this.top = navHeight
}
})
},
onReady() {
this.initCanvas()
},
methods: {
initCanvas() {
uni.createSelectorQuery()
.select('#myCanvas')
.fields({ node: true, size: true })
.exec((res) => {
// 修改canvas的邏輯寬高
// 如果不修改canvas的邏輯寬高,僅通過樣式修改canvas的寬高,會導(dǎo)致繪圖時比例不對,
// 如將物理寬度改為600,但邏輯寬度還是300,假設(shè)畫圖時的起點x是100,那么實際看到的繪圖起點是200
const canvas = res[0].node
this.canvas = canvas
this.ctx = canvas.getContext('2d')
// canvas.width = this.canvasWidth
// canvas.height = this.canvasHeight
// 注意:按照上面方式調(diào)整,雖然邏輯寬高和物理寬高保持一致了,但是會發(fā)現(xiàn)畫出來的線會有鋸齒不夠清晰
// 因為不同設(shè)備上物理像素與邏輯像素是不一致的
// 因此canvas的邏輯寬高等于物理寬高分別*dpr
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = this.canvasWidth * dpr
canvas.height = this.canvasHeight * dpr
// 假設(shè)dpr等于2,,那么canvas的物理寬度是600,邏輯寬度就是1200,
// 假設(shè)畫圖時的起點x是100,那么實際看到的繪圖起點是50,此時只需要將繪圖內(nèi)容進行等比例放大即可
this.ctx.scale(dpr, dpr)
})
},
handleTouchstart(e) {
this.lineBegin(e.touches[0].x, e.touches[0].y)
},
handleTouchmove(e) {
this.lineTo(e.touches[0].x, e.touches[0].y)
},
lineBegin(x, y) {
this.ctx.beginPath()
// 新版Canvas 2D接口,直接修改屬性即可
this.ctx.lineCap = 'round'
this.ctx.lineWidth = 5
this.startX = x
this.startY = y
this.ctx.moveTo(this.startX, this.startY)
},
lineTo(x, y) {
this.ctx.lineTo(x, y)
this.ctx.stroke()
this.ctx.moveTo(x, y)
},
clearContext() {
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
},
confirm() {
uni.canvasToTempFilePath({
canvas: this.canvas,
success: (res) => {
this.rotateImage(res.tempFilePath)
}
})
},
// 橫屏簽名,但是canvas的方向是垂直的,導(dǎo)出的圖片也是豎屏,需要將圖片進行旋轉(zhuǎn)
rotateImage(filePath) {
uni.createSelectorQuery()
.select('#myCanvas2')
.fields({ node: true, size: true })
.exec((res) => {
// 首先繪制一個寬高與上面canvas相反的canvas
const canvas = res[0].node
this.canvas2 = canvas
this.ctx2 = canvas.getContext('2d')
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = this.canvasHeight * dpr
canvas.height = this.canvasWidth * dpr
this.ctx2.scale(dpr, dpr)
// 繪制上述導(dǎo)出的簽名圖片到新的canvas上
const img = this.canvas2.createImage()
img.src = filePath
img.onload = () => {
// 簽名圖片旋轉(zhuǎn)繪畫解析在下方
this.ctx2.translate(0, this.canvasWidth);
this.ctx2.rotate(270 * Math.PI / 180)
this.ctx2.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight)
uni.canvasToTempFilePath({
canvas: this.canvas2,
success: (res) => {
this.handleUploadFile(res.tempFilePath)
}
})
}
})
},
handleUploadFile(filePath) {
uni.uploadFile({
url: config.requestUrl + '/biz/file/upload/annex',
filePath,
name: 'file',
header: {
'Authorization': getToken()
},
success: (res) => {
// 調(diào)用接口成功
if(res.statusCode == 200) {
// 解析服務(wù)器返回數(shù)據(jù)
const data = JSON.parse(res.data)
if(data.code == 200) {
const responseUrl = config.requestUrl + data.filePath
const eventChannel = this.getOpenerEventChannel()
eventChannel.emit('getSignImage', {filePath: responseUrl, fileId: data.fileId});
this.back()
}
} else {
uni.hideLoading()
}
},
fail: (res) => {
uni.hideLoading()
}
})
},
back() {
uni.navigateBack()
}
}
}
</script>
由于簽名的方向是橫向的,但是canvas本身是豎向,導(dǎo)出的簽名圖片也為豎向,那么我們需要將導(dǎo)出的圖片旋轉(zhuǎn)為橫向后重新繪制到canvas上然后導(dǎo)出。簽名圖旋轉(zhuǎn)繪制的效果圖如下:
圖中黑色部分為canvas區(qū)域,豎向的簽名圖片為剛剛我們導(dǎo)出的圖片,繪制到canvas上的效果如下圖,如果我們要將其橫向繪制到面板上,此時需要將繪畫內(nèi)容沿左上角順時針旋轉(zhuǎn)270deg,此時可以發(fā)現(xiàn)旋轉(zhuǎn)后圖片的覆蓋區(qū)域在canvas向上移動canvasWdth的位置,那么旋轉(zhuǎn)前將canvas的繪畫起點重置到(0,canvasWidth)即可保證繪畫內(nèi)容旋轉(zhuǎn)后剛好覆蓋在canvas上
需要注意的點是,后面繪畫旋轉(zhuǎn)后的canvas在實際頁面中我們是不需要看到的,需要通過樣式將其隱藏,如果需要使用canvasToTempFilePath方法導(dǎo)出圖片的話,不能使用display:none的隱藏canvas,否則會報錯no image found,
可以通過定位和visiblity(opacity)屬性隱藏。文章來源:http://www.zghlxwxcb.cn/news/detail-519113.html
頁面樣式:文章來源地址http://www.zghlxwxcb.cn/news/detail-519113.html
<style lang="scss" scoped>
.sign-page {
min-height: 100vh;
background-color: #f5f5f5;
.canvas-box {
position: relative;
width: 100%;
}
.left-pane {
width: 100rpx;
.left-text {
position: absolute;
top: 0;
line-height: 100rpx;
transform: translateX(100rpx) rotate(90deg) ;
transform-origin: 0 0;
}
.right-box {
position: absolute;
display: flex;
align-items: center;
bottom: 0;
transform: translateX(100rpx) rotate(90deg) translateX(-100%) translateX(100rpx);
transform-origin: 0 0;
.left-button {
line-height: 100rpx;
margin-right: 30rpx;
}
.right-button {
font-size: 30rpx;
color: #fff;
width: 140rpx;
height: 60rpx;
line-height: 60rpx;
background-color: green;
}
}
}
.canvas {
margin: 0 auto;
background-color: #fff;
border: 2rpx dashed #d9d9d9;
transform-origin: center center;
}
.canvas2 {
/*設(shè)置display:none會導(dǎo)致wx.canvasToTempFilePath報錯no image found*/
/*display: none;*/
position: absolute;
opacity: 0;
}
.right-pane {
position: absolute;
width: 100rpx;
height: 100%;
right: 0;
top: 0;
.back-button {
position: relative;
z-index: 5;
white-space: nowrap;
line-height: 100rpx;
align-items: center;
transform: translateX(100rpx) rotate(90deg);
transform-origin: 0 0;
}
.title {
position: absolute;
top: 0;
z-index: 4;
width: 100rpx;
height: 100%;
white-space: nowrap;
display: flex;
justify-content: center;
align-items: center;
line-height: 100rpx;
text-align: center;
.text {
display: inline-block;
transform: rotate(90deg);
}
}
}
}
</style>
到了這里,關(guān)于微信小程序canvas實現(xiàn)簡易手寫簽名版(uni-app)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!