历时一周开发了一个简单的canvas实现的画板功能,这是在vue+elementui项目里开发的,支持画笔、橡皮擦、回退、清除、保存图片、切换颜色、设置宽度等。先看最终效果:
1.我们先创建一个canvas元素
<div class="canvas">
<canvas ref="canvas" id="canvas">canvas>
div>
2.初始化画布
initCanvas() {
let that = this;
// 获取canvas元素
this.canvas = this.$refs.canvas;
// 指定了画布上绘制的类型为2d
this.ctx = this.canvas.getContext('2d');
// 获取画布相对于视窗的位置集合
let rect = this.canvas.getBoundingClientRect();
let initX = rect.x;
let initY = rect.y;
this.pageWidth = document.documentElement.clientWidth - rect.x - 50;
this.pageHeight = document.documentElement.clientHeight - rect.y - 50;
this.canvas.width = this.pageWidth;
this.canvas.height = this.pageHeight;
}
3.画笔功能
我们给一个画笔button,点击时isPainting
为true,active
表示正在使用的按钮index
<el-button :type=buttonType(0)
icon="iconfont icon-pen" round
@click="painting">
el-button>
painting() {
this.isPainting = true;
this.active = 0;
},
buttonType(param) {
if (param === this.active) {
return "primary"
}
}
我们需要监听鼠标onmousedown
、onmousemove
和onmouseup
事件
当onmousedown
时,paint属性为true,记录鼠标按下的坐标为lastPoint,moveTo
移动到目标坐标,lineTo
将两个坐标之间连起来
当onmousemove
时,设置paint属性为false,表示一次绘画结束
// 鼠标按下事件
this.canvas.onmousedown = function (e) {
that.paint = this.isPainting;
// e是浏览器坐标系上的点,必须减去canvas的原点坐标,才是准确的画布上的坐标
let x = e.clientX - initX;
let y = e.clientY - initY;
that.lastPoint = {x: x, y: y};
};
// 鼠标移动事件
this.canvas.onmousemove = function (e) {
if (that.paint) {
let x = e.clientX - initX;
let y = e.clientY - initY;
that.newPoint = {x: x, y: y};
that.drawLine();
that.lastPoint = that.newPoint;
}
};
// 鼠标松开事件
this.canvas.onmouseup = function () {
that.paint = false;
};
drawLine() {
this.ctx.lineWidth = 1;
this.ctx.lineCap = "round";
this.ctx.lineJoin = "round";
this.ctx.moveTo(this.lastPoint.x, this.lastPoint.y);
this.ctx.lineTo(this.newPoint.x, this.newPoint.y);
this.ctx.stroke();
},
4.橡皮擦功能
加入eraser按钮
点击eraser时,isPainting为false,clear属性为true,clearRect
清除区域
this.canvas.onmousedown = function (e) {
that.paint = that.isPainting;
that.clear = !that.isPainting;
let x = e.clientX - initX;
let y = e.clientY - initY;
that.lastPoint = {x: x, y: y};
};
this.canvas.onmousemove = function (e) {
if (that.clear) {
let x = e.clientX - initX;
let y = e.clientY - initY;
that.ctx.save();
that.ctx.clearRect(x, y, 10,10);
that.ctx.restore();
}
};
5.撤回
撤回功能的思路是通过getImageData()
复制画布上指定矩形的像素数据,将每次操作的像素保存在history
数组中。当点击撤回按钮时,通过putImageData()
将数组末尾的像素数据放回画布
this.canvas.onmouseup = function () {
let image = that.ctx.getImageData(0, 0, that.pageWidth, that.pageHeight);
that.history.push(image);
};
lastStep() {
this.history.pop();
this.ctx.putImageData(this.history[this.history.length - 1], 0, 0);
this.active = 2;
},
6.清空画布
context.clearRect(x,y,width,height);
参数 | 描述 |
---|---|
x | 要清除的矩形左上角的 x 坐标 |
y | 要清除的矩形左上角的 y 坐标 |
width | 要清除的矩形的宽度,以像素计 |
height | 要清除的矩形的高度,以像素计 |
clearAll() {
this.paint = this.clear = this.isPainting = false;
this.ctx.clearRect(0, 0, this.pageWidth, this.pageHeight);
this.history.length = 1;
this.active = 3;
}
7.设置线条宽度
我们加入lineWidth
属性,初始值为1,加入一个slider组件双向绑定lineWidth
,你也可以用其他更改数值的组件
<el-slider v-model="lineWidth"
:min="1"
:max="50">
el-slider>
画线时,只需要设置画布内容的lineWidth即可
this.ctx.lineWidth = this.lineWidth;
使用橡皮擦时,设置清空矩形的宽高为lineWidth
that.ctx.clearRect(x, y, that.lineWidth, that.lineWidth);
8.切换画笔颜色
初始化一个颜色数组colorArr
,给定color和style,click颜色时设置画布内容的strokeStyle
colorSize方法设置按钮的大小
<el-button v-for="(item, index) in colorArr"
:size="colorSize(index)"
:style="item.style" circle
@click="checkColor(index)">
el-button>
checkColor(param) {
this.ctx.strokeStyle = this.colorArr[param].color;
this.colorActive = param;
},
colorSize(param) {
if (param === this.colorActive) {
return "default"
} else {
return "medium"
}
},
直接修改strokeStyle,虽然画笔的颜色改了,但之前的线条颜色也一起发生了变化,所以我们需要在每次绘制时闭合路径
this.canvas.onmousedown = function (e) {
that.ctx.beginPath();
};
this.canvas.onmouseup = function () {
that.ctx.closePath();
};
9.保存画布
toDataURL()
方法把画布里的图案转变成base64编码格式的png,然后返回 Data URL数据。
创建一个a标签,设置a的href、download和target
<el-button :type="buttonType(4)"
icon="iconfont icon-save"
round @click="save">
el-button>
save() {
this.active = 4;
this.paint = this.clear = this.isPainting = false;
let imgUrl = this.canvas.toDataURL("image/png");
let saveImg = document.createElement("a");
document.body.appendChild(saveImg);
saveImg.href = imgUrl;
saveImg.download = "canvas" + (new Date).getTime();
saveImg.target = "_blank";
saveImg.click();
},
基本功能已经全部实现啦,后续可以优化样式、添加更多画笔效果,加入拖拽功能、画矩形圆形等功能~