简体   繁体   中英

How to resize Canvas Width on Viewport

I have a canvas demo that spawns some circles. I can't seem to figure out how to have it be responsive in setting either canvas.width or canvas.style.width (what's the difference here?) on a windows resize using window.innerWidth .

Code works fine but it rerenders strangely on smaller viewports. I tried adding this snippet of code at the bottom of my javascript file, but it broke animation.

  // ADDING THESE LINES PREVENTS ANIMATION FROM RUNNING
  if (window.innerWidth < 1000) {
    canvas.width = window.innerWidth;
   } else {
     canvas.width = 1000;
   }

在此处输入图片说明

 var canvas = document.querySelector("canvas"); canvas.width = 1000; canvas.height = 100; var c = canvas.getContext("2d"); // Constructor Function (object blueprint) function Circle(x, y, dx, dy, radius, counter) { this.x = x; this.y = y; this.dx = dx; this.dy = dy; this.radius = radius; this.counter = counter; this.draw = function() { c.beginPath(); c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); c.strokeStyle = "white"; c.stroke(); c.fillStyle = "white"; c.fill(); }; this.update = function() { if (this.y + this.radius > canvas.height) { this.y = 0; } this.x += this.dx; this.y += this.dy; this.draw(); }; } // Initialize array to store snow objects var circleArray = []; // Initialize objects with constructor for (var i = 0; i < 50; i++) { var radius = 1 + Math.random() * 5; var x = Math.random() * canvas.width; var y = 0 - Math.random() * 50; // start at top, render some circles off screen var dx = (Math.random() - 0.5) * 2; var dy = 0.5 + Math.random() * 0.5; // use gravity circleArray.push(new Circle(x, y, dx, dy, radius, 0)); } function animate() { requestAnimationFrame(animate); // recurisvely run c.clearRect(0, 0, innerWidth, innerHeight); // erases previously drawn content for (var i = 0; i < circleArray.length; i++) { circleArray[i].update(); } // ADDING THESE LINES PREVENTS ANIMATION FROM RUNNING //if (window.innerWidth < 1000) { // canvas.width = window.innerWidth; // } else { // canvas.width = 1000; // } } animate();
 body { background-color: grey; display: flex; justify-content: center; } .wrapper { position: relative; width: 1000px; height: 110px; min-height: 110px; margin-top: 50vh; } .wrapper > * { width: 1000px; position: absolute; } canvas { position: absolute; } img { width: 100%; height: 110px; }
 <div class="wrapper"> <img class="stars" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/867725/stars.png " alt="" /> <img class="tress" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/867725/trees.png " alt="" /> <img class="clouds" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/867725/clouds.png" alt="" /> <canvas></canvas> </div>

The difference between canvas.width and canvas.style.width is that canvas.width specifies the actual size of the canvas in pixels, while canvas.style.width stretches or compresses the canvas to the width you specify. This will set the canvas width to 300px:

canvas.width = 300;

This will also set the canvas width to 300px, but will stretch it until it reaches 600px:

canvas.width = 300;
canvas.style.width = "600px";

Using canvas.width is better practice.


For the animation to run you must first fix the canvas width. Putting the code that resizes the canvas at the beginning of the animate() function solves the problem:

 var canvas = document.querySelector("canvas"); canvas.width = 1000; canvas.height = 100; var c = canvas.getContext("2d"); // Constructor Function (object blueprint) function Circle(x, y, dx, dy, radius, counter) { this.x = x; this.y = y; this.dx = dx; this.dy = dy; this.radius = radius; this.counter = counter; this.draw = function() { c.beginPath(); c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); c.strokeStyle = "white"; c.stroke(); c.fillStyle = "white"; c.fill(); }; this.update = function() { if (this.y + this.radius > canvas.height) { this.y = 0; } this.x += this.dx; this.y += this.dy; this.draw(); }; } // Initialize array to store snow objects var circleArray = []; // Initialize objects with constructor for (var i = 0; i < 50; i++) { var radius = 1 + Math.random() * 5; var x = Math.random() * canvas.width; var y = 0 - Math.random() * 50; // start at top, render some circles off screen var dx = (Math.random() - 0.5) * 2; var dy = 0.5 + Math.random() * 0.5; // use gravity circleArray.push(new Circle(x, y, dx, dy, radius, 0)); } function animate() { if (window.innerWidth < 1000) { canvas.width = window.innerWidth; } else { canvas.width = 1000; } requestAnimationFrame(animate); // recurisvely run c.clearRect(0, 0, innerWidth, innerHeight); // erases previously drawn content for (var i = 0; i < circleArray.length; i++) { circleArray[i].update(); } } animate();
 body { background-color: grey; display: flex; justify-content: center; } .wrapper { position: relative; width: 1000px; height: 110px; min-height: 110px; margin-top: 50vh; } .wrapper>* { width: 1000px; position: absolute; } canvas { position: absolute; } img { width: 100%; height: 110px; }
 <div class="wrapper"> <img class="stars" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/867725/stars.png " alt="" /> <img class="tress" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/867725/trees.png " alt="" /> <img class="clouds" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/867725/clouds.png" alt="" /> <canvas></canvas> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM