Javascript渲染到HTML画布的速度非常慢

时间:2018-07-30 06:09:45

标签: javascript html html5-canvas

我正在尝试通过渲染单个正方形来将网格渲染到HTML画布(因为稍后在单元格上看起来不应该全部相同,而是具有各自的行为)。

我创建了一个最小的示例,该示例显示了我遇到的性能问题。运行该脚本几乎会冻结我的浏览器,直到它为我停止脚本为止,因为它检测到该脚本运行太慢。

我有一个运行Javascript框架p5.js的类似示例,并且在性能方面运行良好。 但是,我想在没有该框架的情况下转向基本Javascript。

这是引起性能问题的最小示例。我很高兴看到为什么它运行这么慢的任何建议...

const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;

let grid_width = 50;
let grid_height = grid_width;
let grid = [];

class Cell {
  constructor(i,j) {
    this.i = i;
    this.j = j;
    this.width = width / grid_width;
    this.height = height / grid_height;
    this.x = i*this.width;
    this.y = j*this.height;
  }

  render(color) {
    context.rect(this.x, this.y, this.width, this.height);
    context.strokeStyle = '#000000';
    context.lineWidth = .25;
    if(color) {
      context.fillStyle = color;
    }
    context.fillStyle = '#FFFFFF';
    context.fill();
    context.stroke();
  }
}

for(let i = 0; i <= grid_width; i++) {
  if(!(grid[i])) {
    grid[i] = [];
  }
  for(let j = 0; j <= grid_height; j++) {
    grid[i][j] = new Cell(i, j);
  }
}

function draw() {
  context.clearRect(0, 0, width, height);
  grid.forEach(row => {
    row.forEach(cell => {
      cell.render();
    });
  });
  requestAnimationFrame(draw);
}

// This call to draw will run very slowly!
// draw();
<!DOCTYPE html>
<html>
  <head>
    <!-- <script src="p5.js"></script> -->
  </head>
  <body>
    <canvas id="canvas" width="800" height="800"></canvas><br>
    <script src="sketch.js"></script>
  </body>
</html>

请注意,我已注释掉对draw()的调用,因为我的脚本还破坏了该站点上的“运行代码段”按钮...

2 个答案:

答案 0 :(得分:0)

注释了requestAnimationFrame(row)函数调用。因为不存在这样的功能。现在,代码对我来说工作顺利。

const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;

let grid_width = 50;
let grid_height = grid_width;
let grid = [];

class Cell {
  constructor(i,j) {
    this.i = i;
    this.j = j;
    this.width = width / grid_width;
    this.height = height / grid_height;
    this.x = i*this.width;
    this.y = j*this.height;
  }

  render(color) {
    context.rect(this.x, this.y, this.width, this.height);
    context.strokeStyle = '#000000';
    context.lineWidth = .25;
    if(color) {
      context.fillStyle = color;
    }
    context.fillStyle = '#FFFFFF';
    context.fill();
    context.stroke();
  }
}

for(let i = 0; i <= grid_width; i++) {
  if(!(grid[i])) {
    grid[i] = [];
  }
  for(let j = 0; j <= grid_height; j++) {
    grid[i][j] = new Cell(i, j);
  }
}

function draw() {
  context.clearRect(0, 0, width, height);
  grid.forEach(row => {
    row.forEach(cell => {
      cell.render();
    });
  });
  //requestAnimationFrame(draw);
}

// This call to draw will run very slowly!
 draw();
<!DOCTYPE html>
<html>
  <head>
    <!-- <script src="p5.js"></script> -->
  </head>
  <body>
    <canvas id="canvas" width="800" height="800"></canvas><br>
    <script src="sketch.js"></script>
  </body>
</html>

答案 1 :(得分:0)

类似这样的事情。

简要说明。rect是画布path command。因此,fillstroke用最新的beginPath()endPath重绘了fillStylestrokeStyle之间的所有路径。在这种情况下,循环首先仅绘制第一个矩形,然后再绘制第一个和第二个,依此类推。 是的,在方法中固定了if语句后,您的颜色将始终应用于所有单元格。

所以我在这里使用了一些不同的代码。第一。我用立即应用的rectstrokeRect替换了fillRect。第二。我删除了您的if条件。

const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;

let grid_width = 50;
let grid_height = grid_width;
let grid = [];

class Cell {
  constructor(i,j) {
    this.i = i;
    this.j = j;
    this.width = width / grid_width;
    this.height = height / grid_height;
    this.x = i*this.width;
    this.y = j*this.height;
  }

  render(color) {
    context.strokeStyle = '#000000';
    context.lineWidth = .25;
    context.fillStyle = color || '#FFFFFF';
    context.strokeRect(this.x, this.y, this.width, this.height);
    context.fillRect(this.x, this.y, this.width, this.height);
  }
}

for(let i = 0; i <= grid_width; i++) {
  if(!(grid[i])) {
    grid[i] = [];
  }
  for(let j = 0; j <= grid_height; j++) {
    grid[i][j] = new Cell(i, j);
  }
}

function draw() {
  context.clearRect(0, 0, width, height);
  grid.forEach(row => {
    row.forEach(cell => {
      cell.render(Math.random()>0.5?"#FF00FF":undefined);
    });
  });
  //requestAnimationFrame(draw);
}

// This call to draw will run very slowly!
 draw();
<!DOCTYPE html>
<html>
  <head>
    <!-- <script src="p5.js"></script> -->
  </head>
  <body>
    <canvas id="canvas" width="800" height="800"></canvas><br>
    <script src="sketch.js"></script>
  </body>
</html>