canvas api 文档:https://www.canvasapi.cn/
组件里的 canvas
<canvas class="handWriting" id="handWriting" canvas-id="handWriting" type="2d" disable-scroll="true" @touchstart="uploadScaleStart" @touchmove="uploadScaleMove" @touchend="uploadScaleEnd" @touchcancel="uploadScaleEnd" @tap.stop />
this.handwriting = new Handwriting( { canvasName: 'handWriting', }, this )
import { systemObj, loadImgSync, canvasToUrlSync } from '../../utils/utils'
class Handwriting {
// 内置数据
ctx: any
canvas: any
canvasWidth = 300
canvasHeight = 600
canvasSaveImgs: any = []
drawCurrent = 0
beginPoint: any = {}
points: any = []
canvasName = ''
that = {}
firstTouch = true // 第一次触发
lineColorVal = ''
lineColorAlpha = 1
lineSize = 10
isClear = false // 橡皮擦
constructor(opts: any, _this: any) {
this.canvasName = opts.canvasName || 'handWriting'
this.that = _this
this.init()
}
init() {
const query = uni.createSelectorQuery().in(this.that)
const config = { node: true, size: true }
query
.select(`#${this.canvasName}`)
.fields(config, (res: any) => {
// console.log('canvas init:=>', res, systemObj)
const canvas = res.node
const ctx = canvas.getContext('2d')
const { pixelRatio: dpr } = systemObj
const width = res.width * dpr
const height = res.height * dpr
canvas.width = width
canvas.height = height
ctx.scale(dpr, dpr)
this.ctx = ctx
this.canvas = canvas
this.canvasWidth = width
this.canvasHeight = height
// ctx.fillRect(10, 10, 33, 33) // test
})
.exec()
}
// 笔迹开始
uploadScaleStart(event: any) {
// console.log('start', event)
const e = event.mp
if (e.type !== 'touchstart') return false
const { x, y } = e.touches[0]
this.points.push({ x, y })
this.beginPoint = { x, y }
this.ctx.strokeStyle = `rgba(${this.lineColorVal}, ${this.lineColorAlpha})`
this.ctx.lineWidth = this.lineSize
if (systemObj.platform !== 'devtools') {
this.ctx.lineCap = 'round'
let type = 'source-over'
this.isClear && (type = 'destination-out')
this.ctx.globalCompositeOperation = type
}
// if (this.firstTouch) {
// this.firstTouch = false
// }
}
drawLine(beginPoint: any, controlPoint: any, endPoint: any) {
this.ctx.beginPath()
this.ctx.moveTo(beginPoint.x, beginPoint.y)
this.ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y)
this.ctx.stroke()
this.ctx.closePath()
}
// 笔迹移动
uploadScaleMove(event: any) {
// console.log('move')
let e = event.mp
if (e.type !== 'touchmove') return false
if (e.cancelable) {
// 判断默认行为是否已经被禁用
if (!e.defaultPrevented) {
e.preventDefault()
}
}
const { x, y } = e.touches[0]
this.points.push({ x, y })
if (this.points.length > 3) {
const lastTwoPoints = this.points.slice(-2)
const controlPoint = lastTwoPoints[0]
const endPoint = {
x: (lastTwoPoints[0].x + lastTwoPoints[1].x) / 2,
y: (lastTwoPoints[0].y + lastTwoPoints[1].y) / 2,
}
this.drawLine(this.beginPoint, controlPoint, endPoint)
this.beginPoint = endPoint
}
}
// 笔迹结束
async uploadScaleEnd(event: any) {
const e = event.mp
if (e.type != 'touchend') return 0
const { x, y } = e.changedTouches[0]
this.points.push({ x, y })
if (this.points.length > 3) {
const lastTwoPoints = this.points.slice(-2)
const controlPoint = lastTwoPoints[0]
const endPoint = lastTwoPoints[1]
this.drawLine(this.beginPoint, controlPoint, endPoint)
}
this.beginPoint = null
this.points = []
await this.drawEnd()
}
async getCanvasUrl() {
return await canvasToUrlSync(this.canvas)
}
async drawEnd() {
const saveSteps = this.canvasSaveImgs.length
if (this.drawCurrent > 0) {
this.canvasSaveImgs.length = saveSteps - this.drawCurrent
this.drawCurrent = 0
}
this.canvasSaveImgs.push(await this.getCanvasUrl())
}
selectColorEvent(val: any) {
this.lineColorVal = val
this.isClear = false
}
selectLineSize(val: any) {
this.lineSize = val
}
clearEvent() {
this.isClear = true
}
noClearEvent() {
this.isClear = false
}
clearAllCanvas() {
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
}
async stepChange(type: string) {
const saveSteps = this.canvasSaveImgs.length
if (type === 'last') {
if (this.drawCurrent < saveSteps) {
this.drawCurrent++
} else {
return
}
}
if (type === 'next') {
if (this.drawCurrent > 0) {
this.drawCurrent--
} else {
return
}
}
this.clearAllCanvas()
this.ctx.globalCompositeOperation = 'source-over'
if (this.drawCurrent === saveSteps) {
return
}
const index = saveSteps - this.drawCurrent - 1
const { pixelRatio: dpr } = systemObj
const img: any = await loadImgSync(this.canvas, this.canvasSaveImgs[index])
this.ctx.drawImage(
img,
0,
0,
this.canvasWidth,
this.canvasHeight,
0,
0,
this.canvasWidth / dpr,
this.canvasHeight / dpr
)
}
getHelpfulData() {
return {
drawCurrent: this.drawCurrent,
saveSteps: this.canvasSaveImgs.length,
}
}
}
export default Handwriting
utils.js
export function loadImgSync(canvas: any, url: string) { const img = canvas.createImage() img.src = url return new Promise((resolve, reject) => { img.onload = () => { resolve(img) } }) } export function canvasToUrlSync(canvas: any) { return new Promise((resolve, reject) => { wx.canvasToTempFilePath({ canvas, success: async (res: any) => { // console.log('tools-url:>', res.tempFilePath) // uni.previewImage({ // urls: [res.tempFilePath] // }) resolve(res.tempFilePath) }, fail: (err) => { console.log('图片生成失败:' + JSON.stringify(err)) reject() }, }) }) }
export const systemInfo = uni.getSystemInfoSync()