123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- <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" :style="landscapeImageStyle" :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: false
- },
- })
- 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 landscapeImageStyle = ref<Map<string, string>>(new Map())
- let signature : Signature | null = null
- // let url = ref('')
- // #ifdef WEB
- let canvas : HTMLCanvasElement | null = null
- let touchstart,touchmove,touchend
- // #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.value = 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()
- }
- } else {
- success?.({
- tempFilePath: image,
- // @ts-ignore
- isEmpty: signature?.isEmpty() ?? false
- } as LSignatureToFileSuccess)
- }
- // #endif
- }
- defineExpose({
- clear,
- redo,
- undo,
- canvasToTempFilePath,
- })
- onMounted(() => {
- nextTick(() => {
- const width = signatureRef.value?.offsetWidth
- const height = signatureRef.value?.offsetHeight
- // #ifdef APP
- landscapeStyle.value.set('width', `${height}px`)
- landscapeStyle.value.set('height', `${width}px`)
- landscapeImageStyle.value.set('width', `${width}px`)
- landscapeImageStyle.value.set('height', `${height}px`)
- landscapeImageStyle.value.set('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 })
- let isTouch = false
- touchstart = (event: UniMouseEvent) => {
- isTouch = true
- const rect = canvas?.getBoundingClientRect()
- // @ts-ignore
- signature!.canvas.emit('touchstart', {
- points: [
- {
- x: event.clientX - rect.left,
- y: event.clientY - rect.top
- }
- ]
- })
- }
- touchmove = (event: UniMouseEvent) => {
- if(!isTouch) return
- const rect = canvas?.getBoundingClientRect()
- // @ts-ignore
- signature!.canvas.emit('touchmove', {
- points: [
- {
- x: event.clientX - rect.left,
- y: event.clientY - rect.top
- }
- ]
- })
- }
- touchend = (event: UniMouseEvent) => {
- isTouch = false
- const rect = canvas?.getBoundingClientRect();
- // @ts-ignore
- signature!.canvas.emit('touchend', {
- points: [
- {
- x: event.clientX - rect.left,
- y: event.clientY - rect.top
- }
- ]
- })
- }
- canvas?.addEventListener('mousedown', touchstart)
- canvas?.addEventListener('mousemove', touchmove)
- canvas?.addEventListener('mouseup', touchend)
- canvas?.addEventListener('mouseleave', touchend)
-
-
- // #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
- })
- })
- })
-
- onUnmounted(()=>{
- // #ifdef WEB
- canvas?.removeEventListener('mousedown', touchstart)
- canvas?.removeEventListener('mousemove', touchmove)
- canvas?.removeEventListener('mouseup', touchend)
- canvas?.removeEventListener('mouseleave', touchend)
- canvas?.remove()
- // #endif
-
- })
- </script>
- <style lang="scss">
- .l-signature {
- flex: 1;
- &-landscape {
- position: absolute;
- pointer-events: none;
- left: 1000rpx;
- }
- &-image {
- transform-origin: 0% 0%;
- }
- }
- </style>
|