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.
190 lines
4.8 KiB
190 lines
4.8 KiB
<template>
|
|
<canvas
|
|
:style="{ backgroundColor: backgroundColor, borderRadius: borderRadius }"
|
|
ref="inkCanvasRef"
|
|
:width="width"
|
|
:height="height"
|
|
id="ink-canvas"
|
|
></canvas>
|
|
<div></div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { reactive, computed, onMounted, onBeforeUnmount, watch, ref } from 'vue'
|
|
import { getHandWriting } from '@/http/api'
|
|
|
|
type WriteType = 'CN' | 'EN'
|
|
|
|
type State = {
|
|
handWrite: string
|
|
isClick: boolean
|
|
//轨迹X
|
|
clickX: number[]
|
|
//轨迹Y
|
|
clickY: number[]
|
|
//轨迹标志位,为1则是终点
|
|
clickC: number[]
|
|
X: number
|
|
Y: number
|
|
oldX: number
|
|
oldY: number
|
|
timer: number
|
|
list: string[] //返回汉字列表
|
|
}
|
|
|
|
type Props = {
|
|
width: number
|
|
height: number
|
|
lang: WriteType
|
|
backgroundColor: string
|
|
borderRadius: string
|
|
fillText: string
|
|
fillFontSize: string
|
|
strokeStyle: string
|
|
fillStyle: string
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
width: 800,
|
|
height: 800,
|
|
lang: 'CN',
|
|
backgroundColor: '#f2f2f2',
|
|
borderRadius: '10px',
|
|
fillText: '手写区域',
|
|
fillFontSize: '100px',
|
|
strokeStyle: '#000',
|
|
fillStyle: 'rgba(85, 73, 54, 0.1)'
|
|
})
|
|
const emits = defineEmits(['result'])
|
|
|
|
const state = reactive<State>({
|
|
handWrite: '',
|
|
isClick: false,
|
|
//轨迹X
|
|
clickX: [],
|
|
//轨迹Y
|
|
clickY: [],
|
|
//轨迹标志位,为1则是终点
|
|
clickC: [],
|
|
X: 0,
|
|
Y: 0,
|
|
oldX: 0,
|
|
oldY: 0,
|
|
timer: 0,
|
|
list: [] //返回汉字列表
|
|
})
|
|
|
|
const inkCanvasRef = ref<HTMLCanvasElement | null>(null)
|
|
const ctxComRef = computed(() => (inkCanvasRef.value as HTMLCanvasElement).getContext('2d'))
|
|
|
|
function updateBound() {
|
|
const bound = (inkCanvasRef.value as HTMLCanvasElement).getBoundingClientRect()
|
|
state.X = bound.x
|
|
state.Y = bound.y
|
|
}
|
|
function down(ev: MouseEvent | TouchEvent) {
|
|
const cx = Math.floor((ev as MouseEvent).clientX || (ev as TouchEvent).targetTouches[0].clientX) - state.X
|
|
|
|
const cy = Math.floor((ev as MouseEvent).clientY || (ev as TouchEvent).targetTouches[0].clientY) - state.Y
|
|
|
|
clearTimeout(state.timer)
|
|
state.oldX = cx
|
|
state.oldY = cy
|
|
ctxComRef.value && ctxComRef.value.beginPath()
|
|
state.isClick = true
|
|
}
|
|
function move(ev: MouseEvent | TouchEvent) {
|
|
ev.preventDefault()
|
|
if (state.isClick) {
|
|
const cx = Math.floor((ev as MouseEvent).clientX || (ev as TouchEvent).targetTouches[0].clientX) - state.X
|
|
const cy = Math.floor((ev as MouseEvent).clientY || (ev as TouchEvent).targetTouches[0].clientY) - state.Y
|
|
|
|
state.clickX.push(cx)
|
|
state.clickY.push(cy)
|
|
state.clickC.push(0)
|
|
|
|
//画图
|
|
;(ctxComRef.value as CanvasRenderingContext2D).lineWidth = 8
|
|
;(ctxComRef.value as CanvasRenderingContext2D).lineCap = 'round'
|
|
ctxComRef.value && ctxComRef.value.moveTo(state.oldX, state.oldY)
|
|
ctxComRef.value && ctxComRef.value.lineTo(cx, cy)
|
|
ctxComRef.value && ctxComRef.value.stroke()
|
|
state.oldX = cx
|
|
state.oldY = cy
|
|
}
|
|
}
|
|
function mouseUp() {
|
|
if (state.isClick) {
|
|
state.isClick = false
|
|
state.timer = setTimeout(() => {
|
|
reload()
|
|
}, 1500)
|
|
//标记最后一点为终点
|
|
state.clickC.pop()
|
|
state.clickC.push(1)
|
|
_getHandWriting()
|
|
}
|
|
}
|
|
|
|
function reload() {
|
|
if (!inkCanvasRef.value) {
|
|
return
|
|
}
|
|
state.clickX = []
|
|
state.clickY = []
|
|
state.clickC = []
|
|
;(ctxComRef.value as CanvasRenderingContext2D).strokeStyle = props.strokeStyle
|
|
;(ctxComRef.value as CanvasRenderingContext2D).fillStyle = props.fillStyle
|
|
;(ctxComRef.value as CanvasRenderingContext2D).clearRect(0, 0, props.width, props.height)
|
|
;(ctxComRef.value as CanvasRenderingContext2D).font = `bold ${props.fillFontSize} Arial`
|
|
;(ctxComRef.value as CanvasRenderingContext2D).textAlign = 'center'
|
|
;(ctxComRef.value as CanvasRenderingContext2D).textBaseline = 'middle'
|
|
ctxComRef.value && ctxComRef.value.fillText(props.fillText, props.width / 2, props.height / 2, 1000)
|
|
}
|
|
function _getHandWriting() {
|
|
const params = {
|
|
lib: props.lang,
|
|
lpXis: state.clickX,
|
|
lpYis: state.clickY,
|
|
lpCis: state.clickC
|
|
}
|
|
getHandWriting(params)
|
|
.then(res => {
|
|
const { data } = res
|
|
state.list = data as string[]
|
|
})
|
|
.catch(err => {
|
|
console.log(err)
|
|
})
|
|
}
|
|
|
|
watch(
|
|
() => state.list,
|
|
newVal => {
|
|
emits('result', newVal)
|
|
}
|
|
)
|
|
|
|
onMounted(() => {
|
|
updateBound()
|
|
reload()
|
|
;(inkCanvasRef.value as HTMLElement).addEventListener('touchstart', down)
|
|
;(inkCanvasRef.value as HTMLElement).addEventListener('touchmove', move)
|
|
;(inkCanvasRef.value as HTMLElement).addEventListener('touchend', mouseUp)
|
|
})
|
|
onBeforeUnmount(() => {
|
|
;(inkCanvasRef.value as HTMLElement).removeEventListener('touchstart', down)
|
|
;(inkCanvasRef.value as HTMLElement).removeEventListener('touchmove', move)
|
|
;(inkCanvasRef.value as HTMLElement).removeEventListener('touchend', mouseUp)
|
|
})
|
|
|
|
defineExpose({
|
|
updateBound,
|
|
reload
|
|
})
|
|
|
|
defineExpose({
|
|
updateBound,
|
|
reload
|
|
})
|
|
</script>
|
|
|