改进画布绘制调用性能



我想画很多点。我就是这么做的:

let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
function render () {
window.requestAnimationFrame(render);
// clear screen
ctx.clearRect(0, 0, cwidth, cheight);
for (let p of particles) {
p.rmove();
p.render(ctx);
}
}
render();

我的观点的绘图函数如下:

class Point {
x: number;
y: number;
constructor(x, y) {
this.x = x;
this.y = y;
}
rmove() {
this.x += Math.round(Math.random() < 0.5 ? -1 : 1);
this.y += Math.round(Math.random() < 0.5 ? -1 : 1);
}
render (ctx) {
ctx.fillStyle = "gray";
ctx.beginPath();
ctx.rect(this.x, this.y, 1.5,1.5);
ctx.fill();
ctx.stroke();
}
}

请注意,我对rmove()函数中的值进行了四舍五入,因为画布可以更快地绘制具有整数坐标的点。

我想以某种方式把所有这些绘图调用放在一起。

在给定上下文(甚至可以是Path2D(上创建点trace,并保留渲染器的实际图形。

您所要做的就是在跟踪rect之前使上下文moveTo成为它们自己的坐标。

class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
rmove() {
this.x += Math.round(Math.random() < 0.5 ? -1 : 1);
this.y += Math.round(Math.random() < 0.5 ? -1 : 1);
}
trace (ctx) {
ctx.moveTo( this.x, this.y );
ctx.rect(this.x, this.y, 1.5, 1.5);
}
}
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const cwidth = canvas.width = 300;
const cheight = canvas.height = 300;
const particles = Array.from(
{ length: 5000 },
()=> new Point( cwidth/2, cheight/2 )
);
function animate () {
update();
draw();
window.requestAnimationFrame(animate);
}
function update() {
for (let p of particles) {
p.rmove();
}
}
function draw() {
// clear screen
ctx.clearRect(0, 0, cwidth, cheight);
// define our single path
ctx.beginPath();
for (let p of particles) {
p.trace(ctx);
}
ctx.fillStyle = "gray";
ctx.stroke(); // OP has it reversed, but then the fill-color is almost not visible
// (1.5 width - 2*0.5 stroke leaves only 0.5 for the fill => antialiased...
ctx.fill();
}
window.requestAnimationFrame( animate );
<canvas id="canvas"></canvas>

但这只是因为所有粒子共享相同的颜色。如果他们没有,那么你需要更多的逻辑:

const colors = ['red', 'green', 'blue', 'cyan', 'magenta', 'yellow'];
class Point {
constructor(x, y, color=0) {
this.x = x;
this.y = y;
this.color = color;
}
rmove() {
this.x += Math.round(Math.random() < 0.5 ? -1 : 1);
this.y += Math.round(Math.random() < 0.5 ? -1 : 1);
}
trace (ctx) {
ctx.moveTo( this.x, this.y );
ctx.rect(this.x, this.y, 1.5, 1.5);
}
}
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const cwidth = canvas.width = 300;
const cheight = canvas.height = 300;
const particles = Array.from(
{ length: 5000 },
()=> new Point( cwidth/2, cheight/2, (Math.random()*colors.length-1)|0 )
);
function animate () {
update();
draw();
window.requestAnimationFrame(animate);
}
function update() {
for (let p of particles) {
p.rmove();
}
}
function draw() {
// clear screen
ctx.clearRect(0, 0, cwidth, cheight);
// define our single path
let last_color = -1;
for (let p of particles) {
let p_color = p.color;
if( p_color !== last_color ) {
paint();
last_color = p_color;
}
p.trace(ctx);
}
paint(); // the last

function paint() {
ctx.fillStyle = colors[ last_color ];
ctx.strokeStyle = colors[ (last_color + 1) % colors .length ];
ctx.stroke();
ctx.fill();
ctx.beginPath();
}
}
window.requestAnimationFrame( animate );
<canvas id="canvas"></canvas>

尽管这样做,你很可能会画出很多画,所以最后一个可能不适用于所有地方的技巧是根据粒子的颜色对它们进行排序。这会导致不同的图形,因为这一种颜色总是在顶部,但在某些情况下可能会起作用,性能的提高可能会弥补缺点。

const colors = ['red', 'green', 'blue', 'cyan', 'magenta', 'yellow'];
class Point {
constructor(x, y, color=0) {
this.x = x;
this.y = y;
this.color = color;
}
rmove() {
this.x += Math.round(Math.random() < 0.5 ? -1 : 1);
this.y += Math.round(Math.random() < 0.5 ? -1 : 1);
}
trace (ctx) {
ctx.moveTo( this.x, this.y );
ctx.rect(this.x, this.y, 1.5, 1.5);
}
}
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const cwidth = canvas.width = 300;
const cheight = canvas.height = 300;
const particles = Array.from(
{ length: 5000 },
()=> new Point( cwidth/2, cheight/2, (Math.random()*colors.length-1)|0 )
);
particles.sort( (a, b) => a.color - b.color );
function animate () {
update();
draw();
window.requestAnimationFrame(animate);
}
function update() {
for (let p of particles) {
p.rmove();
}
}
function draw() {
// clear screen
ctx.clearRect(0, 0, cwidth, cheight);
// define our single path
let last_color = -1;
for (let p of particles) {
let p_color = p.color;
if( p_color !== last_color ) {
paint();
last_color = p_color;
}
p.trace(ctx);
}
paint(); // the last

function paint() {
ctx.fillStyle = colors[ last_color ];
ctx.strokeStyle = colors[ (last_color + 1) % colors .length ];
ctx.stroke();
ctx.fill();
ctx.beginPath();
}
}
window.requestAnimationFrame( animate );
<canvas id="canvas"></canvas>

没有什么可以阻止你从这些排序的粒子中生成块,这样它看起来更随机。

最新更新