You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

295 lines
7.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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>