每週一點canvas動畫——序

《每週一點canvas動畫》是一個系列文章,本文並不對canvas的API作過多的介紹,我默認你已經瞭解基本的canvas繪圖API,並在此告訴你如何使用簡單的數學與物理知識建立至關酷炫的動畫。一說到物理和數學知識各位騷年們是否是感受蛋疼(原諒我說髒話了),不過我要告訴你,咱們用到的數學和物理知識真的很簡單,一點都不可怕。html

1.支持狀況

canvas做爲H5中最爲重要的新增特性,使開發者能夠用它來創做各類使人驚歎的做品。但開發者最關心的問題確定是瀏覽器的支持狀況(圖片來自張鑫旭博客)!git

圖片描述

2.本文主要內容

本系列文章主要介紹Canvas 2D動畫原理,以及簡單的如何在2D平面模仿3D效果的方法,中間可能會穿插一些與其餘技術相結合的DEMO和項目。首先,咱們創做動畫的基本文檔結構以下。github

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>canvas動畫序</title>
</head>
<body>
   <canvas id="canvas" width='500' height="500">
       <P>you browser not support canvas!</P>
   </canvas>
   <script>
       window.onload = function(){
       //咱們的代碼
       }
   </script>
</body>
</html>

在此咱們須要明白動畫的基本概念:
動畫實際上是由不一樣的靜態畫面組成,每一幅靜態畫面咱們叫作一幀(frame),當衆多的靜態畫面按照必定的規則快速運動時,咱們的眼睛就會欺騙咱們的大腦,從而造成物體運動的假象。在這裏先給你們展現用Canvas創做的兩個酷炫動畫,看看它是否夠簡潔,夠酷炫!web

一、百分比加載

第一個動畫是一個用Canvas作的百分比加載動畫(根據讀者的建議,已經對錯誤的代碼作了修改)。codePen地址canvas

圖片描述

var canvas = document.getElementById('canvas'),  //獲取canvas元素
    context = canvas.getContext('2d'),           //獲取畫圖環境,指明爲2d
    centerX = canvas.width/2,                    //Canvas中心點x軸座標
    centerY = canvas.height/2,                   //Canvas中心點y軸座標
    rad = Math.PI*2/100,                         //將360度分紅100份,那麼每一份就是rad度
    speed = 0.1;                                  //加載的快慢就靠它了
             
    //繪製藍色外圈
    function blueCircle(n){
        context.save();
        context.beginPath();
        context.strokeStyle = "#49f";
        context.lineWidth = 12;
        context.arc(centerX, centerY, 100 , -Math.PI/2, -Math.PI/2 + n*rad, false);
        context.stroke();
        context.restore();
    }
         
    //繪製白色外圈
    function whiteCircle(){
        context.save();
        context.beginPath();
        context.strokeStyle = "#A5DEF1";
        context.lineWidth = 12;
        context.arc(centerX, centerY, 100 , 0, Math.PI*2, false);
        context.stroke();
        context.closePath();
        context.restore();
    }
         
    //百分比文字繪製
    function text(n){
        context.save();
        context.fillStyle = "#F47C7C";
        context.font = "40px Arial";
        context.textAlign = "center";
        context.textBaseline = "middle";
        context.fillText(n.toFixed(0)+"%", centerX, centerY);
        context.restore();
   }
         
    //動畫循環
    (function drawFrame(){
         window.requestAnimationFrame(drawFrame, canvas);
         context.clearRect(0, 0, canvas.width, canvas.height);
             
         whiteCircle();
         text(speed);
         blueCircle(speed);
                
         if(speed > 100) speed = 0;
         speed += 0.1;
    }());
 </script>
</body>
</html>

在上面的代碼段中,咱們經過一個當即執行函數來執行咱們的動畫循環,並在內部經過數組

window.requestAnimationFrame(drawFrame, canvas);

循環調用自身,requestAnimationFrame是一個新的API,做用與setTimeInterval同樣,不一樣的是它會根據瀏覽器的刷新頻率自動調整動畫的時間間隔。在循環中咱們每次執行都會從新繪製藍色的圓弧,和白色的圓環和百分比加載的文字,因爲每次繪製的時間間隔很小,只有十幾毫秒(主要看電腦),因此咱們的肉眼是沒法清楚地分別每一幀的畫面,這樣就造成了咱們看到的動畫。該API的兼容處理以下:瀏覽器

if(!window.requestAnimationFrame){
    window.requestAnimationFrame =(window.webkitRequestAnimationFrame||
                                   window.mozRequestAnimationFrame||
                                   window.oRequestAnimationFrame||
                                   window.msRequestAnimationFrame||
                                   function(callback){
                                       return window.setTimeout(callback,1000/60); 
                                 });
    
}

二、黑客帝國(Matrix.js)

經典的黑客帝國效果,Geek們的最愛。目前,已經被我封裝成插件,可供你們方便使用。codePen地址 | 插件地址bash

圖片描述

具體代碼:dom

var canvas = document.querySelector('canvas'),
    context = canvas.getContext('2d'),
    w = canvas.width = window.innerWidth,
    h = canvas.height = window.innerHeight;
           
     //初始化
    var clearColor = 'rgba(0, 0, 0, .1)',             //用於繪製漸變陰影
        wordColor = "#33ff33",                         //文字顏色
        words = "0123456789qwertyuiopasdfghjklzxcvbnm,./;'\[]QWERTYUIOP{}ASDFGHJHJKL:ZXCVBBNM<>?",
        wordsArr = words.split(''),                 //將文字拆分進一個數組
        font_size = 16,  //字體大小
        clumns = w / font_size,                     //文字降落的列數
        drops = [];

     for(var i=0; i<clumns; i++){
         drops[i] = 1;
     }

   function draw(){
       context.save();
       context.fillStyle = wordColor;
       context.font = font_size + "px arial";
       //核心
       for (var i = 0; i < drops.length; i++){
            var text = wordsArr[Math.floor(Math.random() * wordsArr.length)];
                context.fillText(text, i * font_size, drops[i] * font_size);
                if (drops[i] * font_size > h && Math.random() > 0.98){
                        drops[i] = 0;
                }
                    drops[i]++;
        }
       context.restore();
  }
           
    //動畫循環
  (function drawFrame(){
        window.requestAnimationFrame(drawFrame, canvas);
        context.fillStyle = clearColor;
        context.fillRect(0, 0, w, h);  //注意這
        draw();
   }())

這段代碼有兩個比較核心的地方:
1,在初始化部分,咱們定義了一個變量clearColor = 'rgba(0, 0, 0, .1)',用於繪製陰影。其原理是:每當動畫繪製新的一幀,就在上面覆蓋一個透明度爲0.1的黑色矩形。隨着層數的疊加,文字就會被逐漸遮蓋造成了咱們看到的陰影。函數

2,在初始化的註釋處和核心模塊處。首先,設置了每一個字體的大小(font_size)。而後,用canvas的寬度除以字體的大小,就獲得了須要繪製的列數(clumns), 而後建立了一個數組drops,數組的長度爲clumns,而且每一個元素的值都爲1(drops在這有什麼用呢?繼續往下看)。在繪製部分,咱們採起的思路是一行一行的繪製,首先在循環中隨機的獲取文字,在文字繪製API部分注意這行代碼:

context.fillText(text, i * font_size, drops[i] * font_size);

咱們知道該API有三個參數,第一個是繪製的文字,第二,三是文字的座標。在X座標部分爲i * font_size,也就是說在循環完成後每一個文字的X軸座標是(0, 16, 32,48...), 而Y座標爲drops[i] * font_size因爲drops內元素的初始值都爲1,因此文字的Y座標爲(16, 16, 16, ...),這樣咱們就至關於先繪製了第一行的文字。那麼緊接着咱們繪製第二行只須要將drops中的元素加1便可,即(第二行的Y軸座標爲(32,32,32...)。
依次類推,咱們就繪製了滿屏的文字,經過漸變陰影咱們就能夠看到文字彷佛是向下運動的效果。爲了讓他們看上去運動的速度不一致,加上了這行代碼:

if (drops[i] * font_size > h && Math.random() > 0.98){
           drops[i] = 0;
 }

這行代碼判斷的是當前繪製的這行文字的Y座標是否超過了canvas的高度,若是超過又從第一行開始繪製,那麼如何讓他們出現差別性呢!小祕密在Math.random() > 0.98這,if中的兩個條件一個是判斷文字高度,另外一個是判斷一個隨機數是佛大於0.98,只有當兩個條件同時成立才能回到第一行從新繪製。因此,因爲第二個條件是隨機的,那麼差別性就天然而然的出現了!

看看,只須要這麼簡單的代碼就能寫出這麼酷炫的效果,是否是很贊!你也試試吧!不理解不要緊,這裏只是讓你看看canvas能作出多麼酷炫的效果。

下一節,咱們就正式開始咱們的Canvas動畫之旅!!!

相關文章
相關標籤/搜索