296 lines
7.5 KiB
Plaintext
296 lines
7.5 KiB
Plaintext
<template>
|
||
<view class="l-signature" ref="signatureRef" :style="drawableStyle">
|
||
<!-- #ifdef APP -->
|
||
<view class="l-signature-landscape" ref="signatureLandscapeRef" v-if="landscape && url !=''" :style="landscapeStyle">
|
||
<image class="l-signature-image" ref="signatureImageRef" :src="url" ></image>
|
||
</view>
|
||
<!-- #endif -->
|
||
</view>
|
||
</template>
|
||
<script lang="uts" setup>
|
||
// @ts-nocheck
|
||
// #ifdef APP
|
||
import { Signature } from './signature.uts'
|
||
// #endif
|
||
// #ifndef APP
|
||
import { Signature } from './signature.js'
|
||
// #endif
|
||
import {nextTick} from 'vue'
|
||
import {LSignatureToTempFilePathOptions, LSignatureToFileSuccess, LSignatureOptions} from '../../index.uts'
|
||
// type SignatureToFileSuccessCallback = (res : UTSJSONObject) => void
|
||
// type SignatureToFileFailCallback = (res : TakeSnapshotFail) => void
|
||
// type SignatureToFileCompleteCallback = (res : any) => void
|
||
|
||
/**
|
||
* LimeSignature 手写板签名
|
||
* @description 手写板签名插件,uvue专用版。
|
||
* @tutorial https://ext.dcloud.net.cn/plugin?id=4354
|
||
* @property {Number} penSize 画笔大小
|
||
* @property {String} penColor 画笔颜色
|
||
* @property {String} backgroundColor 背景颜色,不填则为透明
|
||
* @property {Boolean} disableScroll 当在写字时,禁止屏幕滚动以及下拉刷新,nvue无效
|
||
*/
|
||
|
||
const props = defineProps({
|
||
styles: {
|
||
type: String,
|
||
default: ''
|
||
},
|
||
penColor: {
|
||
type: String,
|
||
default: 'black'
|
||
},
|
||
penSize: {
|
||
type: Number,
|
||
default: 2
|
||
},
|
||
backgroundColor: {
|
||
type: String,
|
||
default: ''
|
||
},
|
||
openSmooth: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
minLineWidth: {
|
||
type: Number,
|
||
default: 2
|
||
},
|
||
maxLineWidth: {
|
||
type: Number,
|
||
default: 6
|
||
},
|
||
minSpeed: {
|
||
type: Number,
|
||
default: 1.5
|
||
},
|
||
maxWidthDiffRate: {
|
||
type: Number,
|
||
default: 20
|
||
},
|
||
maxHistoryLength: {
|
||
type: Number,
|
||
default: 20
|
||
},
|
||
disableScroll: {
|
||
type: Boolean,
|
||
default: true
|
||
},
|
||
disabled: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
landscape:{
|
||
type: Boolean,
|
||
default: true
|
||
},
|
||
})
|
||
|
||
const drawableStyle = computed<string>(():string=>{
|
||
let style : string = ''
|
||
|
||
if (props.backgroundColor != '') {
|
||
style += `background-color: ${props.backgroundColor};`
|
||
}
|
||
if (props.styles != '') {
|
||
style += props.styles
|
||
}
|
||
return style
|
||
})
|
||
const signatureRef = ref<UniElement|null>(null)
|
||
let signatureLandscapeRef = ref<UniElement|null>(null)
|
||
let landscapeStyle = ref<Map<string, string>>(new Map())
|
||
let signatureImageRef = ref<UniElement|null>(null)
|
||
|
||
let signature:Signature|null = null
|
||
let url = ''
|
||
// #ifdef WEB
|
||
let canvas:HTMLCanvasElement|null = null
|
||
// #endif
|
||
|
||
const clear = ()=>{
|
||
signature?.clear()
|
||
}
|
||
const redo = ()=>{
|
||
signature?.redo()
|
||
}
|
||
const undo = ()=>{
|
||
signature?.undo()
|
||
}
|
||
const canvasToTempFilePath = (options : LSignatureToTempFilePathOptions)=>{
|
||
const success = options.success // as SignatureToFileSuccessCallback | null
|
||
const fail = options.fail // as SignatureToFileFailCallback | null
|
||
const complete = options.complete// as SignatureToFileCompleteCallback | null
|
||
const format = options.format ?? 'png'
|
||
// #ifdef APP
|
||
signatureRef.value?.takeSnapshot({
|
||
format,
|
||
success: (res) => {
|
||
if(props.landscape){
|
||
url = res.tempFilePath
|
||
setTimeout(()=>{
|
||
signatureLandscapeRef.value?.takeSnapshot({
|
||
format,
|
||
success: (res2) => {
|
||
success?.({
|
||
tempFilePath: res2.tempFilePath,
|
||
isEmpty: signature?.isEmpty ?? false
|
||
} as LSignatureToFileSuccess)
|
||
}
|
||
})
|
||
},300)
|
||
|
||
} else {
|
||
success?.({
|
||
tempFilePath: res.tempFilePath,
|
||
isEmpty: signature?.isEmpty ?? false
|
||
} as LSignatureToFileSuccess)
|
||
}
|
||
},
|
||
fail: (res) => {
|
||
fail?.(res)
|
||
},
|
||
complete: (res) => {
|
||
complete?.(res)
|
||
}
|
||
} as TakeSnapshotOptions)
|
||
// #endif
|
||
|
||
// #ifdef WEB
|
||
// @ts-ignore
|
||
const {backgroundColor, backgroundImage, landscape, boundingBox} = props
|
||
const {quality = 1} = options
|
||
const flag = landscape || backgroundColor || boundingBox
|
||
const type = `image/${format}`.replace(/jpg/, 'jpeg');
|
||
const image = canvas?.toDataURL(!flag && type, !flag && quality)
|
||
|
||
if(flag){
|
||
// @ts-ignore
|
||
const canvas = document.createElement('canvas')
|
||
// @ts-ignore
|
||
const pixelRatio = signature?.canvas.get('pixelRatio')
|
||
// @ts-ignore
|
||
let width = signature?.canvas.get('width')
|
||
// @ts-ignore
|
||
let height = signature?.canvas.get('height')
|
||
let x = 0
|
||
let y = 0
|
||
// @ts-ignore
|
||
const next = () => {
|
||
const size = [width, height]
|
||
if(landscape) {size.reverse()}
|
||
canvas.width = size[0] * pixelRatio
|
||
canvas.height = size[1] * pixelRatio
|
||
const param = [x, y, width, height, 0 , 0, width, height].map(item => item * pixelRatio)
|
||
const context = canvas.getContext('2d')
|
||
if (landscape) {
|
||
context.translate(0, width * pixelRatio)
|
||
context.rotate(-Math.PI / 2)
|
||
}
|
||
if (backgroundColor) {
|
||
context.fillStyle = backgroundColor
|
||
context.fillRect(0, 0, width * pixelRatio, height * pixelRatio)
|
||
}
|
||
const drawImage = () => {
|
||
// @ts-ignore
|
||
context.drawImage(signature?.canvas!.get('el'), ...param)
|
||
success?.({
|
||
tempFilePath: canvas.toDataURL(type, quality),
|
||
// @ts-ignore
|
||
isEmpty: signature?.isEmpty() ?? false
|
||
} as LSignatureToFileSuccess)
|
||
canvas.remove()
|
||
}
|
||
if(backgroundImage) {
|
||
const img = new Image();
|
||
img.onload = () => {
|
||
context.drawImage(img, ...param)
|
||
drawImage()
|
||
}
|
||
img.src = backgroundImage
|
||
}
|
||
if(!backgroundImage) {
|
||
drawImage()
|
||
}
|
||
}
|
||
if(boundingBox) {
|
||
// @ts-ignore
|
||
const res = signature?.getContentBoundingBox()
|
||
width = res.width
|
||
height = res.height
|
||
x = res.startX
|
||
y = res.startY
|
||
next()
|
||
} else {
|
||
next()
|
||
}
|
||
}
|
||
// #endif
|
||
}
|
||
defineExpose({
|
||
clear,
|
||
redo,
|
||
undo,
|
||
canvasToTempFilePath,
|
||
})
|
||
onMounted(()=>{
|
||
nextTick(()=>{
|
||
const width = signatureRef.value?.offsetWidth
|
||
const height = signatureRef.value?.offsetHeight
|
||
// #ifdef APP
|
||
// signatureLandscapeRef.value.style.setProperty('width', `${height}px`)
|
||
// signatureLandscapeRef.value?.style!.setProperty('height', `${width}px`)
|
||
landscapeStyle.value.set('width', `${height}px`)
|
||
landscapeStyle.value.set('height', `${width}px`)
|
||
signatureImageRef.value?.style?.setProperty('width', `${width}px`)
|
||
signatureImageRef.value?.style?.setProperty('height', `${height}px`)
|
||
signatureImageRef.value?.style?.setProperty('transform', `rotate(-90deg) translateY(${width}px)`)
|
||
|
||
signature = new Signature(signatureRef.value!)
|
||
// #endif
|
||
// #ifdef WEB
|
||
canvas = document.createElement('canvas')
|
||
canvas.style = 'width: 100%; height: 100%;'
|
||
signatureRef.value?.appendChild(canvas)
|
||
// @ts-ignore
|
||
signature = new Signature({el: canvas})
|
||
// #endif
|
||
|
||
watchEffect(()=>{
|
||
const options : LSignatureOptions = {
|
||
penColor: props.penColor,
|
||
openSmooth: props.openSmooth,
|
||
disableScroll: props.disableScroll,
|
||
disabled: props.disabled,
|
||
penSize: props.penSize,
|
||
minLineWidth: props.minLineWidth,
|
||
maxLineWidth: props.maxLineWidth,
|
||
minSpeed: props.minSpeed,
|
||
maxWidthDiffRate: props.maxWidthDiffRate,
|
||
maxHistoryLength: props.maxHistoryLength
|
||
}
|
||
// #ifdef APP
|
||
signature?.setOption(options)
|
||
// #endif
|
||
// #ifdef WEB
|
||
// @ts-ignore
|
||
signature?.pen.setOption(options)
|
||
// #endif
|
||
})
|
||
})
|
||
})
|
||
</script>
|
||
<style lang="scss">
|
||
.l-signature {
|
||
flex: 1;
|
||
&-landscape{
|
||
position: absolute;
|
||
pointer-events: none;
|
||
left: 1000rpx;
|
||
}
|
||
&-image{
|
||
transform-origin: 0% 0%;
|
||
}
|
||
}
|
||
</style>
|