JS:调整大小 canvas + 在 canvas 上重绘元素

JS: Resizing canvas + redrawing elements on canvas

我的问题:调整 canvas 及其所有绘制元素的最佳方法是什么?

我有 2 个例子,我试图实现这个。

第一个有效,但缺乏功能,因为如果我要添加更多要绘制的元素,它会变得非常混乱。在我的第二个示例中,我尝试将所有内容放入一个数组并循环遍历它,但它不再正确调整大小,因为它不再重新计算 x、y 宽度和高度。基本上我想知道一种方法,在绘制之前不必再次调用计算元素 x、y、宽度和高度的函数。我想把数学放到数组中,当它被绘制时, 它会重新计算,所以我只需要确保 canvas.width/height 已更新,我该怎么做?

第一个例子

class Canvas {
 constructor() {
  this.canvas = document.createElement('canvas');
  this.canvas.width = window.innerWidth;
  this.canvas.height = window.innerHeight;
  this.ctx = this.canvas.getContext('2d');
  document.body.appendChild(this.canvas);
  this.resize();
 }
 
 initAreas() {
  this.firstArea = { "x": 0, "y": 0, "w": this.canvas.width, "h": this.canvas.height / 2 }
  this.secondArea = { "x": 0, "y": this.firstArea.h, "w": this.canvas.width, "h": this.canvas.height / 2 }
 }
 
 resize() {
  this.canvas.width = window.innerWidth;
  this.canvas.height = window.innerHeight;
  this.initAreas();
  this.ctx.fillStyle = "green";
  this.ctx.fillRect(this.firstArea.x, this.firstArea.y, this.firstArea.w, this.firstArea.h);
  this.ctx.fillStyle = "red";
  this.ctx.fillRect(this.secondArea.x, this.secondArea.y, this.secondArea.w, this.secondArea.h);
 }

}

const canvas = new Canvas();

window.onresize = function() { canvas.resize(); }
body {
 padding: 0;
 margin: 0;
}

canvas {
 display: block;
}
<!DOCTYPE html>

<html>
<head>
 <meta charset="UTF-8">
 <link rel="stylesheet" href="style.css">
</head>
<body>
 <script src="script.js"></script>
</body>
</html>

第二个例子

class Canvas {
constructor() {
    this.canvas = document.createElement('canvas');
    this.canvas.width = window.innerWidth;
    this.canvas.height = window.innerHeight;
    this.ctx = this.canvas.getContext('2d');
    document.body.appendChild(this.canvas);
    this.areasToDraw = [];
    this.initAreas();
    this.resize();
}

initAreas() {
    this.firstArea = { "x": 0, "y": 0, "w": this.canvas.width, "h": this.canvas.height / 2, "color": "green" }
    this.areasToDraw.push(this.firstArea);
    this.secondArea = { "x": 0, "y": this.firstArea.h, "w": this.canvas.width, "h": this.canvas.height / 2, "color": "red" }
    this.areasToDraw.push(this.secondArea);
}

resize() {
    this.canvas.width = window.innerWidth;
    this.canvas.height = window.innerHeight;
    for(this.areas in this.areasToDraw) {
        this.ctx.fillStyle = this.areasToDraw[this.areas].color;
        this.ctx.fillRect(this.areasToDraw[this.areas].x, this.areasToDraw[this.areas].y, this.areasToDraw[this.areas].w, this.areasToDraw[this.areas].h);
    }
}

观察 1:“由于调整大小事件可以高速触发,因此事件处理程序不应执行计算量大的操作,例如 DOM 修改。相反,建议使用 requestAnimationFrame、setTimeout 或 customEvent 来限制事件” 这是来自MDN resize

观察 2:在调整大小时你需要绑定 canvas,否则你会得到 canvas 未定义。

观察3:当你调整canvas的大小时,你需要清空元素数组:this.areasToDraw在这种情况下,并重新填充数组有新元素。

我会这样做:

class Canvas {
constructor() {
    this.canvas = document.createElement('canvas');
    this.canvas.width = window.innerWidth;
    this.canvas.height = window.innerHeight;
    this.ctx = this.canvas.getContext('2d');
    document.body.appendChild(this.canvas);
    this.areasToDraw = [];
    //this.initAreas();
    //this.resize();
   
}

initAreas() {
    this.firstArea = { "x": 0, "y": 0, "w": this.canvas.width, "h": this.canvas.height / 2, "color": "green" }
    this.areasToDraw.push(this.firstArea);
    this.secondArea = { "x": 0, "y": this.firstArea.h, "w": this.canvas.width, "h": this.canvas.height / 2, "color": "red" }
    this.areasToDraw.push(this.secondArea);
}

resize() {
    this.canvas.width = window.innerWidth;
    this.canvas.height = window.innerHeight;
    // empty the array
    this.areasToDraw.length = 0;
    // repopulate the array
    this.initAreas();
    for(this.areas in this.areasToDraw) {
        this.ctx.fillStyle = this.areasToDraw[this.areas].color;
        this.ctx.fillRect(this.areasToDraw[this.areas].x, this.areasToDraw[this.areas].y, this.areasToDraw[this.areas].w, this.areasToDraw[this.areas].h);
    }
}

}

let canvas = new Canvas()

setTimeout(function() {
  canvas.resize()
  addEventListener('resize', canvas.resize.bind(canvas), false);
}, 15);
body {
 padding: 0;
 margin: 0;
}

canvas {
 display: block;
}