【问题标题】:moving an image across a html canvas在 html 画布上移动图像
【发布时间】:2010-06-16 21:04:27
【问题描述】:

我正在尝试将图像从右侧移到中心,但我不确定这是否是最好的方法。

var imgTag = null;
    var x = 0;
    var y = 0;
    var id;

    function doCanvas()
    {
        var canvas = document.getElementById('icanvas');
        var ctx = canvas.getContext("2d");
        var imgBkg = document.getElementById('imgBkg');
        imgTag = document.getElementById('imgTag');

        ctx.drawImage(imgBkg, 0, 0);

        x = canvas.width;
        y = 40;

        id = setInterval(moveImg, 0.25);

    }

    function moveImg()
    {
        if(x <= 250)
            clearInterval(id);

        var canvas = document.getElementById('icanvas');
        var ctx = canvas.getContext("2d");

        ctx.clearRect(0, 0, canvas.width, canvas.height);

        var imgBkg = document.getElementById('imgBkg');
        ctx.drawImage(imgBkg, 0, 0);

        ctx.drawImage(imgTag, x, y);

        x = x - 1;
    }

有什么建议吗?

【问题讨论】:

  • setInterval 需要几毫秒,而不是几秒。大多数浏览器的实际下限约为 10 毫秒。

标签: html canvas


【解决方案1】:

这个问题已经有 5 年历史了,但由于我们现在有 requestAnimationFrame() 方法,这里有一个使用原生 JavaScript 的方法:

var imgTag = new Image(),
    canvas = document.getElementById('icanvas'),
    ctx = canvas.getContext("2d"),
    x = canvas.width,
    y = 0;

imgTag.onload = animate;
imgTag.src = "http://i.stack.imgur.com/Rk0DW.png";   // load image

function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);  // clear canvas
  ctx.drawImage(imgTag, x, y);                       // draw image at current position
  x -= 4;
  if (x > 250) requestAnimationFrame(animate)        // loop
}
&lt;canvas id="icanvas" width=640 height=180&gt;&lt;/canvas&gt;

【讨论】:

    【解决方案2】:

    drawImage() 可以定义源图像的哪个部分在目标画布上绘制。我建议为每个moveImg() 计算前一个图像位置,用imgBkg 的那部分覆盖前一个图像,然后绘制新图像。据说这会节省一些计算能力。

    【讨论】:

      【解决方案3】:

      是的,我知道这个问题已有 10 年的历史了,但无论如何我都会回答它,所以这是我的答案。

      这是 index.html 文件:

      <!DOCTYPE html>
      <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>
                  Animate an Image on a Canvas
              </title>
          </head>
          <body>
              <canvas id="canvas" class="canvas" width="250" height="150"></canvas>
          </body>
          <script src="script.js"></script>
      </html>
      

      这是 script.js 文件:

      var canvas = document.getElementById("canvas");
      ctx = canvas.getContext("2d");
      
      var myImg = new Image();
      var myImgPos = {
          x: 250,
          y: 125,
          width: 50,
          height: 25
      }
      
      function draw() {
          myImg.onload = function () {
              ctx.drawImage(myImg, myImgPos.x, myImgPos.y, myImgPos.width, myImgPos.height);
          }
          
          myImg.src = "myImg.png";
      }
      
      function moveMyImg() {
          ctx.clearRect(myImgPos.x, myImgPos.y, myImgPos.x + myImgPos.width, myImgPos.y + 
              myImgPos.height);
          myImgPos.x -= 5;
      }
      
      setInterval(draw, 50);
      setInterval(moveMyImg, 50);
      

      我希望这会有所帮助!

      【讨论】:

        【解决方案4】:

        对于无延迟动画,我通常使用 kinetic.js。

         var stage = new Kinetic.Stage({
                container: 'container',
                width: 578,
                height: 200
              });
              var layer = new Kinetic.Layer();
        
              var hexagon = new Kinetic.RegularPolygon({
                x: stage.width()/2,
                y: stage.height()/2,
                sides: 6,
                radius: 70,
                fill: 'red',
                stroke: 'black',
                strokeWidth: 4
              });
        
              layer.add(hexagon);
              stage.add(layer);
        
              var amplitude = 150;
              var period = 2000;
              // in ms
              var centerX = stage.width()/2;
        
              var anim = new Kinetic.Animation(function(frame) {
                hexagon.setX(amplitude * Math.sin(frame.time * 2 * Math.PI / period) + centerX);
              }, layer);
        
              anim.start();
        

        这里是例子,如果你想看看。

        http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-animate-position-tutorial/

        为什么我建议这样做是因为,当同时发生大量动画时,setInterval 或 setTimeout 特定函数会导致问题,但 kinetic.Animation 处理帧速率 更智能。

        【讨论】:

          【解决方案5】:

          用一个例子解释window.requestAnimationFrame()

          在下面的 sn-p 中,我将使用一个图像来制作动画。

          老实说...window.requestAnimationFrame() 对我来说并不容易理解,这就是为什么我将其编码得尽可能清晰和直观。这样你就可以比我更容易理解它。

          const canvas = document.getElementById('root')
          const btn = document.getElementById('btn')
          const ctx = canvas.getContext('2d')
          const brickImage = new Image()
                
          brickImage.src = "https://i.stack.imgur.com/YreH6.png"
          
          var piece = {
            image: brickImage,
            x: 0,
            y: 70,
            width: 70
          }
               
          btn.addEventListener('click', start) // When btn is clicked execute start()
          
          function start(){
            if(btn.value === 'start'){
              btn.value = 'animation started'  
              brickImage.onload = window.requestAnimationFrame(gameLoop) // Start gameLoop()
            }
          }
          
          function gameLoop(){ 
            ctx.clearRect(0, 0, canvas.width, canvas.height) // Clear canvas
            ctx.drawImage(piece.image, piece.x, piece.y)     // Draw at coordinates x and y
            
            pieceRightSide = piece.x + piece.width
            if(pieceRightSide < canvas.width){ // Brick stops when it gets to the right border 
              piece.x += 1
            }
            window.requestAnimationFrame(gameLoop)   // Needed to keep looping
          }
          <input id="btn" type="button" value="start" />
          <p>
          <canvas id="root" width="400" style="border:1px solid grey">

          一个关键点

          start() 函数中我们有:

          brickImage.onload = window.requestAnimationFrame(gameLoop);
          

          这也可以写成:window.requestAnimationFrame(gameLoop); 它可能会起作用,但我添加了brickImage.onload 以确保首先加载图像。否则可能会导致一些问题。

          注意:window.requestAnimationFrame() 通常每秒循环 60 次。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-11-18
            • 2018-09-05
            • 1970-01-01
            • 1970-01-01
            • 2016-02-18
            • 1970-01-01
            • 1970-01-01
            • 2011-07-08
            相关资源
            最近更新 更多