DAY 28
0
Modern Web

Chapter5 - 當一個勤勞的園丁，來修剪我們美麗的樹（III）Canvas動畫 讓樹隨著讀取畫面長大

題外話

``````let leafImg = new Array();
let pngImg = new Array();
for(let N = 0; N < 4; N++){ // 準備了四種樹葉素材
leafImg[N] = new Image();
// 等待每一張圖片讀取好
// 每張圖片創建一個對應的畫布
pngImg[N] = document.createElement('canvas');
pngImg[N].width = leafImg[N].width;
pngImg[N].height = leafImg[N].height;
let ctx = pngImg[N].getContext("2d");
// 畫一次就可以了，以後就拿pngImg[N]來當圖片（N為0~3之間）
ctx.drawImage(leafImg[N], 0, 0, leafImg[N].width, leafImg[N].height);
}
}
// 依序設置圖片的src(略)
``````

• 以leafImg(原圖)做來源，用了13~15秒繪製樹葉
• 以pngImg (畫布)做來源，用了10~12秒繪製樹葉

開頭畫面

``````// 獲取開始按鈕的寬度
let Start = document.querySelector("#Start");
let Start_CSS = window.getComputedStyle(Start);
let minWidth = Math.floor(Start_CSS.width.substring(0, Start_CSS.width.lastIndexOf("p")));

// 動畫框架
try{
Resize("#game-box", canvas, context, '#000');
clear(context);

// 1. 讓樹長出來
treeGrowth.NextFrame(1, -1, 3);
myTree.Transform();
myTree.Draw();

// 2. 讀取進度條
Start.style.width = minWidth + percent + "px";
Start.textContent = percent + "%";
}
else Start.textContent = "Start";
}catch(e){
console.log(e);
return;
}
}
``````

緩衝函式

``````let Trail = function(x = 0, y = 0, visibility = false){
this.pointX = x;
this.pointY = y;
this.originX = x;
this.originY = y;
this.period = 1;
this.timer = 0;
this.timestamp = Date.now();

this.NewTarget = function(targetX = 1, targetY = 1, frames = 60){
this.targetX = targetX;
this.targetY = targetY;
this.originX = this.pointX;
this.originY = this.pointY;
this.timer = frames;
this.period = frames;
this.Restore = function(){
this.pointX = x;
this.pointY = y;
this.originX = x;
this.originY = y;
this.timer = frames;
this.period = frames;
};
};
// 以下略
// NextFrame方法
}
``````

``````let treeGrowth = new Trail(0, 0, false);
treeGrowth.NewTarget(1, 0, 90);
``````

`new Traail(x, y, visibility)`設置為`(0, 0, false)`，Restore函式就會變成：

``````this.Restore = function(){
this.pointX = 0;
this.pointY = 0;
this.originX = 0;
this.originY = 0;
this.timer = frames;
this.period = frames;
};
``````

`NewTarget(targetX, targetY, frames)`設置為`(1, 0, 90)`，Restore函式就會變成：

``````this.Restore = function(){
this.pointX = 0;
this.pointY = 0;
this.originX = 0;
this.originY = 0;
this.timer = 90;
this.period = 90;
};
``````

``````Stick.prototype.grow = treeGrowth.pointX;
``````

``````// 1. 讓樹長出來
treeGrowth.NextFrame(1, -1, 3);
myTree.Transform();
myTree.Draw();
``````

``````let myTree = new Tree(WIDTH/2, 0.8 * HEIGHT, HEIGHT/6, 90, maxTimes)
let startScreen = document.querySelector("#startScreen");
treeGrowth.Restore();
myTree = new Tree(WIDTH/2, 0.8 * HEIGHT, HEIGHT/6, 90, maxTimes)
});
``````

2. 讀取進度條

``````<div id="startScreen">
<button id="Start">0%</button>
</div>
``````

``````// 獲取開始按鈕的寬度
let Start = document.querySelector("#Start");
let Start_CSS = window.getComputedStyle(Start);
let minWidth = Math.floor(Start_CSS.width.substring(0, Start_CSS.width.lastIndexOf("p")));
``````

``````// 2. 讀取進度條
Start.style.width = minWidth + percent + "px";
Start.textContent = percent + "%";
}
else if(Start.disabled == true){ // 增設一個條件，避免重複設定Dom的屬性
Start.textContent = "Start";
Start.disabled = false; // 讓按鈕從disabled狀態回到可使用狀態
}
``````

``````Start.addEventListener("click", function(){
Start.style.display = "none";
});
``````

``````let loadingAnime = requestAnimationFrame(LoadingScreen);
// ......
// 以上略
}
``````

附錄: 緩衝函式複習

``````let Trail = function(x = 0, y = 0, visibility = false){
// ......
// 以上略
this.NextFrame = function(a=input.linear, b=input.easein, c=input.easeout){
if(this.timer > 0){
let dX = this.targetX - this.originX;
let dY = this.targetY - this.originY;
let t = this.timer;
let p = this.period;
let linear = 1/p;
let easeout = Math.pow(t/p, 2) - Math.pow((t-1)/p, 2);
let easein = Math.pow(1 - (t-1)/p, 2) - Math.pow(1 - t/p, 2);
this.pointX+= (a * linear + b * easein + c * easeout) / (a+b+c) * dX;
this.pointY+= (a * linear + b * easein + c * easeout) / (a+b+c) * dY;
}
this.timer--;
if(visibility){
let width = WIDTH * 0.05;
let height = WIDTH * 0.05 * mouseImg.height / mouseImg.width;
context.save();
context.translate(this.pointX, this.pointY);
context.drawImage(mouseImg, -width/2, -height/2, width, height);
context.restore();
}
};
}
``````