Canvas使用教程——动画基础(Basic animations)

来源:https://developer.mozilla.org/en/Canvas_tutorial/Basic_animations

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.

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

These are the steps you need to take to draw a frame:

  1. Clear the canvas
    Unless the shapes you'll be drawing fill the complete canvas (for instance a backdrop image), you need to clear any shapes that have been drawn previously. The easiest way to do this is using the clearRect method.
  2. Save the canvas state
    If you're changing any setting (styles, transformations, etc) which affect the canvas state and want to make sure the original state is used each time a frame is drawn, you need to save it.
  3. Draw animated shapes
    The step where you do the actual frame rendering.
  4. Restore the canvas state
    If you've saved the state, restore it before drawing a new frame.

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.

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.

  1. setInterval(animateShape,500);   
  2. 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.

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.

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.

An animation example 1

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

 
  1. var sun = new Image();   
  2. var moon = new Image();   
  3. var earth = new Image();   
  4. function init(){   
  5.   sun.src = 'images/sun.png';   
  6.   moon.src = 'images/moon.png';   
  7.   earth.src = 'images/earth.png';   
  8.   setInterval(draw,100);   
  9. }   
  10.   
  11. function draw() {   
  12.   var ctx = document.getElementById('canvas').getContext('2d');   
  13.   
  14.   ctx.globalCompositeOperation = 'destination-over';   
  15.   ctx.clearRect(0,0,300,300); // clear canvas   
  16.   
  17.   ctx.fillStyle = 'rgba(0,0,0,0.4)';   
  18.   ctx.strokeStyle = 'rgba(0,153,255,0.4)';   
  19.   ctx.save();   
  20.   ctx.translate(150,150);   
  21.   
  22.   // Earth   
  23.   var time = new Date();   
  24.   ctx.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() );   
  25.   ctx.translate(105,0);   
  26.   ctx.fillRect(0,-12,50,24); // Shadow   
  27.   ctx.drawImage(earth,-12,-12);   
  28.   
  29.   // Moon   
  30.   ctx.save();   
  31.   ctx.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() );   
  32.   ctx.translate(0,28.5);   
  33.   ctx.drawImage(moon,-3.5,-3.5);   
  34.   ctx.restore();   
  35.   
  36.   ctx.restore();   
  37.      
  38.   ctx.beginPath();   
  39.   ctx.arc(150,150,105,0,Math.PI*2,false); // Earth orbit   
  40.   ctx.stroke();   
  41.     
  42.   ctx.drawImage(sun,0,0,300,300);   
  43. }  

An animation example 2

  1. function init(){   
  2.   clock();   
  3.   setInterval(clock,1000);   
  4. }   
  5. function clock(){   
  6.   var now = new Date();   
  7.   var ctx = document.getElementById('canvas').getContext('2d');   
  8.   ctx.save();   
  9.   ctx.clearRect(0,0,150,150);   
  10.   ctx.translate(75,75);   
  11.   ctx.scale(0.4,0.4);   
  12.   ctx.rotate(-Math.PI/2);   
  13.   ctx.strokeStyle = "black";   
  14.   ctx.fillStyle = "white";   
  15.   ctx.lineWidth = 8;   
  16.   ctx.lineCap = "round";   
  17.   
  18.   // Hour marks   
  19.   ctx.save();   
  20.   for (var i=0;i<12;i++){   
  21.     ctx.beginPath();   
  22.     ctx.rotate(Math.PI/6);   
  23.     ctx.moveTo(100,0);   
  24.     ctx.lineTo(120,0);   
  25.     ctx.stroke();   
  26.   }   
  27.   ctx.restore();   
  28.   
  29.   // Minute marks   
  30.   ctx.save();   
  31.   ctx.lineWidth = 5;   
  32.   for (i=0;i<60;i++){   
  33.     if (i%5!=0) {   
  34.       ctx.beginPath();   
  35.       ctx.moveTo(117,0);   
  36.       ctx.lineTo(120,0);   
  37.       ctx.stroke();   
  38.     }   
  39.     ctx.rotate(Math.PI/30);   
  40.   }   
  41.   ctx.restore();   
  42.      
  43.   var sec = now.getSeconds();   
  44.   var min = now.getMinutes();   
  45.   var hr  = now.getHours();   
  46.   hr = hr>=12 ? hr-12 : hr;   
  47.   
  48.   ctx.fillStyle = "black";   
  49.   
  50.   // write Hours   
  51.   ctx.save();   
  52.   ctx.rotate( hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec )   
  53.   ctx.lineWidth = 14;   
  54.   ctx.beginPath();   
  55.   ctx.moveTo(-20,0);   
  56.   ctx.lineTo(80,0);   
  57.   ctx.stroke();   
  58.   ctx.restore();   
  59.   
  60.   // write Minutes   
  61.   ctx.save();   
  62.   ctx.rotate( (Math.PI/30)*min + (Math.PI/1800)*sec )   
  63.   ctx.lineWidth = 10;   
  64.   ctx.beginPath();   
  65.   ctx.moveTo(-28,0);   
  66.   ctx.lineTo(112,0);   
  67.   ctx.stroke();   
  68.   ctx.restore();   
  69.      
  70.   // Write seconds   
  71.   ctx.save();   
  72.   ctx.rotate(sec * Math.PI/30);   
  73.   ctx.strokeStyle = "#D40000";   
  74.   ctx.fillStyle = "#D40000";   
  75.   ctx.lineWidth = 6;   
  76.   ctx.beginPath();   
  77.   ctx.moveTo(-30,0);   
  78.   ctx.lineTo(83,0);   
  79.   ctx.stroke();   
  80.   ctx.beginPath();   
  81.   ctx.arc(0,0,10,0,Math.PI*2,true);   
  82.   ctx.fill();   
  83.   ctx.beginPath();   
  84.   ctx.arc(95,0,10,0,Math.PI*2,true);   
  85.   ctx.stroke();   
  86.   ctx.fillStyle = "#555";   
  87.   ctx.arc(0,0,3,0,Math.PI*2,true);   
  88.   ctx.fill();   
  89.   ctx.restore();   
  90.   
  91.   ctx.beginPath();   
  92.   ctx.lineWidth = 14;   
  93.   ctx.strokeStyle = '#325FA2';   
  94.   ctx.arc(0,0,142,0,Math.PI*2,true);   
  95.   ctx.stroke();   
  96.   
  97.   ctx.restore();   
  98. }  

An animation example 3

This is the code for a left-to-right looping panoramic image scroller. Make sure the image is larger than the canvas.
Using this file for this example
http://commons.wikimedia.org/wiki/File:Capitan_Meadows,_Yosemite_National_Park.jpg

  1. var img = new Image();   
  2.   
  3. //User Variables   
  4. img.src = 'Capitan_Meadows,_Yosemite_National_Park.jpg';   
  5. var CanvasXSize = 800;   
  6. var CanvasYSize = 200;   
  7. var speed = 30; //lower is faster   
  8. var scale = 1.05;   
  9. var y = -4.5; //vertical offset   
  10. //End User Variables   
  11.   
  12. var dx = 0.75;   
  13. var imgW = img.width*scale;   
  14. var imgH = img.height*scale;   
  15. var x = 0;   
  16. if (imgW > CanvasXSize) { x = CanvasXSize-imgW; } // image larger than canvas   
  17. var clearX;   
  18. var clearY;   
  19. if (imgW > CanvasXSize) { clearX = imgW; } // image larger than canvas   
  20. else { clearX = CanvasXSize; }   
  21. if (imgH > CanvasYSize) { clearY = imgH; } // image larger than canvas   
  22. else { clearY = CanvasYSize; }   
  23. var ctx;   
  24.   
  25. function init() {   
  26.     //Get Canvas Element   
  27.     ctx = document.getElementById('canvas').getContext('2d');   
  28.     //Set Refresh Rate   
  29.     return setInterval(draw, speed);   
  30. }   
  31.   
  32. function draw() {   
  33.     //Clear Canvas   
  34.     ctx.clearRect(0,0,clearX,clearY);   
  35.     //If image is <= Canvas Size   
  36.     if (imgW <= CanvasXSize) {   
  37.         //reset, start from beginning   
  38.         if (x > (CanvasXSize)) { x = 0; }   
  39.         //draw aditional image   
  40.         if (x > (CanvasXSize-imgW)) { ctx.drawImage(img,x-CanvasXSize+1,y,imgW,imgH); }   
  41.     }   
  42.     //If image is > Canvas Size   
  43.     else {   
  44.         //reset, start from beginning   
  45.         if (x > (CanvasXSize)) { x = CanvasXSize-imgW; }   
  46.         //draw aditional image   
  47.         if (x > (CanvasXSize-imgW)) { ctx.drawImage(img,x-imgW+1,y,imgW,imgH); }   
  48.     }   
  49.     //draw image   
  50.     ctx.drawImage(img,x,y,imgW,imgH);   
  51.     //amount to move   
  52.     x += dx;   
  53. }  

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

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

Other examples

加支付宝好友偷能量挖...


评论(0)网络
阅读(196)喜欢(0)Canvas/VML/SVG