chat-app/src/uni_modules/tmui/components/tm-sign-board/tm-sign-board.vue
scout b54bfe63ad
Some checks are pending
Check / lint (push) Waiting to run
Check / typecheck (push) Waiting to run
Check / build (build, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build, 18.x, windows-latest) (push) Waiting to run
Check / build (build:app, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build:app, 18.x, windows-latest) (push) Waiting to run
Check / build (build:mp-weixin, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build:mp-weixin, 18.x, windows-latest) (push) Waiting to run
init
2024-11-11 14:46:14 +08:00

418 lines
9.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view @mouseleave="touchsend" @touchcancel="touchsend" ref="tmspin" :style="{ width: `${props.width}rpx`, height: `${props.height}rpx` }">
<!-- #ifdef APP-NVUE -->
<gcanvas
v-if="show"
@touchstart="touchstart"
@touchmove="touchsmove"
@touchend="touchsend"
:id="canvasId"
:ref="canvasId"
class="canvas"
:style="{ width: `${props.width}rpx`, height: `${props.height}rpx` }"
>
</gcanvas>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN || MP-ALIPAY || MP-QQ -->
<canvas
@touchstart="touchstart"
@touchmove="touchsmove"
@touchend="touchsend"
@mousedown="touchstart"
@mousemove.stop="touchsmove"
@mouseup.stop="touchsend"
type="2d"
id="canvasId"
canvas-id="canvasId"
class="canvas"
:style="{ width: `${props.width}rpx`, height: `${props.height}rpx` }"
></canvas>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ || APP-NVUE -->
<canvas
@touchstart.stop="touchstart"
@touchmove.stop="touchsmove"
@touchend.stop="touchsend"
@mousedown.stop="touchstart"
@mousemove.stop="touchsmove"
@mouseup.stop="touchsend"
@mouseleave.stop="touchsend"
@touchcancel.stop="touchsend"
:id="canvasId"
:canvas-id="canvasId"
class="canvas"
:style="{
width: `${props.width}rpx`,
height: `${props.height}rpx`,
'touch-action': 'none'
}"
></canvas>
<!-- #endif -->
</view>
</template>
<script lang="ts" setup>
/**
* 签名板
* @description 方便签名业务。在当前截止最新的3.5.0版本uni在h5端有自身的bug无法使用。等官方修复 即可使用。
*/
import { number } from 'echarts'
import {
getCurrentInstance,
computed,
ref,
ComponentInternalInstance,
inject,
onUpdated,
onMounted,
onUnmounted,
nextTick,
watch,
ssrContextKey
} from 'vue'
// #ifdef APP-NVUE
import CanvasRenderingContext2D from '../../tool/gcanvas/context-2d/RenderingContext.js'
import { enable, WeexBridge } from '../../tool/gcanvas/index.js'
const dom = uni.requireNativePlugin('dom')
// #endif
const proxy = getCurrentInstance()?.proxy ?? null
const props = defineProps({
width: {
type: Number,
default: 750
},
height: {
type: Number,
default: 500
},
lineWidth: {
type: Number,
default: 5
},
lineColor: {
type: String,
default: 'red'
}
})
const canvasId = ref('canvasId')
// #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ
canvasId.value = 'tm' + uni.$tm.u.getUid(5)
// #endif
let ctx: CanvasRenderingContext2D
let canvasObject: HTMLCanvasElement
let ctxLeft = 0
let ctxTop = 0
let drawhd: draw
const show = ref(false) //安卓上首次要隐藏不然卡。
let isAndroid = false
// #ifdef APP-NVUE
isAndroid = uni.getSystemInfoSync().osName == 'android'
// #endif
onMounted(() => {
// #ifdef APP-NVUE
if (isAndroid) {
setTimeout(() => {
show.value = true
setTimeout(function () {
drawNvue_init()
}, 100)
}, 200)
} else {
show.value = true
setTimeout(() => drawNvue_init(), 250)
}
// #endif
// #ifdef MP-WEIXIN || MP-ALIPAY || MP-QQ
setTimeout(() => MpWeix_init(), 100)
// #endif
// #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ || APP-NVUE
setTimeout(() => appvueH5Other(), 50)
// #endif
})
//appvue,h5,和其它平台。
function appvueH5Other() {
ctx = uni.createCanvasContext(canvasId.value, proxy)
uni.createSelectorQuery()
.in(proxy)
.select('#' + canvasId.value)
.boundingClientRect((result) => {
ctxLeft = result.left ?? 0
ctxTop = result.top ?? 0
drawhd = new draw(ctx, uni.upx2px(props.width), uni.upx2px(props.height))
})
.exec()
}
function drawNvue_init() {
/*获取元素引用*/
var ganvas = proxy?.$refs[canvasId.value]
/*通过元素引用获取canvas对象*/
var canvasObj = enable(ganvas, {
bridge: WeexBridge
})
canvasObject = canvasObj
ctx = canvasObj.getContext('2d')
nextTick(function () {
setTimeout(function () {
dom?.getComponentRect(proxy?.$refs.tmspin, function (res: any) {
if (res?.size) {
ctxLeft = Math.floor(res.size.left)
ctxTop = Math.floor(res.size.top)
drawhd = new draw(ctx, uni.upx2px(props.width), uni.upx2px(props.height))
}
})
}, 200)
})
}
//支付宝和微信QQ 支持2d渲染。
function MpWeix_init() {
const query = uni.createSelectorQuery().in(proxy)
// #ifdef MP-ALIPAY
query
.select('#canvasId')
.node()
.exec((res2) => {
const canvas = res2[0].node
let ctxvb: UniApp.CanvasContext = canvas.getContext('2d')
ctx = ctxvb
drawhd = new draw(ctx, uni.upx2px(props.width), uni.upx2px(props.height))
})
// #endif
// #ifdef MP-WEIXIN || MP-QQ
query
.select('#canvasId')
.fields({
node: true,
size: true,
rect: true,
context: true
})
.exec((res: Array<UniApp.NodeInfo>) => {
ctxLeft = res[0].left
ctxTop = res[0].top
// #ifndef MP-QQ
const canvas = res[0].node
const ctxvb = canvas.getContext('2d')
const dpr = uni.getSystemInfoSync().pixelRatio
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
ctxvb.scale(dpr, dpr)
ctx = ctxvb
canvasObject = canvas
drawhd = new draw(ctx, uni.upx2px(props.width), uni.upx2px(props.height))
// #endif
// #ifdef MP-QQ
ctx = res[0].context
drawhd = new draw(ctx, uni.upx2px(props.width), uni.upx2px(props.height))
// #endif
})
// #endif
}
function touchstart(event: TouchEvent | MouseEvent) {
if (!drawhd) return
if (event.type.indexOf('mouse') == -1 && event.changedTouches.length == 1) {
var touch = event.changedTouches[0]
// #ifdef APP-NVUE
if (isAndroid) {
drawhd.down(touch.pageX, touch.pageY)
} else {
drawhd.down(touch.pageX - ctxLeft, touch.pageY - ctxTop)
}
// #endif
// #ifndef APP-NVUE
drawhd.down(touch.x, touch.y)
// #endif
} else {
drawhd.down(event.pageX - event.currentTarget.offsetLeft - ctxLeft, event.pageY - event.currentTarget.offsetTop - ctxTop)
}
}
function touchsmove(event: TouchEvent | MouseEvent) {
if (!drawhd) return
try{
if (event?.preventDefault) event?.preventDefault()
if (event?.stopPropagation) event?.stopPropagation()
}catch(e){
//TODO handle the exception
}
if (event.type.indexOf('mouse') == -1 && event.changedTouches.length == 1) {
var touch = event.changedTouches[0]
// #ifdef APP-NVUE
if (isAndroid) {
drawhd.move(touch.pageX, touch.pageY)
} else {
drawhd.move(touch.pageX - ctxLeft, touch.pageY - ctxTop)
}
// #endif
// #ifndef APP-NVUE
drawhd.move(touch.x, touch.y)
// #endif
} else {
drawhd.move(event.pageX - event.currentTarget.offsetLeft - ctxLeft, event.pageY - event.currentTarget.offsetTop - ctxTop)
}
}
function touchsend(event: TouchEvent | MouseEvent) {
if (!drawhd) return
if (event.type.indexOf('mouse') == -1 && event.changedTouches.length == 1) {
var touch = event.changedTouches[0]
// #ifdef APP-NVUE
if (isAndroid) {
drawhd.up(touch.pageX, touch.pageY)
} else {
drawhd.up(touch.pageX - ctxLeft, touch.pageY - ctxTop)
}
// #endif
// #ifndef APP-NVUE
drawhd.up(touch.x, touch.y)
// #endif
} else {
drawhd.up(event.pageX - event.currentTarget.offsetLeft - ctxLeft, event.pageY - event.currentTarget.offsetTop - ctxTop)
}
}
/**
* 清除当前画板
*/
function clear() {
if (!ctx) {
uni.showToast({ title: '初始化失败', icon: 'none' })
return
}
ctx.clearRect(0, 0, uni.upx2px(props.width), uni.upx2px(props.height))
// #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ
ctx.draw(false)
// #endif
}
/**
* 保存当前画板内容
* 在h5端面返回的是base64位图片内容其它端返回的是临时路径。
*/
interface imageData {
width: number
height: number
data: ArrayBuffer
}
function save(): Promise<string> {
return new Promise((su, fa) => {
if (!ctx) {
uni.showToast({ title: '初始化失败', icon: 'none' })
fa('初始化失败')
return
}
// #ifdef APP-NVUE
uni.showLoading({ title: '...' })
// ctx.getImageData(0,0,props.width,props.height,function(res:imageData){
// console.log(ArrayBufferToBase64(res.data).length)
// fa(true)
// uni.hideLoading()
// })
ctx.toTempFilePath(0, 0, props.width, props.height, uni.upx2px(props.width), uni.upx2px(props.height), 'png', 1, function (res) {
uni.hideLoading()
console.log(res.errMsg)
if (res.errMsg == 'canvasToTempFilePath:ok') {
su(res.tempFilePath)
} else {
fa(res.errMsg)
}
})
// #endif
//webgl保存图片的方法
// #ifndef APP-NVUE
uni.canvasToTempFilePath(
{
x: 0,
y: 0,
destWidth: uni.upx2px(props.width),
destHeight: uni.upx2px(props.height),
width: props.width,
height: props.height,
// #ifndef MP-ALIPAY
canvasId: canvasId.value,
// #endif
canvas: canvasObject,
success: function (res) {
// 在H5平台下tempFilePath 为 base64
su(res.tempFilePath)
},
fail: (res) => {
console.error(res)
fa(res)
}
},
proxy
)
// #endif
})
}
defineExpose({ save, clear })
interface points {
x: number
y: number
}
class draw {
_x = 0
_y = 0
_lineWidth = 2
_lineColor = 'black'
cx: CanvasRenderingContext2D
width = 0
height = 0
_isDown = false
_points: Array<points> = []
constructor(ctx: CanvasRenderingContext2D, w: number, h: number, lineWidth = 2, lineColor = 'black') {
this._lineColor = lineColor
this._lineWidth = lineWidth
this.width = w
this.height = h
this.cx = ctx
}
down(x = 0, y = 0) {
this._isDown = true
this._x = x
this._y = y
}
move(x = 0, y = 0) {
if (!this._isDown) return
// #ifdef MP-WEIXIN || MP-ALIPAY || MP-QQ
ctx.strokeStyle = props.lineColor
ctx.lineWidth = props.lineWidth
ctx.lineCap = 'round'
// #endif
// #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ
ctx.setStrokeStyle(props.lineColor)
ctx.setLineWidth(props.lineWidth)
ctx.setLineCap('round')
// #endif
ctx.beginPath()
ctx.moveTo(this._x, this._y)
ctx.lineTo(x, y)
ctx.stroke()
ctx.closePath()
// #ifndef MP-WEIXIN || MP-ALIPAY
ctx.draw(true)
// #endif
this._x = x
this._y = y
}
up(x = 0, y = 0) {
this._isDown = false
this._x = x
this._y = y
}
}
</script>
<style scoped></style>