效果展现javascript
getImageData()
返回ImageData
对象,该对象为画布上指定的矩形复制像素数据html
putImageData()
把图像数据(从指定的 ImageData
对象)放回画布上java
clearRect()
在给定的矩形内清除指定的像素git
toDataURL()
返回canvas图像的URLgithub
lineTo()
添加一个新点,建立从该点到最后指定点的线条canvas
stroke()
绘制已定义的路径数组
beginPath()
起始一条路径,或重置当前路径this
moveTo()
把路径移动到画布中的指定点,不建立线条spa
strokeStyle
设置或返回用于笔触的颜色、渐变或模式code
shadowBlur
设置或返回用于阴影的模糊级别
shadowColor
设置或返回用于阴影的颜色
lineWidth
设置或返回当前的线条宽度
更多API请参考 canvas基本使用
基础线条绘制功能
笔触颜色修改
笔刷粗细调整
撤回、前进、状况功能
生成图片
colors
: 笔触颜色列表
brushs
: 笔刷对应的粗细
context
: canvas context
imgUrl
: 用于存放保存图片的地址
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数据):
<!-- 画笔颜色 --> <li v-for="item in colors" :class="{'active':config.lineColor === item}" :style="{ background: item }" @click="setColor(item)" ></li>
<!-- 画笔粗细 --> <span v-for="pen in brushs" :class="[pen.className,{'active': config.lineWidth === pen.lineWidth}]" @click="setBrush(pen.lineWidth)" ></span>
// 当在屏幕中移动时即开始绘制准备 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等。
<canvas id="canvas" class="fl" width="600" height="400" @mousedown="canvasDown($event)" @mouseup="canvasUp($event)" @mousemove="canvasMove($event)" @touchstart="canvasDown($event)" @touchend="canvasUp($event)" @touchmove="canvasMove($event)" >
// 撤销 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]]