如何调整包含元素的画布的尺寸?

时间:2020-02-06 20:04:55

标签: javascript html css canvas resize

背景信息

我目前正在一个项目上,我希望背景是一块空白的画布,球从墙上弹起。

到目前为止,我已经做到了,但是遇到了一个问题。 每当我调整浏览器窗口的大小时,画布或其中的球都不会通过。我不知道我在做什么错。

codepen

代码

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>

3 个答案:

答案 0 :(得分:2)

您可以使用 <!--I want to take data that looks like this--> <Foo xmlns:e="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo"> <e:Description></e:Description> <e:Name i:nil="true"></e:Name> <e:DisplaySeqNo>0</e:DisplaySeqNo> </Foo> <!--I want to make that data that looks like this--> <Foo> <Description xmlns="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo"></Description> <Name i:nil="true" xmlns="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo"></Name> <DisplaySeqNo xmlns="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo">0</DisplaySeqNo> </Foo> 按给定的比例缩放画布上的所有内容,X和Y分别在X和Y轴上缩放。

您可能想使用以下方法重置画布 ctx.scale(x,y);ctx.resetTransform() 然后从0,0绘制背景到canvas.width和canvas.height 然后绘制所有内容(所有圆圈),最后将缩放比例设置为所需的值。

答案 1 :(得分:1)

如果要更改宽度和高度,只需在{border-box}所在的CSS区域中添加宽度和高度。

但是,如果要使其中的图像不被拉伸,则需要使用上述注释方法专门访问画布中的高度。

最好使用:

width:() => document.documentElement.clientWidth

答案 2 :(得分:0)

首先,您必须修复冲突逻辑,然后可以根据需要安全地更改画布大小。

始终完全解决冲突。

未解决的碰撞意味着您的SIM卡处于不可能的状态(例如,墙内的球)。从那时起,以下状态将不再有意义。

修复

球移出画布的原因是,如果球不在外面,则不要将其移回画布。

此外,当您改变击球方向时的方向时,也不能确保方向是正确的符号。

    // 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;  
    } 

在碰撞测试中保持系统性,以便在运动场(画布)改变大小时不会出现意外结果

更新时,请先移动然后检查是否有碰撞。如果发生碰撞,请再次移动球以确保墙体中没有魔术球发生。

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);
    }
}

调整画布大小

解决了碰撞问题后,您现在可以随时更改画布大小。一种方法是在动画函数中进行。

如果画布大小与页面大小不匹配,请更改画布大小以使其匹配。

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);
} 

请注意,更改画布的大小也会清除画布,这就是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);
}