方法:
方法名 | 参数 | 返回值 | 描述 |
---|---|---|---|
getSignImage | - | string | 获取签名图片数据,直接设置给src |
resetCanvas | - | - | 清空画布,重新手写 |
核心实现
通过监听触摸事件,获取手指滑动的坐标,然后通过canvas的moveTo,lineTo方法绘制路径。
const draw = (x: number, y: number) => {
context.value?.beginPath()
context.value?.moveTo(lastPaint.x, lastPaint.y)
context.value?.lineTo(x, y)
context.value?.stroke()
}
源码
<template>
<div ref="canvas_container" class="canvas_container">
<canvas
id="canvas"
ref="canvas"
width="100%"
height="100%"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
/>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
const canvas = ref<HTMLCanvasElement>()
const context = ref<CanvasRenderingContext2D>()
let top = 0
let left = 0
let isDrawing = false
const lastPaint = { x: 0, y: 0 }
const startPaint = { x: 0, y: 0 }
const endPaint = { x: 0, y: 0 }
const initCanvas = () => {
const boundRect = document
.getElementsByClassName('canvas_container')[0]
.getBoundingClientRect()
console.log(boundRect)
top = boundRect.top
left = boundRect.left
canvas.value.width = boundRect.width
canvas.value.height = boundRect.height
startPaint.x = boundRect.width
startPaint.y = boundRect.height
context.value = canvas.value?.getContext('2d')
context.value!.lineWidth = 2
context.value!.lineCap = 'round'
context.value!.lineJoin = 'round'
context.value!.strokeStyle = '#000000'
}
onMounted(() => {
initCanvas()
})
const draw = (x: number, y: number) => {
context.value?.beginPath()
context.value?.moveTo(lastPaint.x, lastPaint.y)
context.value?.lineTo(x, y)
context.value?.stroke()
}
const touchStart = (e: TouchEvent) => {
console.log('mousemove', e)
if (e.targetTouches.length > 1) return
const x = e.targetTouches[0].clientX - left
const y = e.targetTouches[0].clientY - top
lastPaint.x = x
lastPaint.y = y
setPaint(x, y)
isDrawing = true
}
const touchMove = (e: TouchEvent) => {
if (e.targetTouches.length > 1) return
if (!isDrawing) return
const x = e.targetTouches[0].clientX - left
const y = e.targetTouches[0].clientY - top
draw(x, y)
lastPaint.x = x
lastPaint.y = y
setPaint(x, y)
}
const touchEnd = (e: TouchEvent) => {
isDrawing = false
}
const setPaint = (x: number, y: number) => {
if (x < startPaint.x) {
startPaint.x = x
}
if (y < startPaint.y) {
startPaint.y = y
}
if (x > endPaint.x) {
endPaint.x = x
}
if (y > endPaint.y) {
endPaint.y = y
}
}
/**
* 获取到签名图片数据
*/
const getSignImage = () => {
console.log('getSignImage', startPaint, endPaint)
const canvas2 = document.createElement('canvas')
canvas2.width = endPaint.x - startPaint.x
canvas2.height = endPaint.y - startPaint.y
canvas2
.getContext('2d')!
.drawImage(
canvas.value,
startPaint.x,
startPaint.y,
endPaint.x - startPaint.x,
endPaint.y - startPaint.y,
0,
0,
endPaint.x - startPaint.x,
endPaint.y - startPaint.y
)
return canvas2.toDataURL('image/png')
}
/**
* 清空画布
*/
const resetCanvas = () => {
context.value?.clearRect(0, 0, canvas.value.width, canvas.value.height)
startPaint.x = canvas.value.width
startPaint.y = canvas.value.height
endPaint.x = 0
endPaint.y = 0
}
defineExpose({ getSignImage, resetCanvas })
</script>
<style lang="scss" scoped>
.canvas_container {
position: relative;
width: 100%;
height: 100%;
}
</style>