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

您所在的位置:网站首页 Js手写签名像素 微信小程序canvas实现简易手写签名版(uni

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

2024-06-10 17:37| 来源: 网络整理| 查看: 265

微信小程序可以通过canvas实现手写签名的效果,本文中使用的是微信小程序Canvas 2D接口 本示例中绘制的是横屏签名的效果,效果图如下: 在这里插入图片描述 这里我们需要调整canvas的物理宽高,默认物理宽高为300*150px,物理宽高调整通过css样式即可,本文中需要根据屏幕高度进行动态调整,使用的是行内样式 页面布局:

请签字确认 清空 完成 取消 {{title || '检测人员'}}

js代码:canvas的物理宽高调整后,canvas的逻辑宽高也需要进行调整,默认逻辑宽高是300*150px,(小程序Canvas 2D接口支持修改逻辑宽高),具体参考本文中的initCanvas方法

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 // 顶部高度 = 状态栏高度 + 胶囊按钮行高度 + 胶囊按钮上下的padding let navHeight = res.statusBarHeight + navPadding * 2 + menuData.height // 设置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的宽高,会导致绘图时比例不对, // 如将物理宽度改为600,但逻辑宽度还是300,假设画图时的起点x是100,那么实际看到的绘图起点是200 const canvas = res[0].node this.canvas = canvas this.ctx = canvas.getContext('2d') // canvas.width = this.canvasWidth // canvas.height = this.canvasHeight // 注意:按照上面方式调整,虽然逻辑宽高和物理宽高保持一致了,但是会发现画出来的线会有锯齿不够清晰 // 因为不同设备上物理像素与逻辑像素是不一致的 // 因此canvas的逻辑宽高等于物理宽高分别*dpr const dpr = wx.getSystemInfoSync().pixelRatio canvas.width = this.canvasWidth * dpr canvas.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 = 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的方向是垂直的,导出的图片也是竖屏,需要将图片进行旋转 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) // 绘制上述导出的签名图片到新的canvas上 const img = this.canvas2.createImage() img.src = filePath img.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.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() } } }

由于签名的方向是横向的,但是canvas本身是竖向,导出的签名图片也为竖向,那么我们需要将导出的图片旋转为横向后重新绘制到canvas上然后导出。签名图旋转绘制的效果图如下:

图中黑色部分为canvas区域,竖向的签名图片为刚刚我们导出的图片,绘制到canvas上的效果如下图,如果我们要将其横向绘制到面板上,此时需要将绘画内容沿左上角顺时针旋转270deg,此时可以发现旋转后图片的覆盖区域在canvas向上移动canvasWdth的位置,那么旋转前将canvas的绘画起点重置到(0,canvasWidth)即可保证绘画内容旋转后刚好覆盖在canvas上 在这里插入图片描述 需要注意的点是,后面绘画旋转后的canvas在实际页面中我们是不需要看到的,需要通过样式将其隐藏,如果需要使用canvasToTempFilePath方法导出图片的话,不能使用display:none的隐藏canvas,否则会报错no image found, 可以通过定位和visiblity(opacity)属性隐藏。

页面样式:

.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); } } } }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3