更新——Canvas畫布動畫效果之實現倒計時

Hello,你們好!javascript

小W復活啦!繼續歡樂的給你們更博,輸送新知識~~java

不開玩笑啦!秒進正題~~~git

上次更博,小W給你們介紹了Canvas畫布的基礎部分,以及實現了一個由7*10點陣圖顯示的倒計時的基本架構。canvas

上次的效果以下圖所示,僅僅只是一個時間的靜態顯示而已:瀏覽器

今天呢,小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();             
            }            
        }        
    }    
}
相關文章
相關標籤/搜索