代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
<template> <view class="confirm-page"> <view class="sign-box"> <view class="canvas"> <canvas canvas-id="canvas" @touchstart="onTouchstart" @touchmove="onTouchmove" @touchend="onTouchend" ></canvas> </view> <view class="sign-actions"> <view class="sign-finish" @click="onFinish">完成</view> <view class="sign-clear" @click="onClear">清除</view> </view> </view> </view> </template> <script setup lang="ts"> import useUploadImage from '@/composition/uploadImage' type DataType = { ctx: UniApp.CanvasContext points: { x: number; y: number }[] flag: boolean canvasImg: string } const data = reactive<DataType>({ ctx: uni.createCanvasContext('canvas'), points: [], flag: false, canvasImg: '' }) // 手写签名 const signImageList = ref<{ uri: string; url: string }[]>([]) const signImage = useUploadImage(signImageList) onLoad(() => { data.ctx.lineWidth = 4 data.ctx.lineCap = 'round' data.ctx.lineJoin = 'round' }) // 触摸开始,获取到起点 const onTouchstart = e => { const startX = e.changedTouches[0].x const startY = e.changedTouches[0].y const startPoint = { x: startX, y: startY } data.points.push(startPoint) // 每次触摸开始,开启新的路径 data.ctx.beginPath() } // 触摸移动,获取到路径点 const onTouchmove = e => { const { x, y } = e.changedTouches[0] const movePoint = { x, y } data.points.push(movePoint) if (data.points.length >= 2) { draw() // 绘制路径 } } // 触摸结束,将未绘制的点清空防止对后续路径产生干扰 const onTouchend = () => { data.points = [] } /** * 绘制笔迹 * 1. 为保证笔迹实时显示,必须在移动的同时绘制笔迹 * 2. 为保证笔迹连续,每次从路径集合中取两个点作为起点(moveTo)和终点(lineTo) * 3. 将上一次的终点作为下一次绘制的起点(即清除第一个点) */ const draw = () => { data.flag = true const point1 = data.points[0] const point2 = data.points[1] data.points.shift() data.ctx.moveTo(point1.x, point1.y) data.ctx.lineTo(point2.x, point2.y) data.ctx.stroke() data.ctx.draw(true) } // 完成绘画 const onFinish = () => { if (!data.flag) { uni.showToast({ title: '请先签字', icon: 'none' }) return } uni.canvasToTempFilePath({ x: 0, y: 0, canvasId: 'canvas', success: function (res) { uni.getFileSystemManager().readFile({ filePath: res.tempFilePath, encoding: 'base64', success: res => { const base64 = 'data:image/png;base64,' + res.data data.canvasImg = base64 console.log(base64) // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error const buffer = uni.base64ToArrayBuffer(res.data) // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error const filePath = wx.env.USER_DATA_PATH + '/sign.png' const fs = uni.getFileSystemManager() fs.writeFile({ filePath, data: buffer, encoding: 'utf8', success(res) { console.log(res) signImage.uploadFilePromise(filePath).then(res => { signImageList.value = [ { url: res.uri, uri: res.url } ] }) }, fail(res) { console.error(res) } }) } }) } }) } // 清空画布 const onClear = () => { data.flag = false uni.getSystemInfo({ success: function (res) { const width = res.windowWidth const height = res.windowHeight data.ctx.clearRect(0, 0, width, height) data.ctx.draw(true) } }) } </script> <style lang="scss" scoped> .sign-box { @apply bg-white; } .sign-actions { @apply flex justify-center items-center; view { @apply w-1/2 text-center py-2 text-white; &.sign-finish { @apply bg-blue-500; } &.sign-clear { @apply bg-red-500; } } } </style> |