效果展示
Canvas API简介
调用方法
getImageData()
返回ImageData
对象,该对象为画布上指定的矩形复制像素数据putImageData()
把图像数据(从指定的ImageData
对象)放回画布上clearRect()
在给定的矩形内清除指定的像素toDataURL()
返回canvas图像的URLlineTo()
添加一个新点,创建从该点到最后指定点的线条stroke()
绘制已定义的路径beginPath()
起始一条路径,或重置当前路径moveTo()
把路径移动到画布中的指定点,不创建线条
调用属性
strokeStyle
设置或返回用于笔触的颜色、渐变或模式shadowBlur
设置或返回用于阴影的模糊级别shadowColor
设置或返回用于阴影的颜色lineWidth
设置或返回当前的线条宽度
更多API请参考 canvas基本使用
功能需求说明
基础线条绘制功能
笔触颜色修改
笔刷粗细调整
撤回、前进、情况功能
生成图片
初始化数据
colors
: 笔触颜色列表brushs
: 笔刷对应的粗细context
: canvas contextimgUrl
: 用于存放保存图片的地址canvasMoveUse
: 是否允许执行move时候绘制线条preDrawAry
: 存储当前表面状态数组-上一步nextDrawAry
: 存储当前表面状态数组-下一步middleAry
: 中间数组lineWidth
: 线条宽度lineColor
: 线条颜色shadowBlur
: 阴影
data() {
return {
colors: ['#fef4ac','#0018ba','#ffc200','#f32f15','#cccccc','#5ab639'],
brushs: [{
className: 'small fa fa-paint-brush',
lineWidth: 3
},{
className: 'middle fa fa-paint-brush',
lineWidth: 6
},{
className: 'big fa fa-paint-brush',
lineWidth: 12
}],
context: {},
imgUrl: [],
canvasMoveUse: true,
preDrawAry: [],
nextDrawAry: [],
middleAry: [],
config: {
lineWidth: 1,
lineColor: "#f2849e",
shadowBlur: 2
}
}
}
设置绘画配置
setCanvasStyle() {
this.context.lineWidth = this.config.lineWidth
this.context.shadowBlur = this.config.shadowBlur
this.context.shadowColor = this.config.lineColor
this.context.strokeStyle = this.config.lineColor
}
笔触颜色及粗细相关设置(点击修改config数据):
画笔的移动操作
// 当在屏幕中移动时即开始绘制准备
beginPath(e){
const canvas = document.querySelector('#canvas')
if (e.target !== canvas) {
this.context.beginPath()
}
}
// 在canvas中鼠标按下
canvasDown(e) {
// 让move方法可用
this.canvasMoveUse = true
// client是基于整个页面的坐标
// offset是cavas距离顶部以及左边的距离
const canvasX = e.clientX - e.target.parentNode.offsetLeft
const canvasY = e.clientY - e.target.parentNode.offsetTop
// 设置canvas的配置
this.setCanvasStyle()
//清除子路径
this.context.beginPath()
// 移动的起点
this.context.moveTo(canvasX, canvasY)
//当前绘图表面状态
const preData = this.context.getImageData(0, 0, 600, 400)
//当前绘图表面进栈
// 按下相当于新的操作的开始,所以把当前记录数据放到prev中
this.preDrawAry.push(preData)
},
// canvas中鼠标移动
canvasMove(e) {
if(this.canvasMoveUse) {
// 只有允许移动时调用
const t = e.target
let canvasX
let canvasY
// 由于手机端和pc端获取页面坐标方式不同,所以需要做出判断
if(this.isPc()){
canvasX = e.clientX - t.parentNode.offsetLeft
canvasY = e.clientY - t.parentNode.offsetTop
}else {
canvasX = e.changedTouches[0].clientX - t.parentNode.offsetLeft
canvasY = e.changedTouches[0].clientY - t.parentNode.offsetTop
}
// 连接到移动的位置并上色
this.context.lineTo(canvasX, canvasY)
this.context.stroke()
}
},
// canvas中鼠标放开
canvasUp(e){
const preData = this.context.getImageData(0, 0, 600, 400)
if (!this.nextDrawAry.length) {
// 在没有撤销过的情况下,将当前数据放入prev
//当前绘图表面进栈
this.middleAry.push(preData)
} else {
// 在撤销的情况下,将在后面步骤的数据情况记录
this.middleAry = []
this.middleAry = this.middleAry.concat(this.preDrawAry)
this.middleAry.push(preData)
this.nextDrawAry = []
}
// 设置move时不可绘制
this.canvasMoveUse = false
}
为了保证移动端的可用性,加入touchstart等。
撤销清空等操作
// 撤销
if (this.preDrawAry.length) {
const popData = this.preDrawAry.pop()
const midData = this.middleAry[this.preDrawAry.length + 1]
this.nextDrawAry.push(midData)
this.context.putImageData(popData, 0, 0)
}
// 前进
if (this.nextDrawAry.length) {
const popData = this.nextDrawAry.pop()
const midData = this.middleAry[this.middleAry.length - this.nextDrawAry.length - 2]
this.preDrawAry.push(midData)
this.context.putImageData(popData, 0, 0)
}
// 清空
this.context.clearRect(0, 0, this.context.canvas.width, this.context.canvas.height)
// 清空前后数据
this.preDrawAry = []
this.nextDrawAry = []
// middleAry恢复到默认数据
this.middleAry = [this.middleAry[0]]
demo地址
查看代码