【问题标题】:How to use a for loop to move a rectangle position in a canvas如何使用 for 循环在画布中移动矩形位置
【发布时间】:2017-03-05 12:33:16
【问题描述】:

首先,我是画布的新手,我已经尝试了 2 天来解决这个问题,所以我非常感谢任何帮助。我的目标是让绿色矩形一次向上移动 1 个像素(现在这个数量并不重要),但我最终也想对红色矩形做同样的事情。如果我注释掉for循环,您可以在我想要的起始位置看到矩形,但是当我在画布中添加for循环时是空白的,而理论上我希望绿色矩形向上移动。 (或向下,实际上并不重要)。

$(document).ready(function() {
  var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    cw = canvas.width,
    ch = canvas.height;


  function rectangles() {

    var y = 0;
    // Starting point rectangles
    ctx.save();
    ctx.clearRect(0, 0, cw, ch);
    ctx.beginPath();
    ctx.fillStyle = "#006847";
    ctx.fillRect(0, 0, 200, 450);
    ctx.closePath();

    ctx.beginPath();
    ctx.fillStyle = "#CE1126";
    ctx.fillRect(400, 0, 200, 450);
    ctx.closePath();

    ctx.save();
    /*for (i = 0; i < 450; i++) {
        y = y + 1;
        ctx.beginPath();
        ctx.fillRect(0, y, 200, 450);
        ctx.closePath();
        ctx.clearRect(0, 0, cw, ch);
    }*/
  }

  setInterval(rectangles, 2000);
});
CSS : #canvas {
  border: 3px #000 solid;
  margin: 0 auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div id="canvas-container">
  <canvas id="canvas" height="450" width="600"></canvas>
</div>

【问题讨论】:

    标签: javascript css html canvas


    【解决方案1】:

    不需要for 循环。您只需使用if 语句即可完成此操作。

    $(document).ready(function() {
        var canvas = document.getElementById("canvas"),
            ctx = canvas.getContext("2d"),
            cw = canvas.width,
            ch = canvas.height,
            GY = 0,
            RY = 0;
    
        rectangles();
    
        function rectangles() {
            if (GY > -450 && RY > -450) {
                GY -= 1;  // pixel
                RY -= 1;
            } else if (GY == -450 && RY == -450) {
                GY = 450;
                RY = 450;
            }
            // Starting point rectangles
            ctx.clearRect(0, 0, cw, ch);
            // green
            ctx.fillStyle = "#006847";
            ctx.fillRect(0, GY, 200, 450);
            // red
            ctx.fillStyle = "#CE1126";
            ctx.fillRect(400, RY, 200, 450);
            requestAnimationFrame(rectangles);
        }
    });
    #canvas {
      border: 3px #000 solid;
      margin: 0 auto;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div id="canvas-container">
        <canvas id="canvas" height="450" width="600"></canvas>
    </div>

    【讨论】:

    • 感谢您提供此信息。 @暹罗
    【解决方案2】:

    简短的回答是:你不能。

    原因是:在脚本执行完毕之前,您的浏览器不会渲染任何内容(因为只有这样浏览器才会返回其渲染上下文)。

    使用requestAnimationFramehttps://developer.mozilla.org/de/docs/Web/API/window/requestAnimationFrame

    $(document).ready(function() {
      var canvas = document.getElementById("canvas"),
        ctx = canvas.getContext("2d"),
        cw = canvas.width,
        ch = canvas.height;
    
      var y = 0;
    
      function rectangles() {
    
        // Starting point rectangles
        ctx.save();
        ctx.clearRect(0, 0, cw, ch);
        ctx.beginPath();
        ctx.fillStyle = "#006847";
        ctx.fillRect(0, 0, 200, 450);
        ctx.closePath();
    
        ctx.beginPath();
        ctx.fillStyle = "#CE1126";
        ctx.fillRect(400, 0, 200, 450);
        ctx.closePath();
    
        ctx.save();
        y++;
    
        ctx.beginPath();
        ctx.fillRect(0, y, 200, 450);
        ctx.closePath();
        ctx.clearRect(0, 0, cw, ch);
        if (y < 450)
          requestAnimationFrame( rectangles );
      }
    
    
      setInterval(rectangles, 2000);
    });
    

    【讨论】:

      【解决方案3】:

      您无法实现的原因是因为画布是单个实体。在清除画布之前,您无法移动矩形。 clearRect 是来救援的。

      我创建了一个名为clearCanvas 的函数。它将在重新定位矩形之前运行并清除画布。因此,您每隔两秒就会使用新计算的位置重新绘制画布。

      $(document).ready(function() {
        var canvas = document.getElementById("canvas"),
          ctx = canvas.getContext("2d"),
          cw = canvas.width,
          ch = canvas.height;
      
        var x = 100;
        var y = 100;
      
        function rectangles() {
          clearCanvas();
          var y = 0;
          // Starting point rectangles
          ctx.save();
          ctx.clearRect(0, 0, cw, ch);
          ctx.beginPath();
          ctx.fillStyle = "#006847";
          ctx.fillRect(x, 0, 50, 50);
          ctx.closePath();
      
          ctx.beginPath();
          ctx.fillStyle = "#CE1126";
          ctx.fillRect(x + 400, 0, 50, 50);
          ctx.closePath();
      
          ctx.save();
      
      
          if (x < 10) {
            x = 100;
          }
          x = x - 10;
      
        }
      
        setInterval(rectangles, 400);
      
        function clearCanvas() {
          ctx.clearRect(0, 0, cw, ch);
        }
      
      });
      #canvas {
        border: 3px #000 solid;
        margin: 0 auto;
      }
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
      <div id="canvas-container">
        <canvas id="canvas" height="450" width="600"></canvas>
      </div>

      【讨论】:

        【解决方案4】:

        已编辑:siam 在此之后做了更好的回答:HERE

        画布变为空白,因为在函数 rectangles() 中,for 循环计算位置并在眨眼间绘制矩形,在我们看到任何动画之前向我们显示最终状态(空白)。

        所以我们在每次绘制新矩形之间都设置了一些时间。我还添加了一个索引 i 来记录已经过去了多少时间,以计算矩形的新位置。请检查 sn-p 并发表评论,看看是否需要。

        $(document).ready(function() {
            var canvas = document.getElementById("canvas"),
                ctx = canvas.getContext("2d"),
                cw = canvas.width,
                ch = canvas.height;
                step = 1; // Distance the rectangle move each time
                refresh = 10; // Repaint interval
                var i = 0; // Record how far has the rectangle go
        
            function rectangles() {
                // Starting point rectangles
                ctx.save();
                ctx.clearRect(0, 0, cw, ch);
                ctx.beginPath();
                ctx.fillStyle = "#006847";
                // Leave blank area with height: i*step
                ctx.fillRect(0, 0, 100, ch-i*step); 
                ctx.closePath();
        
                ctx.beginPath();
                ctx.fillStyle = "#CE1126";
                ctx.fillRect(200, 0, 100, ch-i*step);
                ctx.closePath();
        
                ctx.save();
                i ++;
                // The canvas is blank, stop drawing
                if (ch-i*step < 0) {
                  clearInterval(interval)
                }
            }
          interval = setInterval(rectangles, refresh);
          });
        #canvas {
            border: 3px #000 solid;
            margin: 0 auto;
        }
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
        <div id="canvas-container">
          <canvas id="canvas" height="225" width="300"></canvas>
        </div> 

        【讨论】:

        • 非常感谢@jrying。正是我所希望的,现在我只是计划进一步开发它以使动画循环播放。
        • 不客气。 :) 那么也许你可以在if (ch-i*step &lt; 0) {clearInterval(interval)}做点什么
        • 对不起,你的回答很差,-1 你可能已经解决了 OPs 问题,但只是鼓励了更多的坏习惯。不要将setInterval(非常糟糕)用于动画使用requestAnimationFrame。不要无缘无故地保存状态,也不要在没有相应 ctx.restore 的情况下调用 ctx.save。如果不需要,请勿致电 beginPathclosePath。请花时间创建一个高质量的答案,因为从长远来看,这对 OP 和其他人根本没有帮助。
        • @Blindman67 首先,感谢您列出这些坏习惯。当我第一次看到这个问题时,我并没有多想,并且无法抗拒做一些简单的事情来让它工作。而且我不知道我的话会如何影响人们。我承认追求或分享知识不是正确的态度。感谢您指出这一点,我非常感谢并将记住它。
        • @Blindman67 Fortunatley 我目前正在做一些事情,需要我在画布上使用 setInterval 函数只是为了表明我可以做到,因此使用了这种方法。但是,我研究了 requestAnimationFrame 并了解它更有效。还是谢谢你:)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-01-01
        • 2016-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-20
        • 1970-01-01
        相关资源
        最近更新 更多