-
Create components
<template> <view class="box" v-show="modelValue" :style="{height:'100%'}"> <view class="whole canvas-autograph flexc"> <canvas class="scroll-view" canvas-id="mycanvas" @touchstart="touchstart" @touchmove="touchmove" disable-scroll="true" @touchend="touchend" /> <view class="fun-box"> <van-button round block type="warning" size="small" @click="clear"> empty </van-button> <van-button round block type="primary" size="small" @click="confirm"> confirm </van-button> <van-button round block type="danger" size="small" @click="cancel"> Cancel </van-button> </view> </view> </view> </template> <script setup> // base64 to Blob format method // base64 to file stream method import { parseBlob, base64toFile, blobToDataURI } from '@/utils/base64ToFile.js' // Use Qiniu cloud package image upload method import { qiniuUploadSubscribe } from '@/utils/upload.js' import { ref, reactive, watch, getCurrentInstance, onMounted } from 'vue' const { proxy: t } = getCurrentInstance() const emits = defineEmits(['update:modelValue', 'complete']) const props = defineProps({ modelValue: { type: Boolean, default: false }, infor: { type: Object, default: {} }, }) watch(() => props. modelValue, e => {}, { immediate: true, }) let cavWidth = ref(2000) let cavWidth1 = ref(2000) let points = reactive([]) let pointList = ref([]) const isDraw = ref(false) let canvasCtx = reactive(uni. createCanvasContext('mycanvas')) canvasCtx.lineWidth = 4; canvasCtx.lineCap = 'round' canvasCtx.lineJoin = 'round' const touchstart = e => { let startX = e.changedTouches[0].x let startY = e.changedTouches[0].y let startPoint = { X: startX, Y: startY } points. push(startPoint); canvasCtx.beginPath(); } const touchmove = e => { let moveX = e.changedTouches[0].x let moveY = e.changedTouches[0].y let movePoint = { X: moveX, Y: moveY } points. push(movePoint) pointList. value. push(movePoint) let len = points. length if (len >= 2) { draw() } } const draw = () => { let point1 = points[0] let point2 = points[1] points. shift() canvasCtx.moveTo(point1.X, point1.Y) canvasCtx.lineTo(point2.X, point2.Y) canvasCtx.stroke() canvasCtx. draw(true) } const touchend = e => { points = []; } const clear = () => { pointList. value = [] return uni. getSystemInfo() .then(res => { canvasCtx. clearRect(0, 0, res. windowWidth, res. windowHeight); canvasCtx. draw(true); return res }) .catch(err => { console. log(err); }) } const confirm = () => { if (pointList. value. length < 10) { uni.showToast({ icon: 'none', title: 'Please sign' }) } else { uni.canvasToTempFilePath({ canvasId: 'mycanvas', }) .then(res => { const { tempFilePath } = res getImageInfo(tempFilePath) }) } } const cancel = () => { pointList. value = [] clear().then((res) => { emits('update:modelValue', false); }) } const getImageInfo = (src) => { const { infor: { idCard } } = props let lista = {} uni. showLoading({ title: "Uploading" }) uni.getImageInfo({ src, success(res) { let img = new Image() img.src = res.path let canvas = document. createElement('canvas'); let ctx = canvas. getContext('2d') let rate = res.height / res.width let width = 300 / rate let height = 300 cavWidth.value = 300 / rate cavWidth1. value = 300 ctx. translate(height / 2, width / 2) ctx.rotate((270 * Math.PI) / 180) ctx. drawImage(img, -width / 2, -height / 2, width, height) canvas.toBlob((fileSrc) => { blobToDataURI(fileSrc, (dataurl) => { const imgInfor = idCard + '/' + new Date().getTime() const blobPath = parseBlob(dataurl) const File = base64toFile(dataurl, imgInfor) File.path = blobPath <!-- qiniuUploadSubscribe (upload method of secondary packaging), if the project is uploaded The picture does not need to be packaged twice and can be uploaded directly with uni.uploadFile --> qiniuUploadSubscribe({ files: [File], type: 5, success: (res, index) => { if (res.code == 20000) { lista.url = res.data // setFilePath (the globally defined method of setting the image access path) lista.imageURL = t.setFilePath(res.data) lista.percent = 100 lista.uploadStatus = 'SUCCESS' lista.size = File.size lista.type = File.type lista.name = File.name lista.path = File.path //Return the image path returned by the backend interface to the parent component emits('complete', [lista]) } uni.showToast({ icon: 'none', title: res.message }) pointList. value = [] uni.hideLoading(); cancel() }, error: (err, index) => { lista.uploadStatus = 'ERROR' }, progress: (res, index) => { const { progress, totalBytesSent, totalBytesExpectedToSend } = res lista.percent = Math.floor(progress) lista.uploadStatus = progress < 100 ? 'UPLOADING' : 'SUCCESS' }, complete: (err, index) => { console. log(err, index) }, }) }); }) } }) } </script> <style scoped lang="scss"> .box { position: absolute; animation: boxBotToTop .9s; -webkit-animation: boxBotToTop .9s; width: 92%; bottom: 0; left: 4%; z-index: 997; background: #374151; border-radius: 30rpx; } @keyframes boxBotToTop { 0% { opacity: 0; -webkit-transform: translateY(40px); transform: translateY(40px); } 100% { opacity: 1; -webkit-transform: translateY(0); transform: translateY(0) scale(.9); } } @-webkit-keyframes boxBotToTop { 0% { opacity: 0; -webkit-transform: translateY(40px); transform: translateY(40px); } 100% { opacity: 1; -webkit-transform: translateY(0); transform: translateY(0) scale(.9); } } .canvas-autograph { position: absolute; z-index: 998; height: 95%; width: 82%; top: 50%; left: 50%; transform: translate(-43%, -50%); .scroll-view { width: 100%; height: 100%; background-color: #FFFFFF; } .fun-box { position: absolute; display: flex; align-items: center; width: 100%; justify-content: space-between; transform: rotate(90deg); top: 50%; left: -59%; .fun-box-btn { width: 160rpx; height: 100%; color: #FFFFFF; border-radius: 20rpx; border: 1rpx solid #C0C0C0; text-align: center; + .fun-box-btn { margin-left: 20rpx; } } } } </style>
-
component call
<template> <view class="homePage"> <view style="position: absolute;height: 100vh;bottom:0;width:100%" v-if="isCanvas"> <MiliuAutograph v-model="isCanvas" @complete="complete" :infor="{idCard:floatingForm.idCard}" /> </view> </view> </template> <script setup> import MiliuAutograph from '@/components/MiliuAutograph/index.vue' import { ref, defineComponent, getCurrentInstance, reactive } from 'vue' const { proxy: t } = getCurrentInstance() const isCanvas = ref(false) const complete = e => { console.log(e,'After the electronic signature image is successfully uploaded, the image path returned by the backend'); } </script>