更新——Canvas畫布動畫效果之實現倒計時
Hello,大家好!
小W復活啦!繼續歡樂的給大家更博,輸送新知識~~
不開玩笑啦!秒進正題~~~
上次更博,小W給大家介紹了Canvas畫布的基礎部分,以及實現了一個由7*10點陣圖顯示的倒計時的基本架構。
上次的效果如下圖所示,僅僅只是一個時間的靜態顯示而已:
今天呢,小W想實現就是,讓它開始倒計時!效果先給大家看一下:
Canvas畫布用於圖形的繪制、動畫,都是通過腳本(JavaScript)實現的。
上次更博,countdown.js代碼中,已經實現了時:分:秒的基本架構,先把上次的JS代碼再次梳理一下,在這個基礎上,小W再進行接下來的操作:
// 全局變量 有助於後期數據的變動更改var WINDOW_WIDTH = 1024; var WINDOW_HEIGHT = 768; // 此處需要註意寬高的比例 適當縮小放大畫布的時候,盡量同時縮小放大,避免出現圓形顯示為橢圓形等不對稱現象 var MARGIN_LEFT = 30; var MARGIN_TOP = 60; var RADIUS = 8; window.onload = function(){ var canvas = document.getElementById("canvas"); var context = canvas.getContext("2d"); canvas.width= WINDOW_WIDTH; canvas.height = WINDOW_HEIGHT; render( context ); } function render( cxt ){ var hours = 12; var minute = 36; var second = 59; // 小時 為了顯示效果好看、設置居中,給每個數字設置margin renderDigit( MARGIN_LEFT , MARGIN_TOP , parseInt(hours/10) , cxt ); // 每個字水平點陣個數為直徑7,半徑:7*2 = 14,14+1 = 15 (1間隔)renderDigit( MARGIN_LEFT + 15*(RADIUS+1) , MARGIN_TOP , parseInt(hours%10) , cxt ); // 冒號 (4*2+1)= 9 digit.js中 10代表 : renderDigit( MARGIN_LEFT+ 30*(RADIUS+1) , MARGIN_TOP , 10 , cxt ); // 分鐘 renderDigit( MARGIN_LEFT+ 39*(RADIUS+1) , MARGIN_TOP , parseInt(minute/10) , cxt ); renderDigit( MARGIN_LEFT+ 54*(RADIUS+1) , MARGIN_TOP , parseInt(minute%10) , cxt ); renderDigit( MARGIN_LEFT+ 69*(RADIUS+1) , MARGIN_TOP , 10 , cxt ); // 秒 renderDigit( MARGIN_LEFT+ 78*(RADIUS+1) , MARGIN_TOP , parseInt(second/10) , cxt ); renderDigit( MARGIN_LEFT+ 93*(RADIUS+1) , MARGIN_TOP , parseInt(second%10) , cxt ); } function renderDigit(x , y , num , cxt){ // X軸坐標、Y軸坐標、將要顯示的數字、canvas上下文語境
cxt.fillStyle = "#005588";
for (var i = 0 ; i < digit[num].length ;i++) {
for (var j = 0 ; j < digit[num][i].length ;j++){
if(digit[num][i][j] == 1){ cxt.beginPath();
// 圓心位置公式
cxt.arc( x+j * 2 * (RADIUS+1) + (RADIUS+1) , y+i * 2 * (RADIUS+1) + (RADIUS+1) , RADIUS , 0 , 2*Math.PI ); cxt.closePath(); cxt.fill();
}
}
}
}
梳理完成之後我們可以進行下一步操作了,首先,我們需要設置一個截止時間,倒計時就是從現在開始到截止時間所剩余的時間:
//限制: 小時二位數 不超過4天
var endTime = new Date(2017,9,15,18,15,26); // 註意!!!:data中的參數第二個表示月份,是由0-11表示的。0 - 一月;11- 十二月
這裏需要註意,我們在之前調取小時hours的位數的時候,僅僅只是設置了兩位數,因而現在我們的倒計時最多到99:99:99,也就是四天。如果有讀者需要實現更長時間的倒計時,需要再做些許調整,為了效果美觀整潔,我們這裏只設置兩位數。使用JS提供的data()方式設置截止時間。
在render函數中,如何獲取當前時間距離截止時間剩余時間?
JS的data對象給我們提供了一個getTime的方法:它返回了距離1970.1.1的00:00:00的毫秒數,用這個方法減去截止日期的getTime(),這個差值就表示中間我們需要倒計時的小時、分鐘和秒數,但是由於時間是一秒一秒變動的,這個動畫效果需要不斷的與當前時間作比較,為此我們設計一個全局的變量,來表示現在倒計時需要多少秒?
var curShowTimeSecond = 0; // 現在倒計時需要多少毫秒, —— > 秒
接下來,對 curShowTimeSecond 進行具體的計算:
curShowTimeSecond = getCurShowTimeSecond(); // 封裝一個函數
// javascript Date 提供了 getTime 函數 以便於獲取實時時間 // getCurShowTimeSecond 函數 獲取當前總共的毫秒數 function getCurShowTimeSecond(){ var curTime = new Date(); // 獲取當前的時間是多少 var ret = endTime.getTime() - curTime.getTime(); //ret 獲取截止時間與當前時間相差的毫秒數 ret = Math.round( ret/1000 ); // 將毫秒轉換成秒 return ret>=0 ? ret : 0; // 判斷 ret,倒計時結束,函數返回0. }
現在,剩余時間的秒數已經得到了,我們接下來需要設置小時、分鐘、秒數的顯示:
var hours = parseInt( curShowTimeSecond/3600 ); // 剩余時間有多少個小時 var minute = parseInt( (curShowTimeSecond - hours * 3600) / 60 ); // 減去小時,剩余時間的分鐘數 var second = curShowTimeSecond % 60; // 減去小時、分鐘後,剩余時間還剩多少秒
到這裏,在瀏覽器的刷新後,倒計時可以實現實時更新了。
然而我們想要實現的是讓它自己更新、變化,實現倒計時,接下來我們需要引入一個實現動畫的基礎函數——定時器setInterval() 方法:
// 動畫效果 setInterval( function(){ render( context ); // 繪制當前的畫面。 update(); // 根據繪制畫面所需要的數據結構,對數據結構進行調整。 }, 50 // 毫秒 );
其實,我們可以直接獲取新的時間在render()裏面進行繪制就可以了,但是這個最終的效果是想要實現,隨著時間變化,產生彩色小球的物理變化的動畫,因為為了鋪墊後文,我們使用了一個update() 函數,如下圖所示:
// 時間更新函數 function update(){ // 註意 render 裏面是繪制curShowTimeSecond var nextShowTimeSecond = getCurShowTimeSecond(); // 下一次 // 下一次要顯示的時間(時\分\秒分解) var nextHours = parseInt( nextShowTimeSecond/3600 ); var nextMinute = parseInt( (nextShowTimeSecond - nextHours * 3600) / 60 ); var nextSecond = nextShowTimeSecond % 60; var curtHours = parseInt( curShowTimeSecond/3600 ); var curtMinute = parseInt( (curShowTimeSecond - curtHours * 3600) / 60 ); var curtSecond = curShowTimeSecond % 60; if(nextSecond != curtSecond) // 下一次顯示的秒數不等於當前顯示的秒數了,替換為新的時間 curShowTimeSecond = nextShowTimeSecond; }
為了避免當前新圖像,與之前的圖像疊加,我們在render()裏面引入一個新的函數:
// 為避免新一次的圖像與之前的圖像疊加。 // clearRect(): 對一個矩形空間內的圖像進行一次刷新操作。這裏,對整個屏幕進行一次操作、刷新。 cxt.clearRect(0,0,WINDOW_WIDTH,WINDOW_HEIGHT);
到這裏我們今天的效果已經基本實現了。
後續學習後,還會繼續更新,與大家分享...希望可以多多關註!
如果有任何問題,大家可以提出來,小W同大家一起解決,有何不妥的地方也請大神多多指教,這次的博文就到這了,謝謝大家!
附完整countdown.js代碼
var WINDOW_WIDTH = 1024; var WINDOW_HEIGHT = 768; var MARGIN_LEFT = 30; var MARGIN_TOP = 60; var RADIUS = 8; //限制: 小時二位數 不超過4天 var endTime = new Date(2017,9,15,18,15,26); // 註意!!!:data中的參數第二個表示月份,是由0-11表示的。0 - 一月;11- 十二月 var curShowTimeSecond = 0; // 現在倒計時需要多少毫秒 window.onload = function(){ var canvas = document.getElementById("canvas"); var context = canvas.getContext("2d"); canvas.width = WINDOW_WIDTH; canvas.height = WINDOW_HEIGHT; curShowTimeSecond = getCurShowTimeSecond(); //curShowTimeSecond:當前總共的毫秒數 // 動畫效果 setInterval( function(){ render( context ); update(); }, 50 // 毫秒 ); } // javascript 的 Date 提供了 getTime 函數 以便於獲取實時時間 // getCurShowTimeSecond 函數 獲取當前總共的毫秒數 function getCurShowTimeSecond(){ var curTime = new Date(); // 獲取當前的時間是多少 var ret = endTime.getTime() - curTime.getTime(); //ret 獲取截止時間與當前時間相差的毫秒數 ret = Math.round( ret/1000 ); // 將毫秒轉換成秒 return ret>=0 ? ret : 0; // 判斷 ret,倒計時結束,函數返回0. } // 時間更新函數 function update(){ var nextShowTimeSecond = getCurShowTimeSecond(); // 下一次要顯示的時間(時分秒分解) var nextHours = parseInt( nextShowTimeSecond/3600 ); var nextMinute = parseInt( (nextShowTimeSecond - nextHours * 3600) / 60 ); var nextSecond = nextShowTimeSecond % 60; var curtHours = parseInt( curShowTimeSecond/3600 ); // 一共需要多少個小時 var curtMinute = parseInt( (curShowTimeSecond - curtHours * 3600) / 60 ); var curtSecond = curShowTimeSecond % 60; if(nextSecond != curtSecond) curShowTimeSecond = nextShowTimeSecond; } function render( cxt ){ // 為避免新一次的圖像與之前的圖像疊加。 // clearRect(): 對一個矩形空間內的圖像進行一次刷新操作。這裏,對整個屏幕進行一次刷新。 cxt.clearRect(0,0,WINDOW_WIDTH,WINDOW_HEIGHT); var hours = parseInt( curShowTimeSecond/3600 ); // 一共需要多少個小時 var minute = parseInt( (curShowTimeSecond - hours * 3600) / 60 ); var second = curShowTimeSecond % 60; // 小時 renderDigit( MARGIN_LEFT , MARGIN_TOP , parseInt(hours/10) , cxt ); // 每個字水平位置直徑7,7*2 = 14半徑+1 = 15 renderDigit( MARGIN_LEFT + 15*(RADIUS+1) , MARGIN_TOP , parseInt(hours%10) , cxt ); // 冒號 (4*2+1)= 9 digit.js中 10代表 : renderDigit( MARGIN_LEFT+ 30*(RADIUS+1) , MARGIN_TOP , 10 , cxt ); // 分鐘 renderDigit( MARGIN_LEFT+ 39*(RADIUS+1) , MARGIN_TOP , parseInt(minute/10) , cxt ); renderDigit( MARGIN_LEFT+ 54*(RADIUS+1) , MARGIN_TOP , parseInt(minute%10) , cxt ); // 冒號 (4*2+1)= 9 digit.js中 10代表 : renderDigit( MARGIN_LEFT+ 69*(RADIUS+1) , MARGIN_TOP , 10 , cxt ); // 秒 renderDigit( MARGIN_LEFT+ 78*(RADIUS+1) , MARGIN_TOP , parseInt(second/10) , cxt ); renderDigit( MARGIN_LEFT+ 93*(RADIUS+1) , MARGIN_TOP , parseInt(second%10) , cxt ); } function renderDigit(x , y , num , cxt){ cxt.fillStyle = "#005588"; for (var i = 0 ; i < digit[num].length ;i++) { for (var j = 0 ; j < digit[num][i].length ;j++){ if(digit[num][i][j] == 1){ cxt.beginPath(); // 圓心位置公式 cxt.arc( x+j * 2 * (RADIUS+1) + (RADIUS+1) , y+i * 2 * (RADIUS+1) + (RADIUS+1) , RADIUS , 0 , 2*Math.PI ); cxt.closePath(); cxt.fill(); } } } }
更新——Canvas畫布動畫效果之實現倒計時