[转]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:
- 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 theclearRectmethod. - 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. - Draw animated shapes
The step where you do the actual frame rendering. - 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.
- setInterval(animateShape,500);
- setTimeout(animateShape,500);
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.
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.
- 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);
- }
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);
}
|
Canvas sun.png
source image sun |
Canvas earth.png
source image earth |
Canvas moon.png
source image moon |
An animation example 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();
- }
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();
}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
- 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;
- }
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>
<body onload="init();"> <canvas id="canvas" width="800" height="200"></canvas>
Other examples
- Particle Fountain
Interactive particle emitter with physics that uses the mouse. - Canvascape
A 3D adventure game (first-person shooter). - http://www.gradius-js.com
A classic 2D Space shooter game. - A Basic RayCaster
A good example of how to do animations using keyboard controls. - canvas adventure
Also a nice example that uses keyboard controls. - An interactive Blob
Have fun with the blob. - Flying through a starfield
Fly through stars, circles or squares. - iGrapher
An example of charting stock market data.
- ·Canvas使用教程——..
- ·svg+js+path直线的拖..
- ·Canvas使用教程——..
- ·Canvas绘图(Drawin..
- ·Canvas使用教程——..
- ·Canvas使用教程——..
- ·Canvas使用教程——..
- ·如何获得svg文件的内..
- flash/flex/fcs/AIR(752)
- Asp.Net/C#/WCF(601)
- 操作系统及应用软件(377)
- JavaScript/Ajax(331)
- SQL及数据库(135)
- 黑客技术(115)
- Asp/VBScript(111)
- HTML/WML/CSS兼容/XML(102)
- PHP/apache/Perl(96)
- 网站排名及优化(96)
- 其他(75)
- showbo日志(66)
- lucene.net/分词技术(33)
- 计算机网络(26)
- C#设计模式(26)
- 机械重工(26)
- Google Maps开发(17)
- 日语学习(15)
- Canvas/VML/SVG(13)
- linux(11)
- 游戏开发(8)
- 正则表达式(5)
- Jsp/Java(4)
- ·Canvas绘图(Drawin..
- ·Canvas使用教程——..
- ·Canvas使用教程——..
- ·Canvas使用教程——..
- ·Canvas使用教程——..
- ·Canvas使用教程——..
- ·Canvas使用教程——..
- ·Canvas使用教程——..


