今天分享一个vue开发小应用:使用Canvas模拟手写中文签字。我们经常去银行办理业务的时候,需要在设备上手签文字,这个功能如何去实现呢?我们今天来模拟下。
用到的插件:
**后端接口api:**使用 QQ输入法手写接口
https://handwriting.shuru.qq.com/cloud/cgi-bin/cloud_hw_pub.wsgi
| 参数 | 说明 | 类型 | 默认值 | |-----------|---------------------------------------------------------------------------------|--------|-----| | track_str | 笔画字符串,单笔画以'x1,y1,x2,y2,...'格式拼接,多笔画在单笔画的基础上以eb拼接,例如'x1,y1,x2,y2,eb,x3,y3,x4,y4' | string | - | | cmd | 未知,目前传0 | number | - |
**注:**此接口通过其他大佬文章获知,原文在此,本人未能查到官方文档相关地址,如果有大佬知晓还请留言告知,感谢!
思路:
(1)创建一个canvas绘图区域
// template
<div class="canvas-container">
<canvas ref="canvas" width="300" height="200">你的浏览器不支持 canvas,请升级你的浏览器。</canvas>
</div>
// scss
.canvas-container {
background: #fafafa;
canvas {
background: #fff;
border: 1px solid #000;
}
}
(2)获取初始横纵坐标
data() {
return {
initX: 0, // 初始横坐标
initY: 0, // 初始纵坐标
}
},
mounted() {
this.initBound()
},
methods: {
// 初始化canvas位置
initBound() {
let bound = this.$refs.canvas.getBoundingClientRect()
this.initX = bound.x
this.initY = bound.y
}
}
(3)添加鼠标点击事件、移动事件、松开事件
// template
<div class="canvas-container">
<canvas ref="canvas" width="300" height="200" @mousedown="onMouseDown" @mousemove="onMouseMove" @mouseup="onMouseUp">你的浏览器不支持 canvas,请升级你的浏览器。</canvas>
</div>
// script
data() {
return {
// ...
lastX: 0, // 上一个横坐标
lastY: 0, // 上一个纵坐标
isHandWrite: false, // 是否开始手写
pointsXY: [], // 单笔画
allPointsXY: [], // 全部笔画
}
},
methods: {
onMouseDown(e) {
this.pointsXY = []
let cx = e.clientX - this.initX
let cy = e.clientY - this.initY
this.lastX = cx
this.lastY = cy
this.pointsXY.push(cx)
this.pointsXY.push(cy)
this.isHandWrite = true
},
onMouseMove(e) {
if (this.isHandWrite) {
let cx = e.clientX - this.initX
let cy = e.clientY - this.initY
this.pointsXY.push(cx - this.lastX)
this.pointsXY.push(cy - this.lastY)
// 获取2d上下文对象
let ctx = this.$refs.canvas.getContext('2d')
// 新建一条路径
ctx.beginPath()
ctx.strokeStyle = '#000'
ctx.fillStyle = '#000'
ctx.lineWidth = 8
ctx.lineCap = 'round'
ctx.moveTo(this.lastX, this.lastY)
ctx.lineTo(cx, cy)
ctx.stroke()
this.lastX = cx
this.lastY = cy
}
},
onMouseUp(e) {
if (this.isHandWrite) {
this.isHandWrite = false
this.allPointsXY.push(this.pointsXY.join(','))
this.queryText() // 识别文字
}
},
}
(4)添加识别文字接口以及jsonp回调函数,跨域请求使用了 vue-jsonp。
// script
data() {
return {
// ...
write_result: [], // 返回相近字
}
},
mounted() {
// ...
let _this = this
// 添加jsonp回调函数, qq输入法特定
window['QQShuru'] = {
HWPanel: {
ajax_callback: function (res) {
_this.write_result = res.cand
},
},
}
},
methods: {
queryText() {
let track_str = this.allPointsXY.join(',eb,')
this.$jsonp(
`https://handwriting.shuru.qq.com/cloud/cgi-bin/cloud_hw_pub.wsgi?track_str=${track_str}&cmd=0`
).catch(err => {
console.log(err)
})
},
}
5)最后再加个清除画布的重写按钮
// template
<div>
<button @click="onReload">重写</button>
</div>
// script
onReload() {
if (!this.$refs.canvas) return
this.pointsXY = []
this.allPointsXY = []
let ctx = this.$refs.canvas.getContext('2d')
ctx.clearRect(0, 0, 300, 200)
试试吧,如果看懂了,觉得并没想象中的那么复杂吧。最后还是分享下完整代码吧:
<template>
<div id="app">
<div>
<canvas ref="canvas" width="300" height="200" @mousedown="onMouseDown" @mousemove="onMouseMove" @mouseup="onMouseUp">你的浏览器不支持 canvas,请升级你的浏览器。</canvas>
</div>
<div>[{{ lastX + ', ' + lastY }}]</div>
<div>
<button @click="onReload">重写</button>
</div>
<div>返回相近字:{{ write_result }}</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
initX: 0, // 初始横坐标
initY: 0, // 初始纵坐标
lastX: 0, // 上一个横坐标
lastY: 0, // 上一个纵坐标
isHandWrite: false, // 是否开始手写
pointsXY: [], // 单笔画
allPointsXY: [], // 全部笔画
write_result: [], // 返回相近字
}
},
mounted() {
this.initBound()
let _this = this
// 添加jsonp回调函数, qq输入法特定
window['QQShuru'] = {
HWPanel: {
ajax_callback: function (res) {
_this.write_result = res.cand
},
},
}
},
methods: {
// 初始化canvas位置
initBound() {
let bound = this.$refs.canvas.getBoundingClientRect()
this.initX = bound.x
this.initY = bound.y
},
onMouseDown(e) {
console.log('onDown', e)
this.pointsXY = []
let cx = e.clientX - this.initX
let cy = e.clientY - this.initY
this.lastX = cx
this.lastY = cy
this.pointsXY.push(cx)
this.pointsXY.push(cy)
this.isHandWrite = true
},
onMouseMove(e) {
if (this.isHandWrite) {
let cx = e.clientX - this.initX
let cy = e.clientY - this.initY
this.pointsXY.push(cx - this.lastX)
this.pointsXY.push(cy - this.lastY)
// 获取2d上下文对象
let ctx = this.$refs.canvas.getContext('2d')
// 新建一条路径
ctx.beginPath()
ctx.strokeStyle = '#000'
ctx.fillStyle = '#000'
ctx.lineWidth = 8
ctx.lineCap = 'round'
ctx.moveTo(this.lastX, this.lastY)
ctx.lineTo(cx, cy)
ctx.stroke()
this.lastX = cx
this.lastY = cy
}
},
onMouseUp(e) {
if (this.isHandWrite) {
this.isHandWrite = false
this.allPointsXY.push(this.pointsXY.join(','))
this.queryText()
}
},
// 识别文字
queryText() {
let track_str = this.allPointsXY.join(',eb,')
this.$jsonp(
`https://handwriting.shuru.qq.com/cloud/cgi-bin/cloud_hw_pub.wsgi?track_str=${track_str}&cmd=0`
).catch(err => {
console.log(err)
})
},
onReload() {
if (!this.$refs.canvas) return
this.pointsXY = []
this.allPointsXY = []
let ctx = this.$refs.canvas.getContext('2d')
ctx.clearRect(0, 0, 300, 200)
},
},
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
.canvas-container {
background: #fafafa;
canvas {
background: #fff;
border: 1px solid #000;
}
}
}
</style>