Улучшение производительности холста при рисовании - PullRequest
1 голос
/ 02 апреля 2020

Я хочу нарисовать немало точек. Вот что я делаю:

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() как canvas dr aws точек с целочисленными координатами быстрее.

Я бы хотел как-то соединить все эти вызовы рисования.

1 Ответ

1 голос
/ 03 апреля 2020

Сделайте ваши очки trace в данном контексте (может быть даже Path2D) и сохраните фактический чертеж для средства визуализации.

Все, что вам нужно сделать, это создать контекст moveTo их собственные координаты до трассировки rect.

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>

Но это работает только потому, что все ваши частицы имеют одинаковый цвет. Если этого не произойдет, вам понадобится немного больше логики c:

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>

Хотя, делая это, вы вполне можете получить множество рисунков, поэтому последний трюк, который может не сработать везде, - отсортировать частицы по их цвет. Это приводит к другому графику c, так как этот один цвет всегда будет наверху, но он может работать в некоторых случаях, и выигрыш в производительности может соответствовать недостаткам.

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>

И ничто не мешает вам генерировать куски из этих отсортированных частиц, поэтому это выглядит более случайным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...