mozilla
您的搜索结果

    基本的动画

    Since we're using script to control canvas elements it's also very easy to make (interactive) animations. Unfortunately the canvas element was never designed to be used in this way (unlike Flash) so there are limitations.

    由于我们是用脚本去操控 canvas 对象,这样要实现一些交互动画也是相当容易的。只不过,canvas 从来都不是专门为动画而设计的(不像 Flash),难免会有些限制。

    Probably the biggest limitation is that once a shape gets drawn it stays that way. If we need to move it we have to redraw it and everything that was drawn before it. It takes a lot of time to redraw complex frames and the performance depends highly on the speed of the computer it's running on.

    可能最大的限制就是图像一旦绘制出来,它就是一直保持那样了。如果需要移动它,我们不得不对所有东西(包括之前的)进行重绘。重绘是相当费时的,而且性能很依赖于电脑的速度。

    基本动画的步骤 Basic animation steps

    画一帧,你需要以下一些步骤:

    1. 清空 canvas
      除非接下来要画的内容会完全充满 canvas (例如背景图),否则你需要清空所有。最简单的做法就是用 clearRect 方法。
    2. 保存 canvas 状态
      如果你要改变一些会改变 canvas 状态的设置(样式,变形之类的),又要在每画一帧之时都是原始状态的话,你需要先保存一下。
    3. 绘制动画图形(animated shapes)
      这一步才是重绘动画帧。
    4. 恢复 canvas 状态
      如果已经保存了 canvas 的状态,可以先恢复它,然后重绘下一帧。

    操控动画 Controlling an animation

    Shapes are drawn to the canvas by using the canvas methods directly or calling custom functions. In normal circumstances we only see these results appear on the canvas when the script finishes execution. For instance it isn't possible to do an animation from within a for loop.

    在 canvas 上绘制内容是用 canvas 提供的或者自定义的方法,而通常,我们仅仅在脚本执行结束后才能看见结果,比如说,在 for 循环里面做完成动画是不太可能的。

    We need a way to execute our drawing functions over a period of time. There are two ways to control an animation like this. First there's the setInterval and setTimeout functions which can be used to call a specific function over a set period of time.

    我们需要一些可以定时的执行重绘的方法。有两种方法可以实现这样的动画操控。首先可以通过 setIntervalsetTimeout 方法来控制在设定的时间点上执行重绘。

    setInterval(animateShape,500);
    setTimeout(animateShape,500);
    

    If you don't want any user interaction it's best to use the setInterval function which repeatedly executes the supplied code. In the example above the animateShape function is executed every 500 miliseconds (half a second). The setTimeout function only executes once after the set amount of time.

    如果你不需要任何交互操作,用 setInterval 方法定时执行重绘是最适合的了。在上面的例子(leegorous不见了?)里 animateShape 方法每半秒执行一次。setTimeout 方法只会在预设时间点上执行操作。

    The second method we can use to control an animation is user input. If we wanted to make a game we could use keyboard or mouse events to control the animation. By setting eventListeners we catch any user interaction and execute our animation functions.

    第二个方法,我们可以利用用户输入来实现操控。如果需要做一个游戏,我们可以通过监听用户交互过程中触发的事件(如 keyboard,mouse)来控制动画效果。

    In the examples below I'm using the first method to control the animation. At the bottom of this page are some links to examples which use the second.

    下面的例子,我还使用第一种方式实现动画效果。页面底部有些链接,那些是应用第二种方法的例子。

    动画例子 1

    In this example I'm going to animate a mini simulation of our solar system.

    这个例子里面,我会让一个小型的太阳系模拟系统动起来。

    var sun = new Image();
    var moon = new Image();
    var earth = new Image();
    function init(){
      sun.src = 'images/sun.png';
      moon.src = 'images/moon.png';
      earth.src = 'images/earth.png';
      setInterval(draw,100);
    }
    
    function draw() {
      var ctx = document.getElementById('canvas').getContext('2d');
    
      ctx.globalCompositeOperation = 'destination-over';
      ctx.clearRect(0,0,300,300); // clear canvas
    
      ctx.fillStyle = 'rgba(0,0,0,0.4)';
      ctx.strokeStyle = 'rgba(0,153,255,0.4)';
      ctx.save();
      ctx.translate(150,150);
    
      // Earth
      var time = new Date();
      ctx.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() );
      ctx.translate(105,0);
      ctx.fillRect(0,-12,50,24); // Shadow
      ctx.drawImage(earth,-12,-12);
    
      // Moon
      ctx.save();
      ctx.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() );
      ctx.translate(0,28.5);
      ctx.drawImage(moon,-3.5,-3.5);
      ctx.restore();
    
      ctx.restore();
      
      ctx.beginPath();
      ctx.arc(150,150,105,0,Math.PI*2,false); // Earth orbit
      ctx.stroke();
     
      ctx.drawImage(sun,0,0,300,300);
    }
    

    动画例子 2

    function init(){
      clock();
      setInterval(clock,1000);
    }
    function clock(){
      var now = new Date();
      var ctx = document.getElementById('canvas').getContext('2d');
      ctx.save();
      ctx.clearRect(0,0,150,150);
      ctx.translate(75,75);
      ctx.scale(0.4,0.4);
      ctx.rotate(-Math.PI/2);
      ctx.strokeStyle = "black";
      ctx.fillStyle = "white";
      ctx.lineWidth = 8;
      ctx.lineCap = "round";
    
      // Hour marks
      ctx.save();
      for (var i=0;i<12;i++){
        ctx.beginPath();
        ctx.rotate(Math.PI/6);
        ctx.moveTo(100,0);
        ctx.lineTo(120,0);
        ctx.stroke();
      }
      ctx.restore();
    
      // Minute marks
      ctx.save();
      ctx.lineWidth = 5;
      for (i=0;i<60;i++){
        if (i%5!=0) {
          ctx.beginPath();
          ctx.moveTo(117,0);
          ctx.lineTo(120,0);
          ctx.stroke();
        }
        ctx.rotate(Math.PI/30);
      }
      ctx.restore();
      
      var sec = now.getSeconds();
      var min = now.getMinutes();
      var hr  = now.getHours();
      hr = hr>=12 ? hr-12 : hr;
    
      ctx.fillStyle = "black";
    
      // write Hours
      ctx.save();
      ctx.rotate( hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec )
      ctx.lineWidth = 14;
      ctx.beginPath();
      ctx.moveTo(-20,0);
      ctx.lineTo(80,0);
      ctx.stroke();
      ctx.restore();
    
      // write Minutes
      ctx.save();
      ctx.rotate( (Math.PI/30)*min + (Math.PI/1800)*sec )
      ctx.lineWidth = 10;
      ctx.beginPath();
      ctx.moveTo(-28,0);
      ctx.lineTo(112,0);
      ctx.stroke();
      ctx.restore();
      
      // Write seconds
      ctx.save();
      ctx.rotate(sec * Math.PI/30);
      ctx.strokeStyle = "#D40000";
      ctx.fillStyle = "#D40000";
      ctx.lineWidth = 6;
      ctx.beginPath();
      ctx.moveTo(-30,0);
      ctx.lineTo(83,0);
      ctx.stroke();
      ctx.beginPath();
      ctx.arc(0,0,10,0,Math.PI*2,true);
      ctx.fill();
      ctx.beginPath();
      ctx.arc(95,0,10,0,Math.PI*2,true);
      ctx.stroke();
      ctx.fillStyle = "#555";
      ctx.arc(0,0,3,0,Math.PI*2,true);
      ctx.fill();
      ctx.restore();
    
      ctx.beginPath();
      ctx.lineWidth = 14;
      ctx.strokeStyle = '#325FA2';
      ctx.arc(0,0,142,0,Math.PI*2,true);
      ctx.stroke();
    
      ctx.restore();
    }

    动画例子 3

    This is the code for a left-to-right looping panoramic image scroller. Make sure the image is larger than the canvas.

    这是一个从左到右滚动的全景动画的代码。请注意图片的大小需要比 canvas 大。

    本例中用的是这张图片:
    http://commons.wikimedia.org/wiki/File:Capitan_Meadows,_Yosemite_National_Park.jpg

    var img = new Image();
    
    //User Variables
    img.src = 'Capitan_Meadows,_Yosemite_National_Park.jpg';
    var CanvasXSize = 800;
    var CanvasYSize = 200;
    var speed = 30; //lower is faster
    var scale = 1.05;
    var y = -4.5; //vertical offset
    //End User Variables
    
    var dx = 0.75;
    var imgW = img.width*scale;
    var imgH = img.height*scale;
    var x = 0;
    if (imgW > CanvasXSize) { x = CanvasXSize-imgW; } // image larger than canvas
    var clearX;
    var clearY;
    if (imgW > CanvasXSize) { clearX = imgW; } // image larger than canvas
    else { clearX = CanvasXSize; }
    if (imgH > CanvasYSize) { clearY = imgH; } // image larger than canvas
    else { clearY = CanvasYSize; }
    var ctx;
    
    function init() {
        //Get Canvas Element
        ctx = document.getElementById('canvas').getContext('2d');
        //Set Refresh Rate
        return setInterval(draw, speed);
    }
    
    function draw() {
        //Clear Canvas
        ctx.clearRect(0,0,clearX,clearY);
        //If image is <= Canvas Size
        if (imgW <= CanvasXSize) {
            //reset, start from beginning
            if (x > (CanvasXSize)) { x = 0; }
            //draw aditional image
            if (x > (CanvasXSize-imgW)) { ctx.drawImage(img,x-CanvasXSize+1,y,imgW,imgH); }
        }
        //If image is > Canvas Size
        else {
            //reset, start from beginning
            if (x > (CanvasXSize)) { x = CanvasXSize-imgW; }
            //draw aditional image
            if (x > (CanvasXSize-imgW)) { ctx.drawImage(img,x-imgW+1,y,imgW,imgH); }
        }
        //draw image
        ctx.drawImage(img,x,y,imgW,imgH);
        //amount to move
        x += dx;
    }
    

    html code. Canvas width and height should match the CanvasXSize, CanvasYSize.

    <body onload="init();">
    <canvas id="canvas" width="800" height="200"></canvas>
    

    其它例子

    下页应该导向《概括总结》,不过还没写,所有下页会导向一个编辑页面。

    文档标签和贡献者

    此页面的贡献者有: ziyunfei, YanLing, leegorous
    最后编辑者: ziyunfei,