如何调整 canvas 中包含我的元素的大小?
How do I resize my canvas with my elements in it?
背景信息
我目前正在做一个项目,我希望背景是空白的 canvas,球从墙上弹跳。
到目前为止我已经成功了,但是我遇到了一个问题。
每当我调整浏览器 window 大小时,我的 canvas 或其中的球都不会跟进。我不知道我做错了什么。
代码
const canvas = document.querySelector('#responsive-canvas')
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let c = canvas.getContext('2d');
function Circle(x, y, dx, dy, radius, colour) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
this.colour = colour;
this.draw = function() {
this.getNewColour = function() {
let symbols, colour;
symbols = "0123456789ABCDEF";
colour = "#";
for (let i = 0; i < 6; i++) {
colour += symbols[Math.floor(Math.random() * 16)];
}
c.strokeStyle = colour;
c.fillStyle = colour;
}
this.getNewColour();
this.x = x;
this.y = y;
this.radius = radius;
//this.getNewColour().colour = colour;
c.beginPath();
c.arc(x, y, radius, 0, Math.PI * 2, false);
// c.strokeStyle = 'blue';
c.stroke();
//c.fill();
}
this.update = function() {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
if (x + radius > innerWidth || x - radius < 0) {
dx = -dx;
}
if (y + radius > innerHeight || y - radius < 0) {
dy = -dy;
}
x += dx;
y += dy;
this.draw();
}
}
let circleArr = [];
for (let i = 0; i < 23; i++) {
let radius = 50;
let x = Math.random() * (innerWidth - radius * 2) + radius;
let y = Math.random() * (innerHeight - radius * 2) + radius;
let dx = (Math.random() - 0.5);
let dy = (Math.random() - 0.5);
circleArr.push(new Circle(x, y, dx, dy, radius));
};
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, innerWidth, innerHeight)
for (var i = 0; i < circleArr.length; i++) {
circleArr[i].update();
}
};
animate();
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* BODY
*/
html,
body {
width: 100%;
height: 100%;
margin: 0;
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<meta name="description" content="">
<link rel="stylesheet" href="../dist/css/style.css">
<body>
<canvas id="responsive-canvas"></canvas>
</body>
<script src="js/canvas.js"></script>
</html>
你可以使用
ctx.scale(x,y);
要按给定因子缩放 canvas 上的所有内容,X 和 Y 分别在 X 轴和 Y 轴上缩放。
您可能希望使用 canvas 重置
ctx.resetTransform()
或 ctx.setTransform(1,0,0,1,0,0);
然后将背景从 0,0 绘制到 canvas.width 和 canvas.height
然后绘制所有内容(所有圆圈),最后将缩放设置为您想要的值。
如果你想改变宽度和高度,你只需要在与`{border-box}相同的CSS区域添加宽度和高度。
但是如果你想让里面的图片不被拉伸,你需要使用上面的注释方法在canvas中专门访问heigh。
最好使用:
width:() => document.documentElement.clientWidth
首先你必须修复你的碰撞逻辑,然后你可以根据需要安全地更改 canvas 大小。
始终完全解决冲突。
未解决的碰撞意味着您的 sim 处于不可能的状态(例如墙内的球)。从那时起,以下状态的意义将减少。
修复
球移出 canvas 的原因是,如果它们在外面,您不会将它们移回 canvas。
此外,当您在球击中侧面时改变球的方向时,您无法确保方向是正确的符号。
// if the dx = 1 and x > innerWidth + 1000 then dx becomes -1
// Next tine x is still > innerWidth + 1000 and you flip the sign of dx again to 1,
// Then dx to -1 and so on. You never move the ball
if(x + radius > innerWidth || x - radius < 0) {
dx = -dx;
}
系统地进行碰撞测试,这样当运动场 (canvas) 改变大小时,您就不会得到意想不到的结果
更新时,先移动再检查碰撞。如果发生碰撞,请再次移动球以确保不会发生魔法球在墙上的事情。
update() {
this.x += this.dx;
this.y += this.dy;
if (this.x < this.radius) {
this.x = this.radius;
this.dx = Math.abs(this.dx);
}
if (this.y < this.radius) {
this.y = this.radius;
this.dy = Math.abs(this.dy);
}
if (this.x > ctx.canvas.width - this.radius) {
this.x = ctx.canvas.width - this.radius;
this.dx = -Math.abs(this.dx);
}
if (this.y > ctx.canvas.height - this.radius) {
this.y = ctx.canvas.height - this.radius;
this.dy = -Math.abs(this.dy);
}
}
调整大小 canvas
随着碰撞问题的解决,您现在可以随时更改 canvas 大小。一种方法是在 animate 函数中进行。
如果 canvas 大小与页面大小不匹配,请更改 canvas 大小以匹配。
function animate () {
if (ctx.canvas.width !== innerWidth || ctx.canvas.height !== innerHeight) {
ctx.canvas.width = innerWidth;
ctx.canvas.height = innerHeight;
} else {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
}
// ... do stuff
requestAnimationFrame(animate);
}
注意 更改 canvas 大小也会清除 canvas,这就是清除 else
子句的原因。
复制粘贴演示
代码中有很多不好的地方。您可以将下面的代码片段复制粘贴到代码笔中,或者使用上面的信息按照您的风格修改代码。
const canvas = document.querySelector('#responsive-canvas')
canvas.width = innerWidth;
canvas.height = innerHeight;
// Set constants in one place so you can make changes quickly and easily
const DEFAULT_RADIUS = 50;
const MAX_SPEED = 5;
const CIRCLE_COUNT = 100;
Math.TAU = Math.PI * 2
// Use function to do repetitive code
Math.rand = (min, max) => Math.random() * (max - min) + min; //
function randomHexColor() {
return "#" + ((Math.random() * 0xFFFFFF | 0).toString(16).padStart(6,"0"));
}
// pulral names for arrays and variables that do not change should be constants
const circles = [];
const ctx = canvas.getContext('2d');
requestAnimationFrame(animate); // start frame renderer with a request, dont call it directly
function Circle( // using default params to set random values
radius = Math.rand(DEFAULT_RADIUS/4, DEFAULT_RADIUS), // radius must be first argument as its used to set random x, and y
x = Math.rand(radius, ctx.canvas.width - radius),
y = Math.rand(radius, ctx.canvas.height - radius),
dx = Math.rand(-MAX_SPEED, MAX_SPEED),
dy = Math.rand(-MAX_SPEED, MAX_SPEED),
colour = randomHexColor()
) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
this.colour = colour;
}
// Define Circle functions as prototype outside the function Circle (runs faster)
Circle.prototype = {
draw() {
ctx.strokeStyle = ctx.fillStyle = this.colour;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.TAU);
ctx.stroke();
},
update() {
this.x += this.dx;
this.y += this.dy;
if (this.x < this.radius) {
this.x = this.radius;
this.dx = Math.abs(this.dx);
}
if (this.y < this.radius) {
this.y = this.radius;
this.dy = Math.abs(this.dy);
}
if (this.x > ctx.canvas.width - this.radius) {
this.x = ctx.canvas.width - this.radius;
this.dx = -Math.abs(this.dx);
}
if (this.y > ctx.canvas.height - this.radius) {
this.y = ctx.canvas.height - this.radius;
this.dy = -Math.abs(this.dy);
}
}
};
for (let i = 0; i < CIRCLE_COUNT; i++) { circles.push(new Circle()) }
function animate () {
if (ctx.canvas.width !== innerWidth || ctx.canvas.height !== innerHeight) {
ctx.canvas.width = innerWidth;
ctx.canvas.height = innerHeight;
} else {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
}
// use for of loop (saves having to mess with index)
for (const circle of circles) {
circle.update(); // seperate update and draw
circle.draw()
}
requestAnimationFrame(animate);
}
背景信息
我目前正在做一个项目,我希望背景是空白的 canvas,球从墙上弹跳。
到目前为止我已经成功了,但是我遇到了一个问题。 每当我调整浏览器 window 大小时,我的 canvas 或其中的球都不会跟进。我不知道我做错了什么。
代码
const canvas = document.querySelector('#responsive-canvas')
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let c = canvas.getContext('2d');
function Circle(x, y, dx, dy, radius, colour) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
this.colour = colour;
this.draw = function() {
this.getNewColour = function() {
let symbols, colour;
symbols = "0123456789ABCDEF";
colour = "#";
for (let i = 0; i < 6; i++) {
colour += symbols[Math.floor(Math.random() * 16)];
}
c.strokeStyle = colour;
c.fillStyle = colour;
}
this.getNewColour();
this.x = x;
this.y = y;
this.radius = radius;
//this.getNewColour().colour = colour;
c.beginPath();
c.arc(x, y, radius, 0, Math.PI * 2, false);
// c.strokeStyle = 'blue';
c.stroke();
//c.fill();
}
this.update = function() {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
if (x + radius > innerWidth || x - radius < 0) {
dx = -dx;
}
if (y + radius > innerHeight || y - radius < 0) {
dy = -dy;
}
x += dx;
y += dy;
this.draw();
}
}
let circleArr = [];
for (let i = 0; i < 23; i++) {
let radius = 50;
let x = Math.random() * (innerWidth - radius * 2) + radius;
let y = Math.random() * (innerHeight - radius * 2) + radius;
let dx = (Math.random() - 0.5);
let dy = (Math.random() - 0.5);
circleArr.push(new Circle(x, y, dx, dy, radius));
};
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, innerWidth, innerHeight)
for (var i = 0; i < circleArr.length; i++) {
circleArr[i].update();
}
};
animate();
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* BODY
*/
html,
body {
width: 100%;
height: 100%;
margin: 0;
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<meta name="description" content="">
<link rel="stylesheet" href="../dist/css/style.css">
<body>
<canvas id="responsive-canvas"></canvas>
</body>
<script src="js/canvas.js"></script>
</html>
你可以使用
ctx.scale(x,y);
要按给定因子缩放 canvas 上的所有内容,X 和 Y 分别在 X 轴和 Y 轴上缩放。
您可能希望使用 canvas 重置
ctx.resetTransform()
或 ctx.setTransform(1,0,0,1,0,0);
然后将背景从 0,0 绘制到 canvas.width 和 canvas.height
然后绘制所有内容(所有圆圈),最后将缩放设置为您想要的值。
如果你想改变宽度和高度,你只需要在与`{border-box}相同的CSS区域添加宽度和高度。
但是如果你想让里面的图片不被拉伸,你需要使用上面的注释方法在canvas中专门访问heigh。
最好使用:
width:() => document.documentElement.clientWidth
首先你必须修复你的碰撞逻辑,然后你可以根据需要安全地更改 canvas 大小。
始终完全解决冲突。
未解决的碰撞意味着您的 sim 处于不可能的状态(例如墙内的球)。从那时起,以下状态的意义将减少。
修复
球移出 canvas 的原因是,如果它们在外面,您不会将它们移回 canvas。
此外,当您在球击中侧面时改变球的方向时,您无法确保方向是正确的符号。
// if the dx = 1 and x > innerWidth + 1000 then dx becomes -1
// Next tine x is still > innerWidth + 1000 and you flip the sign of dx again to 1,
// Then dx to -1 and so on. You never move the ball
if(x + radius > innerWidth || x - radius < 0) {
dx = -dx;
}
系统地进行碰撞测试,这样当运动场 (canvas) 改变大小时,您就不会得到意想不到的结果
更新时,先移动再检查碰撞。如果发生碰撞,请再次移动球以确保不会发生魔法球在墙上的事情。
update() {
this.x += this.dx;
this.y += this.dy;
if (this.x < this.radius) {
this.x = this.radius;
this.dx = Math.abs(this.dx);
}
if (this.y < this.radius) {
this.y = this.radius;
this.dy = Math.abs(this.dy);
}
if (this.x > ctx.canvas.width - this.radius) {
this.x = ctx.canvas.width - this.radius;
this.dx = -Math.abs(this.dx);
}
if (this.y > ctx.canvas.height - this.radius) {
this.y = ctx.canvas.height - this.radius;
this.dy = -Math.abs(this.dy);
}
}
调整大小 canvas
随着碰撞问题的解决,您现在可以随时更改 canvas 大小。一种方法是在 animate 函数中进行。
如果 canvas 大小与页面大小不匹配,请更改 canvas 大小以匹配。
function animate () {
if (ctx.canvas.width !== innerWidth || ctx.canvas.height !== innerHeight) {
ctx.canvas.width = innerWidth;
ctx.canvas.height = innerHeight;
} else {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
}
// ... do stuff
requestAnimationFrame(animate);
}
注意 更改 canvas 大小也会清除 canvas,这就是清除 else
子句的原因。
复制粘贴演示
代码中有很多不好的地方。您可以将下面的代码片段复制粘贴到代码笔中,或者使用上面的信息按照您的风格修改代码。
const canvas = document.querySelector('#responsive-canvas')
canvas.width = innerWidth;
canvas.height = innerHeight;
// Set constants in one place so you can make changes quickly and easily
const DEFAULT_RADIUS = 50;
const MAX_SPEED = 5;
const CIRCLE_COUNT = 100;
Math.TAU = Math.PI * 2
// Use function to do repetitive code
Math.rand = (min, max) => Math.random() * (max - min) + min; //
function randomHexColor() {
return "#" + ((Math.random() * 0xFFFFFF | 0).toString(16).padStart(6,"0"));
}
// pulral names for arrays and variables that do not change should be constants
const circles = [];
const ctx = canvas.getContext('2d');
requestAnimationFrame(animate); // start frame renderer with a request, dont call it directly
function Circle( // using default params to set random values
radius = Math.rand(DEFAULT_RADIUS/4, DEFAULT_RADIUS), // radius must be first argument as its used to set random x, and y
x = Math.rand(radius, ctx.canvas.width - radius),
y = Math.rand(radius, ctx.canvas.height - radius),
dx = Math.rand(-MAX_SPEED, MAX_SPEED),
dy = Math.rand(-MAX_SPEED, MAX_SPEED),
colour = randomHexColor()
) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
this.colour = colour;
}
// Define Circle functions as prototype outside the function Circle (runs faster)
Circle.prototype = {
draw() {
ctx.strokeStyle = ctx.fillStyle = this.colour;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.TAU);
ctx.stroke();
},
update() {
this.x += this.dx;
this.y += this.dy;
if (this.x < this.radius) {
this.x = this.radius;
this.dx = Math.abs(this.dx);
}
if (this.y < this.radius) {
this.y = this.radius;
this.dy = Math.abs(this.dy);
}
if (this.x > ctx.canvas.width - this.radius) {
this.x = ctx.canvas.width - this.radius;
this.dx = -Math.abs(this.dx);
}
if (this.y > ctx.canvas.height - this.radius) {
this.y = ctx.canvas.height - this.radius;
this.dy = -Math.abs(this.dy);
}
}
};
for (let i = 0; i < CIRCLE_COUNT; i++) { circles.push(new Circle()) }
function animate () {
if (ctx.canvas.width !== innerWidth || ctx.canvas.height !== innerHeight) {
ctx.canvas.width = innerWidth;
ctx.canvas.height = innerHeight;
} else {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
}
// use for of loop (saves having to mess with index)
for (const circle of circles) {
circle.update(); // seperate update and draw
circle.draw()
}
requestAnimationFrame(animate);
}