qa-regulatory-gwj-app/uni_modules/lime-signature/components/l-signature/l-signature.vue

383 lines
9.8 KiB
Vue
Raw Normal View History

2023-11-07 10:08:37 +08:00
<template>
<view class="lime-signature" v-if="show" :style="[canvasStyle, styles]" ref="limeSignature">
<!-- #ifndef APP-VUE || APP-NVUE -->
<canvas
v-if="useCanvas2d"
class="lime-signature__canvas"
:id="canvasId"
type="2d"
:disableScroll="disableScroll"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
></canvas>
<canvas
v-else
:disableScroll="disableScroll"
class="lime-signature__canvas"
:canvas-id="canvasId"
:id="canvasId"
:width="canvasWidth"
:height="canvasHeight"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
@mousedown="touchStart"
@mousemove="touchMove"
@mouseup="touchEnd"
></canvas>
<canvas
class="offscreen"
canvas-id="offscreen"
id="offscreen"
:style="'width:' + offscreenSize[0] + 'px;height:' + offscreenSize[1] + 'px'"
:width="offscreenSize[0]"
:height="offscreenSize[1]">
</canvas>
<!-- #endif -->
<!-- #ifdef APP-VUE -->
<view
:id="canvasId"
:disableScroll="disableScroll"
:rparam="param"
:change:rparam="sign.update"
:rclear="rclear"
:change:rclear="sign.clear"
:rundo="rundo"
:change:rundo="sign.undo"
:rsave="rsave"
:change:rsave="sign.save"
:rempty="rempty"
:change:rempty="sign.isEmpty"
></view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<web-view
src="/uni_modules/lime-signature/static/index.html"
class="lime-signature__canvas"
ref="webview"
@pagefinish="onPageFinish"
@error="onError"
@onPostMessage="onMessage"
></web-view>
<!-- #endif -->
</view>
</template>
<!-- #ifdef APP-VUE -->
<script module="sign" lang="renderjs">
export {default} from './render'
</script>
<!-- #endif -->
<script>
// #ifndef APP-NVUE
import {canIUseCanvas2d, wrapEvent, requestAnimationFrame, sleep} from './utils'
import {Signature} from './signature'
// import {Signature} from '@signature';
import {uniContext, createImage, toDataURL} from './context'
// #endif
import props from './props';
import {base64ToPath, getRect} from './utils'
export default {
props,
data() {
return {
canvasWidth: null,
canvasHeight: null,
useCanvas2d: true,
show: true,
offscreenStyles: '',
// #ifdef APP-PLUS
rclear: 0,
rundo: 0,
rsave: 0,
rempty: 0,
risEmpty: true,
toDataURL: null,
tempFilePath: [],
// #endif
}
},
computed: {
canvasId() {
return `lime-signature${this._uid||this._.uid}`
},
offscreenId() {
return this.canvasId + 'offscreen'
},
offscreenSize() {
const {canvasWidth, canvasHeight} = this
return this.landscape ? [canvasHeight, canvasWidth] : [canvasWidth, canvasHeight]
},
canvasStyle() {
const {canvasWidth, canvasHeight, backgroundColor} = this
return {
width: canvasWidth && (canvasWidth + 'px'),
height: canvasHeight && (canvasHeight + 'px'),
background: backgroundColor
}
},
param() {
const {penColor, penSize, backgroundColor, landscape, openSmooth, minLineWidth, maxLineWidth, minSpeed, maxWidthDiffRate, maxHistoryLength, disableScroll} = this
return JSON.parse(JSON.stringify({penColor, penSize, backgroundColor, landscape, openSmooth, minLineWidth, maxLineWidth, minSpeed, maxWidthDiffRate, maxHistoryLength, disableScroll}))
}
},
// #ifdef APP-NVUE
watch: {
param(v) {
this.$refs.webview.evalJS(`update(${JSON.stringify(v)})`)
}
},
// #endif
// #ifndef APP-PLUS
created() {
this.useCanvas2d = this.type == '2d' && canIUseCanvas2d()
},
// #endif
// #ifndef APP-PLUS
async mounted() {
if(this.beforeDelay) {
await sleep(this.beforeDelay)
}
const config = await this.getContext()
this.signature = new Signature(config)
this.canvasEl = this.signature.canvas.get('el')
this.canvasWidth = this.signature.canvas.get('width')
this.canvasHeight = this.signature.canvas.get('height')
this.stopWatch = this.$watch('param' , (v) => {
this.signature.pen.setOption(v)
}, {immediate: true})
},
// #endif
// #ifndef APP-PLUS
// #ifdef VUE3
beforeUnmount() {
this.stopWatch && this.stopWatch()
this.signature.destroy()
this.signature = null
this.show = false;
},
// #endif
// #ifdef VUE2
beforeDestroy() {
this.stopWatch && this.stopWatch()
this.signature.destroy()
this.show = false;
this.signature = null
},
// #endif
// #endif
methods: {
// #ifdef MP-QQ
// toJSON() { return this },
// #endif
// #ifdef APP-PLUS
onPageFinish() {
this.$refs.webview.evalJS(`update(${JSON.stringify(this.param)})`)
},
onMessage(e = {}) {
const {detail: {data: [res]}} = e
if(res.event?.save) {
this.toDataURL = res.event.save
}
if(res.event?.changeSize) {
const {width, height} = res.event.changeSize
}
if(res.event.hasOwnProperty('isEmpty')) {
this.risEmpty = res.event.isEmpty
}
if (res.event?.file) {
this.tempFilePath.push(res.event.file)
if (this.tempFilePath.length > 7) {
this.tempFilePath.shift()
}
return
}
if (res.event?.success) {
if (res.event.success) {
this.tempFilePath.push(res.event.success)
if (this.tempFilePath.length > 8) {
this.tempFilePath.shift()
}
this.toDataURL = this.tempFilePath.join('')
this.tempFilePath = []
} else {
this.$emit('fail', 'canvas no data')
}
return
}
},
// #endif
undo() {
// #ifdef APP-VUE || APP-NVUE
this.rundo += 1
// #endif
// #ifdef APP-NVUE
this.$refs.webview.evalJS(`undo()`)
// #endif
// #ifndef APP-VUE
if(this.signature)
this.signature.undo()
// #endif
},
clear() {
// #ifdef APP-VUE || APP-NVUE
this.rclear += 1
// #endif
// #ifdef APP-NVUE
this.$refs.webview.evalJS(`clear()`)
// #endif
// #ifndef APP-VUE
if(this.signature)
this.signature.clear()
// #endif
},
isEmpty() {
// #ifdef APP-NVUE
this.$refs.webview.evalJS(`isEmpty()`)
// #endif
// #ifdef APP-VUE || APP-NVUE
this.rempty += 1
// #endif
// #ifndef APP-VUE || APP-NVUE
return this.signature.isEmpty()
// #endif
},
canvasToTempFilePath(param) {
const isEmpty = this.isEmpty()
// #ifdef APP-NVUE
this.$refs.webview.evalJS(`save()`)
// #endif
// #ifdef APP-VUE || APP-NVUE
const stopURLWatch = this.$watch('toDataURL', (v, n) => {
if(v && v !== n) {
// if(param.pathType == 'url') {
base64ToPath(v).then(res => {
param.success({tempFilePath: res,isEmpty: this.risEmpty })
})
// } else {
// param.success({tempFilePath: v,isEmpty: this.risEmpty })
// }
this.toDataURL = ''
}
stopURLWatch && stopURLWatch()
})
this.rsave += 1
// #endif
// #ifndef APP-VUE || APP-NVUE
const success = (success) => param.success && param.success(success)
const fail = (fail) => param.fail && param.fail(err)
const {canvas} = this.signature.canvas.get('el')
const {backgroundColor, landscape} = this
const width = this.signature.canvas.get('width')
const height = this.signature.canvas.get('height')
const canvasToTempFilePath = (image) => {
const context = uni.createCanvasContext('offscreen', this)
context.save()
context.setTransform(1,0,0,1,0,0)
if(landscape) {
context.translate(0, width)
context.rotate(-Math.PI / 2)
}
if(backgroundColor) {
context.fillStyle = backgroundColor
context.fillRect(0,0, width, height)
}
context.drawImage(image, 0, 0, width, height);
context.draw(false, () => {
toDataURL('offscreen', this, param).then((res) => {
const size = Math.max(width, height)
context.restore()
context.clearRect(0,0, size, size)
success({tempFilePath: res, isEmpty})
})
})
}
if(this.useCanvas2d) {
try{
// #ifndef MP-ALIPAY
base64ToPath(canvas.toDataURL()).then(canvasToTempFilePath)
// #endif
// #ifdef MP-ALIPAY
canvas.toTempFilePath({
canvasid: this.canvasid,
success(res){
canvasToTempFilePath(res.tempFilePath)
},
fail
})
// #endif
} catch(err){fail(err)}
} else {
toDataURL(this.canvasId, this).then(canvasToTempFilePath).catch(fail)
}
// #endif
},
// #ifndef APP-PLUS
getContext() {
return getRect(`#${this.canvasId}`, {context: this, type: this.useCanvas2d ? 'fields': 'boundingClientRect'}).then(res => {
if(res) {
let {width, height, node: canvas, left, top, right} = res
let {pixelRatio} = uni.getSystemInfoSync()
let context;
if(canvas) {
context = canvas.getContext('2d')
canvas.width = width * pixelRatio;
canvas.height = height * pixelRatio;
} else {
pixelRatio = 1
context = uniContext(uni.createCanvasContext(this.canvasId, this))
canvas = {
createImage,
toDataURL: () => toDataURL(this.canvasId, this),
requestAnimationFrame
}
}
// 支付宝小程序 使用stroke有个默认背景色
context.clearRect(0,0,width,height)
return { left, top, right, width, height, context, canvas, pixelRatio};
}
})
},
touchStart(e) {
if(!this.canvasEl) return
this.isStart = true
this.canvasEl.dispatchEvent('touchstart', wrapEvent(e))
},
touchMove(e) {
if(!this.canvasEl || !this.isStart && this.canvasEl) return
this.canvasEl.dispatchEvent('touchmove', wrapEvent(e))
},
touchEnd(e) {
if(!this.canvasEl) return
this.isStart = false
this.canvasEl.dispatchEvent('touchend', wrapEvent(e))
},
// #endif
}
}
</script>
<style lang="stylus">
.lime-signature,.lime-signature__canvas
// #ifndef APP-NVUE
width: 100%;
height: 100%
// #endif
// #ifdef APP-NVUE
flex: 1;
// #endif
.offscreen {
position: fixed;
top: 0
left: 1500rpx;
}
</style>