微信小程序canvas实现简易手写签名版(uni-app)
微信小程序可以通過canvas實現手寫簽名的效果,本文中使用的是微信小程序Canvas 2D接口
本示例中繪制的是橫屏簽名的效果,效果圖如下:
這里我們需要調整canvas的物理寬高,默認物理寬高為300*150px,物理寬高調整通過css樣式即可,本文中需要根據屏幕高度進行動態調整,使用的是行內樣式
頁面布局:
js代碼:canvas的物理寬高調整后,canvas的邏輯寬高也需要進行調整,默認邏輯寬高是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// 頂部高度 = 狀態欄高度 + 膠囊按鈕行高度 + 膠囊按鈕上下的paddinglet navHeight = res.statusBarHeight + navPadding * 2 + menuData.height// 設置canvas的物理寬高this.canvasWidth = res.windowWidth - 100this.canvasHeight = res.windowHeight - navHeight - 20this.top = navHeight}})},onReady() {this.initCanvas()},methods: {initCanvas() {uni.createSelectorQuery().select('#myCanvas').fields({ node: true, size: true }).exec((res) => {// 修改canvas的邏輯寬高// 如果不修改canvas的邏輯寬高,僅通過樣式修改canvas的寬高,會導致繪圖時比例不對,// 如將物理寬度改為600,但邏輯寬度還是300,假設畫圖時的起點x是100,那么實際看到的繪圖起點是200const canvas = res[0].nodethis.canvas = canvasthis.ctx = canvas.getContext('2d')// canvas.width = this.canvasWidth// canvas.height = this.canvasHeight// 注意:按照上面方式調整,雖然邏輯寬高和物理寬高保持一致了,但是會發現畫出來的線會有鋸齒不夠清晰// 因為不同設備上物理像素與邏輯像素是不一致的// 因此canvas的邏輯寬高等于物理寬高分別*dprconst dpr = wx.getSystemInfoSync().pixelRatiocanvas.width = this.canvasWidth * dprcanvas.height = this.canvasHeight * dpr// 假設dpr等于2,,那么canvas的物理寬度是600,邏輯寬度就是1200,// 假設畫圖時的起點x是100,那么實際看到的繪圖起點是50,此時只需要將繪圖內容進行等比例放大即可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 = 5this.startX = xthis.startY = ythis.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的方向是垂直的,導出的圖片也是豎屏,需要將圖片進行旋轉rotateImage(filePath) {uni.createSelectorQuery().select('#myCanvas2').fields({ node: true, size: true }).exec((res) => {// 首先繪制一個寬高與上面canvas相反的canvasconst canvas = res[0].nodethis.canvas2 = canvasthis.ctx2 = canvas.getContext('2d')const dpr = wx.getSystemInfoSync().pixelRatiocanvas.width = this.canvasHeight * dprcanvas.height = this.canvasWidth * dprthis.ctx2.scale(dpr, dpr)// 繪制上述導出的簽名圖片到新的canvas上const img = this.canvas2.createImage()img.src = filePathimg.onload = () => {// 簽名圖片旋轉繪畫解析在下方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) => {// 調用接口成功if(res.statusCode == 200) {// 解析服務器返回數據const data = JSON.parse(res.data)if(data.code == 200) {const responseUrl = config.requestUrl + data.filePathconst 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本身是豎向,導出的簽名圖片也為豎向,那么我們需要將導出的圖片旋轉為橫向后重新繪制到canvas上然后導出。簽名圖旋轉繪制的效果圖如下:
圖中黑色部分為canvas區域,豎向的簽名圖片為剛剛我們導出的圖片,繪制到canvas上的效果如下圖,如果我們要將其橫向繪制到面板上,此時需要將繪畫內容沿左上角順時針旋轉270deg,此時可以發現旋轉后圖片的覆蓋區域在canvas向上移動canvasWdth的位置,那么旋轉前將canvas的繪畫起點重置到(0,canvasWidth)即可保證繪畫內容旋轉后剛好覆蓋在canvas上
需要注意的點是,后面繪畫旋轉后的canvas在實際頁面中我們是不需要看到的,需要通過樣式將其隱藏,如果需要使用canvasToTempFilePath方法導出圖片的話,不能使用display:none的隱藏canvas,否則會報錯no image found,
可以通過定位和visiblity(opacity)屬性隱藏。
頁面樣式:
<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 {/*設置display:none會導致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>總結
以上是生活随笔為你收集整理的微信小程序canvas实现简易手写签名版(uni-app)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Contest RankList --
- 下一篇: Parallels Desktop 17