HTML Canvas 调整大小后形状动画卡在 window 的末尾

HTML Canvas shape animation stuck at end of window after resize

我正在为 HTML Canvas 做一个有趣的介绍项目。基本概念是,在这种情况下,圆圈中的某些形状会四处移动并从侧面反弹。我想帮助解决的两个问题是:

  1. 调整浏览器大小后,圆圈可能会卡在屏幕末端的开放边(底部和右侧),它们的边界是宽度Canvas 和高度Canvas.理想情况下,我希望圆圈的行为方式与它们在以 0 为界的两侧(左侧和顶部)的行为方式相同。(请参阅 animate() 函数中的 if 语句)

  2. 如何去掉canvas周围因使用而留下的白色space:

    canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;

<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        html,
        body {
            overflow: hidden;
        }
    </style>
</head>

<body onresize="resizeCanvas()">
    <div>
        <canvas id="canvas"></canvas>
    </div>

    <script>

        const canvas = document.getElementById('canvas');
        /** @type {CanvasRenderingContext2D} */
        const ctx = canvas.getContext('2d');

        canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
        canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
        widthCanvas = canvas.width;
        heightCanvas = canvas.height;

        draw(40);

        function draw(num) {
            //number of cycles 
            num_cycles = num;

            // speed bounds 
            min_speed = 4;
            // real max_speed is + min_speed
            max_speed = 3;

            // create arrays for changing values 
            const arr_x = new Array(num_cycles);
            const arr_y = new Array(num_cycles);
            const arr_dx = new Array(num_cycles);
            const arr_dy = new Array(num_cycles);
            const arr_r = new Array(num_cycles);

            // populate arrays with random vaalues in range so circles 
            // have different velocities on y and x as well as vary in radii
            for (let index = 0; index < num_cycles; index++) {
                arr_x[index] = ((widthCanvas * 0.2) * Math.random()) + (widthCanvas * 0.4);
                arr_y[index] = ((heightCanvas * 0.2) * Math.random()) + (heightCanvas * 0.4);
                arr_dx[index] = (min_speed + Math.random() * max_speed) * (Math.round(Math.random()) ? -1 : 1);
                arr_dy[index] = (min_speed + Math.random() * max_speed) * (Math.round(Math.random()) ? 1 : -1);
                arr_r[index] = 50 + Math.random() * widthCanvas / 12;
            }

            let arr_color = ["rgba(47, 133, 209, 0.6)", "rgba(244, 67, 54, 0.6)", "rgba(71, 50, 123, 0.6)", "rgba(241, 194, 50, 0.6)", "rgba(56, 118, 29, 0.6)"];

            function animate() {

                //clear the canvas so that new drawings are on a blank canvas 
                ctx.clearRect(0, 0, widthCanvas, heightCanvas)
                ctx.fillStyle = "rgba(224, 31, 92, 1)";
                ctx.fillRect(0, 0, widthCanvas, heightCanvas)

                // Draw shapes aand animations   

                for (var i = 0; i <= widthCanvas; i += widthCanvas / 120) {
                    addLinesPath(i, i, 0, heightCanvas, "rgba(31, 118, 224, 0.5)");
                }

                for (let index = 0; index < num_cycles; index++) {

                    draw_circle(arr_x[index], arr_y[index], arr_r[index], arr_color[index % arr_color.length])

                    if (arr_x[index] + arr_r[index] > widthCanvas || arr_x[index] - arr_r[index] < 0)
                        arr_dx[index] = -arr_dx[index];

                    if (arr_y[index] + arr_r[index] > heightCanvas || arr_y[index] - arr_r[index] < 0)
                        arr_dy[index] = -arr_dy[index];

                    arr_x[index] += arr_dx[index];
                    arr_y[index] += arr_dy[index];
                }

                requestAnimationFrame(animate);
            }

            animate()

        }

        // resize
        function resizeCanvas() {
            canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
            canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;

            widthCanvas = canvas.width;
            heightCanvas = canvas.height;
        }

        function get_width() {
            return canvas.width;
        }
        function get_height() {
            return canvas.height;
        }

        // draw line
        function addLinesPath(y_start, y_end, x_start, x_end, color) {
            ctx.strokeStyle = color;
            ctx.lineWidth = 3;
            ctx.beginPath();
            ctx.moveTo(y_start, x_start);
            ctx.lineTo(y_end, x_end);
            ctx.stroke();
        }

        // draw circle
        function draw_circle(x, y, r, color) {
            ctx.fillStyle = color;
            ctx.beginPath();
            ctx.arc(x, y, r, 0, 2 * Math.PI);
            ctx.fill();
        }

    </script>
</body>

</html>

After resizing the browser the circles may get stuck...

考虑使用您的代码段中的以下简化代码:

if (arr_x[index] + arr_r[index] > widthCanvas)
   arr_dx[index] = -arr_dx[index];

这里,当圆圈由于调整大小超出右边界时,if 语句的计算结果始终为真。因为你每一帧都在切换方向!
确保在圆圈离开 canvas 后仅切换一次方向。



How to remove the white space around the canvas left...

默认情况下 <body> 有一些余量。在 Chrome 8px。需要检查其他浏览器。如果所有涉及的元素上有任何边距和填充,请去掉这些边距和填充。或者相应地调整代码中的 canvas 宽度。


演示:

<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    html,
    body {
      overflow: hidden;
    }
    
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
  </style>
</head>

<body onresize="resizeCanvas()">
  <div>
    <canvas id="canvas"></canvas>
  </div>

  <script>
    const canvas = document.getElementById('canvas');
    /** @type {CanvasRenderingContext2D} */
    const ctx = canvas.getContext('2d');

    canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
    canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
    widthCanvas = canvas.width;
    heightCanvas = canvas.height;

    draw(10);

    function draw(num) {
      //number of cycles 
      num_cycles = num;

      // speed bounds 
      min_speed = 2;
      // real max_speed is + min_speed
      max_speed = 2;

      // create arrays for changing values 
      const arr_x = new Array(num_cycles);
      const arr_y = new Array(num_cycles);
      const arr_dx = new Array(num_cycles);
      const arr_dy = new Array(num_cycles);
      const arr_r = new Array(num_cycles);

      // populate arrays with random vaalues in range so circles 
      // have different velocities on y and x as well as vary in radii
      for (let index = 0; index < num_cycles; index++) {
        arr_x[index] = ((widthCanvas * 0.2) * Math.random()) + (widthCanvas * 0.4);
        arr_y[index] = ((heightCanvas * 0.2) * Math.random()) + (heightCanvas * 0.4);
        arr_dx[index] = (min_speed + Math.random() * max_speed) * (Math.round(Math.random()) ? -1 : 1);
        arr_dy[index] = (min_speed + Math.random() * max_speed) * (Math.round(Math.random()) ? 1 : -1);
        arr_r[index] = 50 + Math.random() * widthCanvas / 12;
      }

      let arr_color = ["rgba(47, 133, 209, 0.6)", "rgba(244, 67, 54, 0.6)", "rgba(71, 50, 123, 0.6)", "rgba(241, 194, 50, 0.6)", "rgba(56, 118, 29, 0.6)"];

      function animate() {

        //clear the canvas so that new drawings are on a blank canvas 
        ctx.clearRect(0, 0, widthCanvas, heightCanvas)
        ctx.fillStyle = "rgba(224, 31, 92, 1)";
        ctx.fillRect(0, 0, widthCanvas, heightCanvas)

        // Draw shapes and animations   

        for (var i = 0; i <= widthCanvas; i += widthCanvas / 120) {
          addLinesPath(i, i, 0, heightCanvas, "rgba(31, 118, 224, 0.5)");
        }

        for (let index = 0; index < num_cycles; index++) {

          draw_circle(arr_x[index], arr_y[index], arr_r[index], arr_color[index % arr_color.length])

          if (arr_x[index] + arr_r[index] > widthCanvas && arr_dx[index] > 0)
            arr_dx[index] *= -1;
          else if (arr_x[index] - arr_r[index] < 0 && arr_dx[index] < 0)
            arr_dx[index] *= -1;

          if (arr_y[index] + arr_r[index] > heightCanvas && arr_dy[index] > 0)
            arr_dy[index] *= -1;
          else if (arr_y[index] - arr_r[index] < 0 && arr_dy[index] < 0)
            arr_dy[index] *= -1;

          arr_x[index] += arr_dx[index];
          arr_y[index] += arr_dy[index];
        }

        requestAnimationFrame(animate);
      }

      animate()

    }

    // resize
    function resizeCanvas() {
      canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
      canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;

      widthCanvas = canvas.width;
      heightCanvas = canvas.height;
      console.log(widthCanvas, '=', heightCanvas);
    }

    function get_width() {
      return canvas.width;
    }

    function get_height() {
      return canvas.height;
    }

    // draw line
    function addLinesPath(y_start, y_end, x_start, x_end, color) {
      ctx.strokeStyle = color;
      ctx.lineWidth = 3;
      ctx.beginPath();
      ctx.moveTo(y_start, x_start);
      ctx.lineTo(y_end, x_end);
      ctx.stroke();
    }

    // draw circle
    function draw_circle(x, y, r, color) {
      ctx.fillStyle = color;
      ctx.beginPath();
      ctx.arc(x, y, r, 0, 2 * Math.PI);
      ctx.fill();
    }
  </script>
</body>

</html>

在这里,为了避免复杂的代码,我将 if 语句分开了。


通过简单的调试,我们可以很容易地找出这些讨厌的错误。本指南可能会有所帮助:https://developer.chrome.com/docs/devtools/javascript/