canvas動畫
小球滾動效果
關鍵api:
window.requestAnimationFrame(draw)
會遞歸調用draw函數,替代setInterval
var x = 20;
var speed = 4;
//電腦的幀率是1秒鍾60Hz, 就相當於一秒鍾可以播放60張圖片,就相當於播放一張圖片使用16.7ms
function draw () {
//1. 先把畫布清空
context.clearRect(0, 0, canvas.width, canvas.height);
//2. 畫小球
context.beginPath();
var gradient = context.createRadialGradient(x-10,190,0,x,200,20);
gradient.addColorStop(0,'#fff');
gradient.addColorStop(1,'#333');
context.fillStyle = gradient;
context.arc(x, 200, 20, 0, 2*Math.PI);
context.fill();
//3. x要移動
x += speed;
if(x>canvas.width - 20||x<20){
speed = -speed;
}
//被優化過的動畫執行方向1.遞歸調用;2.可以自適應瀏覽器的刷新的幀率
window.requestAnimationFrame(draw);
}
draw();
小球x,y軸回彈效果
關鍵點:
1. 跟上面例子差不多
2. 在y軸上加多一個speed即可
var xspeed = 2;
var yspeed = 2;
//小球的初始位置
var x = 20;
var y = 200;
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
//創建一張新的玻璃紙
context.beginPath();
var gradient = context.createRadialGradient(x - 10, y-10, 0, x, y, 20);
gradient.addColorStop(0, '#fff');
gradient.addColorStop(1, '#333');
context.fillStyle = gradient;
context.arc(x, y, 20, 0, 2*Math.PI);
context.fill();
x += xspeed;
y += yspeed;
//水平方向到達了邊界, 就調頭, 速度往反方向
if (x < 20 || x > canvas.width - 20) {
xspeed = -xspeed;
}
if (y < 20 || y > canvas.height - 20) {
yspeed = -yspeed;
}
window.requestAnimationFrame(draw);
}
draw();
小鳥揮動翅膀
var birdsImg = new Image();
birdsImg.src = "./img/birds.png";
//圖片加載完成之后,才開始執行繪制操作
birdsImg.onload = function () {
//翅膀扇了第幾次
var index = 0;
//當前是第幾張圖片
var xindex = 0;
//每張小鳥圖片的寬高
var w = birdsImg.width / 3;
var h = birdsImg.height;
//小鳥的位置
var x = 100;
var y = 100;
//小鳥往下掉的速度
var yspeed = 5;
function draw() {
//使用第幾張圖片
index += 1;
xindex = index % 3;
//清空畫布
context.clearRect(0, 0, canvas.width, canvas.height);
//畫每一張小鳥
context.drawImage(birdsImg, xindex * w, 0, w, h, x, y, w, h);
//小鳥往下掉
y += yspeed;
//遞歸調用draw方法,實現動畫
window.requestAnimationFrame(draw);
}
draw();
}
地球轉動
判斷兩張圖片都加載完成的方法
var sun = new Image();
var earth = new Image();
sun.src = "./img/Canvas_sun.png";
earth.src = "./img/Canvas_earth.png";
//計數器
var count = 0;
var images = [sun, earth];
//如果需要多個圖片都加載完成之后,再操作, 應該怎么辦:
images.forEach(function (img) {
img.onload = function () {
count += 1;
if (count == images.length) {
//。。。code
}
地球轉動
var sun = new Image();
var earth = new Image();
sun.src = "./img/Canvas_sun.png";
earth.src = "./img/Canvas_earth.png";
//計數器
var count = 0;
var images = [sun, earth];
//如果需要多個圖片都加載完成之后,再操作, 應該怎么辦:
images.forEach(function (img) {
img.onload = function () {
count += 1;
if (count == images.length) {
console.log("所有的圖片都加載完成了");
function draw() {
//0. 先把原始的坐標系的狀態保存起來
context.save();
//1. 清空畫布
context.clearRect(0, 0, canvas.width, canvas.height);
//2. 畫太陽(五參模式, 原圖顯示)
context.drawImage(sun, 0, 0, sun.width, sun.height);
//3. 假設地球繞太陽一圈的時間是1分鍾,只需要拿到當前的秒數,就可以用秒數/60*360計算出地球相於水平線的角度
//拿到當前的秒數
var now = new Date();
//精確到毫秒,就能夠形成一個連續的動畫效果了
var seconds = now.getSeconds();
var millSeconds = now.getMilliseconds();
seconds += millSeconds / 1000;
//算出此時此刻的地球的角度(弧度)
var radian = seconds / 60 * 2 * Math.PI;
//4. 平移坐標系,將坐標的原點移到太陽的中心
context.translate(sun.width/2, sun.height/2);
//5. 旋轉坐標系
context.rotate(radian);
//6. 畫地球
context.drawImage(earth, 120-earth.width/2, -earth.height/2, earth.width, earth.height);
//7. 還原坐標系
context.restore();
window.requestAnimationFrame(draw);
}
draw();
}
}
})
關於save和restore
//save保存, restore恢復, 還原
//save的作用,是把context的當前的狀態,保存起來;restore是把context最近一次保存的狀態還原
context.fillStyle = "red";
context.strokeStyle = "blue";
context.shadowColor = "cyan";
//把當前的context整個保存一份
context.save(); //就會把當前的context整個保存一份
context.fillRect(100, 100, 100, 100);
context.fillStyle = "green";
context.fillRect(300, 200, 100, 100);
//把最近保存的那個context直接拿過來用
context.restore();
context.fillRect(500, 300, 100, 100);
鍾表的實現
//畫某一幀的方法
function draw() {
//0. 把坐標系的原始狀態保存
context.save();
//1. 清空畫布
context.clearRect(0, 0, canvas.width, canvas.height);
//2. 先平移坐標系到中心點,再旋轉坐標系到12點鍾的方向
context.translate(300, 200);
//往反方向旋轉90度
context.rotate(-0.5*Math.PI);
//3. 畫表盤
context.beginPath();
context.arc(0, 0, 130, 0, 2*Math.PI);
context.strokeStyle = "blue";
context.lineWidth = 3;
context.stroke();
//4. 畫時針的刻度
context.beginPath();
for (var i = 0; i<12; i++) {
context.moveTo(115, 0);
context.lineTo(126, 0);
context.rotate(30/180*Math.PI);
}
context.strokeStyle = "#000";
context.lineWidth = 6;
context.stroke();
//5. 畫分針的刻度
context.beginPath();
for (var i = 0; i<60; i++) {
if (i % 5 != 0) {
context.moveTo(120, 0);
context.lineTo(126, 0);
}
context.rotate(6/180*Math.PI);
}
context.lineWidth = 4;
context.stroke();
//6. 算出時針, 分針, 秒針的角度
var now = new Date();
var h = now.getHours();
var m = now.getMinutes();
var s = now.getSeconds();
m = m + s/60; //精確到幾點幾分鍾
h = h + m/60; //精確到幾點幾小時
var hradian = h / 12 * 2 * Math.PI;
var mradian = m / 60 * 2 * Math.PI;
var sradian = s / 60 * 2 * Math.PI;
//7. 畫時針
context.save();
context.beginPath();
context.rotate(hradian);
context.moveTo(-15, 0);
context.lineTo(60, 0);
context.strokeStyle = "blue";
context.lineWidth = 6;
context.lineCap = "round";
context.stroke();
context.restore();
//8. 畫分針
context.save();
context.beginPath();
context.rotate(mradian);
context.moveTo(-15, 0);
context.lineTo(70, 0);
context.strokeStyle = "blue";
context.lineWidth = 5;
context.lineCap = "round";
context.stroke();
context.restore();
//9. 畫秒針
context.save();
context.beginPath();
context.rotate(sradian);
context.moveTo(-15, 0);
context.lineTo(85, 0);
context.strokeStyle = "red";
context.lineWidth = 3;
context.lineCap = "round";
context.stroke();
context.restore();
//10. 畫表心
context.beginPath();
context.arc(0, 0, 5, 0, 2*Math.PI);
context.fillStyle = "red";
context.fill();
//11. 還原坐標系
context.restore();
}
//draw();
//沒有必要使用requestAnimationFrame,因為這個鍾表是一秒鍾走一次
setInterval(draw, 1000);