1. 程式人生 > >更新——Canvas畫布動畫效果之實現倒計時

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

判斷 大神 radius 希望 日期 ~~ width radi 多少

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畫布動畫效果之實現倒計時