canvas像素画板的实现代码

2020-04-20 17:11:47易采站长站整理

最近项目上要实现一个类似像素风格的画板,可以像素小格子可以擦除,框选变色,可以擦出各种图形,这样一个小项目看似简单,包含的东西还真不少。

绘制像素格子

我们先定义像素格子类


Pixel = function (option) {
this.x = option.x;
this.y = option.y;
this.shape = option.shape;
this.size = option.size || 8;
}

x和y表示中心点坐标,一开始我是这么做的,先定义路径


createPath: function (ctx) {
if (this.shape === 'circle') {
this.createCircle(ctx);
} else if (this.shape === 'rect') {
this.createRect(ctx);
} else {
this.createCircle(ctx);
}
},

createCircle: function (ctx) {
var radius = this.size / 2;
ctx.arc(this.x,this.y,radius,0,Math.PI*2);
},

createRect: function (ctx) {
var points = this.getPoints();
points.forEach(function (point, i) {
ctx[i == 0 ? 'moveTo' : 'lineTo'](point.x, point.y);
})
ctx.lineTo(points[0].x, points[0].y);
},

像素网格支持圆形和矩形,路径定义好后,然后进行绘制


draw: function (ctx) {
ctx.save();
ctx.lineWidth=this.lineWidth;
ctx.strokeStyle=this.strokeStyle;
ctx.fillStyle=this.fillStyle;
ctx.beginPath();
this.createPath(ctx);
ctx.stroke();
if(this.isFill){ctx.fill();}
ctx.restore();
}

然后通过循环批量创建像素网格:


for (var i = stepX + .5; i < canvas.width; i+=stepX) {
for (var j = stepY + .5; j < canvas.height; j+=stepY) {
var pixel = new Pixel({
x: i,
y: j,
shape: 'circle'
})
box.push(pixel);
pixel.draw(ctx);
}
}

这样做看似完美,然而有一个巨大毙命,每画一个像素都回绘制到上下文中,每一次都在改变canvas的状态,这样做会导致渲染性能太差,因为像素点很多,如果画布比较大,性能很是令人堪忧,并且画板上面还有一些操作,如此频繁改变canvas的状态是不合适的。

因此,正确的做法是:我们应该定义好所有的路径,最好在一次性的批量绘制到canvas中; 


//定义像素的位置
for (var i = stepX + .5; i < canvas.width; i+=stepX) {
for (var j = stepY + .5; j < canvas.height; j+=stepY) {
var pixel = new Pixel({
x: i,
y: j,
shape: 'circle'
})
box.push(pixel);
}
}

//批量绘制
console.time('time');
ctx.beginPath();
for (var c = 0; c < box.length; c++) {
var circle = box[c];