日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

微信小程序canvas实现简易手写签名版(uni-app)

發(fā)布時(shí)間:2024/3/26 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 微信小程序canvas实现简易手写签名版(uni-app) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

微信小程序可以通過(guò)canvas實(shí)現(xiàn)手寫(xiě)簽名的效果,本文中使用的是微信小程序Canvas 2D接口
本示例中繪制的是橫屏簽名的效果,效果圖如下:

這里我們需要調(diào)整canvas的物理寬高,默認(rèn)物理寬高為300*150px,物理寬高調(diào)整通過(guò)css樣式即可,本文中需要根據(jù)屏幕高度進(jìn)行動(dòng)態(tài)調(diào)整,使用的是行內(nèi)樣式
頁(yè)面布局:

<template><view class="sign-page" :style="{paddingTop: top + 'px'}"><view class="canvas-box"><view class="left-pane"><view class="f28 text-gray6 left-text">請(qǐng)簽字確認(rèn)</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的物理寬高可通過(guò)樣式調(diào)整 --><canvasclass="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 || '檢測(cè)人員'}}</text></view></view></view><canvasclass="canvas2"disable-scroll type="2d" id="myCanvas2":style="{width: canvasHeight + 'px', height: canvasWidth + 'px'}"></canvas></view> </template>

js代碼:canvas的物理寬高調(diào)整后,canvas的邏輯寬高也需要進(jìn)行調(diào)整,默認(rèn)邏輯寬高是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)欄高度 + 膠囊按鈕行高度 + 膠囊按鈕上下的paddinglet navHeight = res.statusBarHeight + navPadding * 2 + menuData.height// 設(shè)置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的邏輯寬高,僅通過(guò)樣式修改canvas的寬高,會(huì)導(dǎo)致繪圖時(shí)比例不對(duì),// 如將物理寬度改為600,但邏輯寬度還是300,假設(shè)畫(huà)圖時(shí)的起點(diǎn)x是100,那么實(shí)際看到的繪圖起點(diǎn)是200const canvas = res[0].nodethis.canvas = canvasthis.ctx = canvas.getContext('2d')// canvas.width = this.canvasWidth// canvas.height = this.canvasHeight// 注意:按照上面方式調(diào)整,雖然邏輯寬高和物理寬高保持一致了,但是會(huì)發(fā)現(xiàn)畫(huà)出來(lái)的線(xiàn)會(huì)有鋸齒不夠清晰// 因?yàn)椴煌O(shè)備上物理像素與邏輯像素是不一致的// 因此canvas的邏輯寬高等于物理寬高分別*dprconst dpr = wx.getSystemInfoSync().pixelRatiocanvas.width = this.canvasWidth * dprcanvas.height = this.canvasHeight * dpr// 假設(shè)dpr等于2,,那么canvas的物理寬度是600,邏輯寬度就是1200,// 假設(shè)畫(huà)圖時(shí)的起點(diǎn)x是100,那么實(shí)際看到的繪圖起點(diǎn)是50,此時(shí)只需要將繪圖內(nèi)容進(jìn)行等比例放大即可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的方向是垂直的,導(dǎo)出的圖片也是豎屏,需要將圖片進(jìn)行旋轉(zhuǎn)rotateImage(filePath) {uni.createSelectorQuery().select('#myCanvas2').fields({ node: true, size: true }).exec((res) => {// 首先繪制一個(gè)寬高與上面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)// 繪制上述導(dǎo)出的簽名圖片到新的canvas上const img = this.canvas2.createImage()img.src = filePathimg.onload = () => {// 簽名圖片旋轉(zhuǎn)繪畫(huà)解析在下方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ù)器返回?cái)?shù)據(jù)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本身是豎向,導(dǎo)出的簽名圖片也為豎向,那么我們需要將導(dǎo)出的圖片旋轉(zhuǎn)為橫向后重新繪制到canvas上然后導(dǎo)出。簽名圖旋轉(zhuǎn)繪制的效果圖如下:

圖中黑色部分為canvas區(qū)域,豎向的簽名圖片為剛剛我們導(dǎo)出的圖片,繪制到canvas上的效果如下圖,如果我們要將其橫向繪制到面板上,此時(shí)需要將繪畫(huà)內(nèi)容沿左上角順時(shí)針旋轉(zhuǎn)270deg,此時(shí)可以發(fā)現(xiàn)旋轉(zhuǎn)后圖片的覆蓋區(qū)域在canvas向上移動(dòng)canvasWdth的位置,那么旋轉(zhuǎn)前將canvas的繪畫(huà)起點(diǎn)重置到(0,canvasWidth)即可保證繪畫(huà)內(nèi)容旋轉(zhuǎn)后剛好覆蓋在canvas上

需要注意的點(diǎn)是,后面繪畫(huà)旋轉(zhuǎn)后的canvas在實(shí)際頁(yè)面中我們是不需要看到的,需要通過(guò)樣式將其隱藏,如果需要使用canvasToTempFilePath方法導(dǎo)出圖片的話(huà),不能使用display:none的隱藏canvas,否則會(huì)報(bào)錯(cuò)no image found,
可以通過(guò)定位和visiblity(opacity)屬性隱藏。

頁(yè)面樣式:

<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會(huì)導(dǎo)致wx.canvasToTempFilePath報(bào)錯(cuò)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>

總結(jié)

以上是生活随笔為你收集整理的微信小程序canvas实现简易手写签名版(uni-app)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。