产品经理:我要实现一个集画笔颜色选择器、橡皮擦、旋转,撤销,导入图片
等功能的白板
我:***
但是为了生活,我最终还是低头了!!!
1.初始化画布
getContext
:获取一个 2D 渲染上下文对象。这个上下文对象提供了一系列的绘图方法和属性,用于在画布上进行二维图形的绘制
less
<canvas
ref="canvas"
id="canvas"
:width="canvasHeight"
:height="canvasHeight"
:style="{ top: -(canvasHeight - canvasWidth) / 2 + 'px' }"
@touchstart="touchstart"
@touchmove="touchmove"
@touchend="touchend"
></canvas>
当开始绘制时,计算出画笔开始和结束位置
kotlin
//开始触摸/绘制
touchstart(e) {
this.isDrawing = true
this.startX = e.touches[0].clientX - this.canvas.offsetLeft
this.startY = e.touches[0].clientY - this.canvas.offsetTop
},
移动期间,区分是画笔还是橡皮擦模式
如果是画笔模式,则调用以下方法完成画笔绘制效果
beginPath()
: 开始创建路径moveTo(x, y)
: 将当前点移动到指定的坐标位置lineTo(x, y)
: 从当前点画一条直线到指定的坐标位置stroke()
: 绘制路径的边框
如果是橡皮擦模式,则使用clearRect清除区域像素
clearRect
:清除指定矩形区域内的内容,它会将指定区域的像素设置为透明,从而实现清空画布或擦除特定区域的效果
kotlin
//移动
touchmove(e) {
let x = e.touches[0].clientX - this.canvas.offsetLeft//画笔开始x轴位置
let y = e.touches[0].clientY - this.canvas.offsetTop//画笔开始y轴位置
// 如果是橡皮擦模式
if (this.isRubber) {
this.ctx.clearRect(x - 10, y - 10, 16, 16)
return
}
this.ctx = this.canvas.getContext('2d')
if (!this.isDrawing) return
this.ctx.beginPath()
this.ctx.moveTo(this.startX, this.startY)
this.ctx.lineTo(x, y)
this.ctx.stroke()
this.startX = x
this.startY = y
this.backFlag = true
}
当用户手指离开屏幕时,记录画布上的操作
getImageData
:获取指定矩形区域内的像素数据。它返回一个 ImageData
对象,其中包含了在指定区域内每个像素的颜色信息
kotlin
//用户手指离开屏幕保存此次操作
touchend() {
if (!this.backFlag) return
const ctx = this.ctx.getImageData(
0,
0,
this.canvas.width,
this.canvas.height
)
this.canvasState.push({ctx})
this.backFlag = false
},
旋转
:旋转后将新的像素重新绘制在画布中
drawImage
:在画布上绘制图像
getImageData
:获取画布上指定矩形区域内的像素数据
kotlin
//记录画布操作
canvasOperations() {
if (!this.backFlag) return
const ctx = this.ctx.getImageData(
0,
0,
this.canvas.width,
this.canvas.height
)
this.canvasState.push({
ctx
})
this.backFlag = false
},
kotlin
//点击旋转
rotateImage() {
this.rotate('canvas', 'ctx', 90)
// 记录
this.backFlag = true
this.canvasOperations()
},
rotate(canvasName, ctx, angle) {
const canvas = this.$refs[canvasName]
const tempCanvas = document.createElement('canvas')
const tempContext = tempCanvas.getContext('2d')
tempCanvas.width = canvas.width
tempCanvas.height = canvas.height
// 旋转画布
this[ctx].translate(canvas.width / 2, canvas.height / 2)
this[ctx].rotate((angle * Math.PI) / 180)
// 恢复之前的绘画内容
this[ctx].drawImage(tempCanvas, -canvas.width / 2, -canvas.height / 2)
// 恢复画布状态
this[ctx].setTransform(1, 0, 0, 1, 0, 0)
},
撤销
:将记录每一步操作的数组删除最新一次的操作,使用putImageData
将像素数据绘制到画布上
kotlin
revoke() {
// 移除最后一个保存的状态
this.canvasState.pop()
let lastState = this.canvasState[this.canvasState.length - 1]
//将图像重新放上画布
if (this.canvasState.length > 0) {
this.ctx.putImageData(lastState.ctx, 0, 0)
} else {
//清空画布
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
}
this.backFlag = false
},
这样简易版的白板就完成了,当然各位若借鉴可借鉴思路,代码不一定完全能够实现,因为我在原本功能上删除了一些需求,导致代码可能不是很完整~
删除的功能:三层画布实现橡皮擦只能擦除画笔层、导入图片至画布、文本框拖拽至任意位置等等需求