# 基本的动画
# 动画的基本步骤
你可以通过以下的步骤来画出一帧:
- 清空 canvas 除非接下来要画的内容会完全充满 canvas(例如背景图),否则你需要清空所有。最简单的做法就是用 clearRect 方法。
- 保存 canvas 状态 如果你要改变一些会改变 canvas 状态的设置(样式,变形之类的),又要在每画一帧之时都是原始状态的话,你需要先保存一下。
- 绘制动画图形(animated shapes) 这一步才是重绘动画帧。
- 恢复 canvas 状态 如果已经保存了 canvas 的状态,可以先恢复它,然后重绘下一帧。
# 操控动画
在 canvas 上绘制内容是用 canvas 提供的或者自定义的方法,而通常,我们仅仅在脚本执行结束后才能看见结果,比如说,在 for 循环里面做完成动画是不太可能的。
因此,为了实现动画,我们需要一些可以定时执行重绘的方法。
可以用window.setInterval(), window.setTimeout(),和window.requestAnimationFrame()来设定定期执行一个指定函数。
# 太阳系的动画
下面这个例子实现了一个经典的日地月三星系统。
const sun = new Image();
const moon = new Image();
const earth = new Image();
const WIDTH = 300;
const HEIGHT = 300;
const centerX = WIDTH / 2;
const centerY = HEIGHT / 2;
const sunR = 25;
const earthR = 12;
const moonR = 5;
const sunEarthDis = 105;
const earthMoonDis = 28.5;
function init() {
sun.src = "https://www.gausszhou.top/static/image/learn/canvas/sun.png";
moon.src =
"https://www.gausszhou.top/static/image/learn/canvas/moon.png";
earth.src =
"https://www.gausszhou.top/static/image/learn/canvas/earth.png";
window.requestAnimationFrame(draw);
}
function draw() {
const ctx = document.getElementById("demo10_1").getContext("2d");
ctx.globalCompositeOperation = "destination-over";
ctx.clearRect(0, 0, WIDTH, HEIGHT); // clear canvas
// draw sun
ctx.drawImage(sun, centerX - sunR, centerY - sunR, sunR * 2, sunR * 2);
ctx.fillStyle = "rgba(0,0,0,0.4)";
ctx.strokeStyle = "rgba(0,153,255,0.4)";
ctx.save();
// move origin to center
ctx.translate(centerX, centerY);
// Earth
var time = new Date();
ctx.rotate(
((2 * Math.PI) / 60) * time.getSeconds() +
((2 * Math.PI) / 60000) * time.getMilliseconds()
);
ctx.translate(sunEarthDis, 0);
ctx.drawImage(earth, -earthR, -earthR, earthR * 2, earthR * 2);
// Shadow
ctx.fillRect(0, -earthR, 150, earthR * 2);
// Moon
ctx.save();
ctx.rotate(
((2 * Math.PI) / 5) * time.getSeconds() +
((2 * Math.PI) / 5000) * time.getMilliseconds()
);
ctx.translate(0, earthMoonDis);
ctx.drawImage(moon, -moonR, -moonR, moonR * 2, moonR * 2);
// restore coord
ctx.restore();
ctx.restore();
// Earth orbit
ctx.beginPath();
ctx.arc(centerX, centerY, sunEarthDis, 0, Math.PI * 2, false);
ctx.stroke();
// call
window.requestAnimationFrame(draw);
}
init();