设置点赞签名代码
export class Signature {
width: number = 300
height: number = 300
canvas!: HTMLCanvasElement
ctx!: CanvasRenderingContext2D
private drawing: boolean = false
preTask: string[] = []
nextTask: string[] = []
private allTask: { x: number; y: number; color: string }[][] = []
private itemTask: { x: number; y: number; color: string }[] = []
private lineWidth: number = 1
private color: string = '#000'
private background: string = '#ff234234'
constructor(
canvas: HTMLCanvasElement,
width: number,
height: number,
lineWidth?: number,
color?: string
) {
if (canvas instanceof HTMLCanvasElement != true) {
console.warn('请传入一个Canvas元素')
return
}
this.canvas = canvas
this.canvas.width = width || this.width
this.canvas.height = height || this.height
this.lineWidth = lineWidth || this.lineWidth
this.color = color || this.color
this.ctx = canvas.getContext('2d') as CanvasRenderingContext2D
this.eventListener()
this.initCanvas()
this.setColor()
this.setLineWidth()
}
private initCanvas() {
this.allTask = []
this.preTask = []
this.nextTask = []
this.ctx.imageSmoothingEnabled = true
this.ctx.lineJoin = 'round' // 圆角连接
this.ctx.lineCap = 'round' // 圆角线帽
// this.ctx.translate(0.5, 0.5)
this.ctx.strokeStyle = this.color
}
private eventListener() {
this.canvas.addEventListener('mousedown', this.canvasMouseDown.bind(this))
this.canvas.addEventListener('mousemove', this.canvasMouseMove.bind(this))
this.canvas.addEventListener('mouseup', this.canvasMouseEnd.bind(this))
this.canvas.addEventListener('mouseout', this.canvasMouseEnd.bind(this))
}
removeEventListener() {
this.canvas.removeEventListener(
'mousedown',
this.canvasMouseDown.bind(this)
)
this.canvas.removeEventListener(
'mousemove',
this.canvasMouseMove.bind(this)
)
this.canvas.removeEventListener('mouseup', this.canvasMouseEnd.bind(this))
this.canvas.removeEventListener('mouseout', this.canvasMouseEnd.bind(this))
}
private canvasMouseDown(e: MouseEvent) {
this.drawing = true
this.ctx.beginPath() // 开始绘制
this.ctx.moveTo(e.offsetX, e.offsetY) // 移动到
this.itemTask.push({
x: e.offsetX,
y: e.offsetY,
color: this.color,
})
}
private canvasMouseMove(e: MouseEvent) {
if (this.drawing) {
this.ctx.lineTo(e.offsetX, e.offsetY) // 绘制到
this.ctx.stroke() // 绘制
this.itemTask.push({
x: e.offsetX,
y: e.offsetY,
color: this.color,
})
}
}
private canvasMouseEnd(e: MouseEvent) {
this.drawing = false
this.ctx.closePath()
const index = this.preTask.findIndex((item) => {
return item === this.toDataURL()
})
if (index === -1) {
this.preTask.push(this.toDataURL())
}
this.allTask.push(this.itemTask)
this.itemTask = []
}
/**
* @description: 设置画笔颜色
* @param {string} color
* @return {*}
*/
setColor(color?: string) {
this.color = color || this.color
this.ctx.strokeStyle = this.color
}
/**
* @description: 设置画布背景
* @param {string} background
* @return {*}
*/
setBgColor(background?: string) {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
this.background = background || this.background
this.ctx.fillStyle = this.background
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
this.allTask.length ? this.setPathLine() : ''
}
/**
* @description: 设置折线
* @return {*}
*/
private setPathLine() {
const taskFilter = this.allTask.filter((item) => {
return item.length
})
taskFilter.forEach((item) => {
this.ctx.beginPath()
this.ctx.moveTo(item[0].x, item[0].y)
item.forEach((list, index) => {
if (index) {
this.ctx.lineTo(list.x, list.y)
this.ctx.strokeStyle = list.color
this.ctx.stroke()
}
})
this.ctx.closePath()
})
}
/**
* @description: 设置线条宽度
* @param {number} width
* @return {*}
*/
setLineWidth(width?: number) {
this.lineWidth = width || this.lineWidth
this.ctx.lineWidth = this.lineWidth
}
/**
* @description: 清空画布
* @return {*}
*/
clear() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
this.preTask = []
this.nextTask = []
this.allTask = []
}
/**
* @description: 上一个画布
* @return {*}
*/
setPreImage() {
if (this.preTask.length > 0) {
const currentData = this.preTask.pop()!
this.allTask.pop()!
this.nextTask.push(currentData)
const previousData = this.preTask[this.preTask.length - 1]
if (previousData) {
this.drawImage(previousData).then(() => console.log('撤销成功'))
} else {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
console.log('画布已清空')
}
console.log(
`撤销: preTask = ${this.preTask.length}, nextTask = ${this.nextTask.length}`
)
}
}
/**
* @description: 下一个画布
* @return {*}
*/
setNextImage() {
if (this.nextTask.length > 0) {
const nextData = this.nextTask.pop()!
this.preTask.push(nextData)
this.drawImage(nextData).then(() => console.log('恢复成功'))
console.log(
`恢复: preTask = ${this.preTask.length}, nextTask = ${this.nextTask.length}`
)
}
}
/**
* @description: 导入图片
* @param {string} src
* @return {*}
*/
drawImage(
src: string,
x = 0,
y = 0,
width = this.canvas.width,
height = this.canvas.height
) {
return new Promise((resolve, reject) => {
const image = new Image()
image.onload = (e) => {
this.ctx.clearRect(x, y, width, height)
this.ctx.drawImage(image, x, y, width, height)
resolve(e)
}
image.onerror = (e) => {
reject(e)
}
image.src = src
})
}
/**
* @description: 转换成base64
* @return {*}
*/
toDataURL(
format: 'image/png' | 'image/jpeg' = 'image/png',
quality: number = 1.0
): string {
return this.canvas.toDataURL(format, quality)
}
/**
* @description: 导出图片
* @return {*}
*/
exportToImage(fileName: string) {
const url = this.canvas.toDataURL('image/png')
var link = document.createElement('a')
link.download = fileName
link.href = url
link.click()
}
}