1. 程式人生 > >canvas製作動態文字顆粒動畫

canvas製作動態文字顆粒動畫

久違的想玩下,且回顧下canva顆粒動畫製作,在codepen中找了個小案例,看了下原始碼,學習下,覺得很不錯,拿出來給大家分享下:

一、最終預覽效果:


二、核心程式碼邏輯

1. 初始化canvas畫布大小
2. canvas繪製文字,設定文字大小,文字位置
3. 繫結滑鼠事件
4. 獲取畫布內文字畫素點資料存入顆粒物件陣列
5. 更新繪製,更改 x, y的值,指定規則檢測結束狀態

三、核心程式碼 

function Banner(){
    
    var keyword = "MY LOVE";
    var canvas;
    var context;
    
    var bgCanvas;
    var bgContext;
    
    var denseness = 10;
    
    //Each particle/icon
    var parts = [];
    
    var mouse = {x:-100,y:-100};
    var mouseOnScreen = false;
    
    var itercount = 0;
    var itertot = 40;
    
    // 初始化canvas寬高
    this.initialize = function(canvas_id){

        canvas = document.getElementById_x_x(canvas_id);
        context = canvas.getContext('2d');
        
        canvas.width = document.body.clientWidth;
        canvas.height = document.body.clientHeight;
        
        bgCanvas = document_createElement_x_x('canvas');
        bgContext = bgCanvas.getContext('2d');

        bgCanvas.width = canvas.width;
        bgCanvas.height = canvas.height;
    
        canvas.addEventListener('mousemove', MouseMove, false);
        canvas.addEventListener('mouseout', MouseOut, false);
            
        start();
    }
    
    // 繪製文字
    var start = function(){
            
        bgContext.fillStyle = "#000";
        bgContext.font = '300px impact';
        bgContext.fillText(keyword, 85, 275);
        
        clear();    
        getCoords();
    }
    
    //獲取畫布內畫素點資料
    var getCoords = function(){
        
        var imageData, pixel, height, width;
        
        imageData = bgContext.getImageData(0, 0, canvas.width, canvas.height);
        // console.log(imageData.data.length); //3139560

        // quickly iterate over all pixels - leaving density gaps
        for(height = 0; height < bgCanvas.height; height += denseness){
            for(width = 0; width < bgCanvas.width; width += denseness){   
                pixel = imageData.data[((width + (height * bgCanvas.width)) * 4) - 1];

                // pixel is black from being drawn on.
                // 當檢索到每個畫素灰度為255不為0 -> 確定是文字區域 -> 繪製圈
                
                if(pixel == 255) {
                    drawCircle(width, height);
                }
            }
        }
        
        setInterval( update, 40 );
    }
    
    // 繪製圓
    var drawCircle = function(x, y){
        
        var startx = (Math.random() * canvas.width);
        var starty = (Math.random() * canvas.height);
        
        var velx = (x - startx) / itertot;
        var vely = (y - starty) / itertot;  
        
        parts.push(
            {c: '#' + (Math.random() * 0x949494 + 0xaaaaaa | 0).toString(16),
             x: x, //goal position
             y: y,
             x2: startx, //start position
             y2: starty,
             r: true, //Released (to fly free!)
             v: {x:velx , y: vely}
            }
        )
    }
    
    // 重複繪製
    var update = function(){
        var i, dx, dy, sqrDist, scale;
        itercount++;
        clear();
        
        for (i = 0; i < parts.length; i++){
                    
            //If the dot has been released
            if (parts[i].r == true){
                //Fly into infinity!!
                parts[i].x2 += parts[i].v.x;
                parts[i].y2 += parts[i].v.y;
            //Perhaps I should check if they are out of screen... and kill them?
            }
            
            if (itercount == itertot){

                parts[i].v = {x:(Math.random() * 6) * 2 - 6 , y:(Math.random() * 6) * 2 - 6};
                //console.log(parts[i].v)
                parts[i].r = false;
            }
               
            //Look into using svg, so there is no mouse tracking.
            //Find distance from mouse/draw!
            dx = parts[i].x - mouse.x;
            dy = parts[i].y - mouse.y;
            sqrDist =  Math.sqrt(dx*dx + dy*dy);
            
            if (sqrDist < 20){
                parts[i].r = true;
            }           

            //Draw the circle
            context.fillStyle = parts[i].c;
            context.beginPath();
            context.arc(parts[i].x2, parts[i].y2, 4 ,0 , Math.PI*2, true);
            context.closePath();
            context.fill(); 
        }   
    }
    
    //滑鼠移動事件監聽函式
    var MouseMove = function(e) {
        if (e.layerX || e.layerX == 0) {
            //Reset particle positions
            mouseOnScreen = true;
        
            mouse.x = e.layerX - canvas.offsetLeft;
            mouse.y = e.layerY - canvas.offsetTop;
        }
    }
    
    // 滑鼠移除事件監聽函式
    var MouseOut = function(e) {
        mouseOnScreen = false;
        mouse.x = -100;
        mouse.y = -100; 
    }
    
    // 清除畫布
    var clear = function(){
        context.fillStyle = '#333';
        context.beginPath();
        context.rect(0, 0, canvas.width, canvas.height);
        context.closePath();
        context.fill();
    }

}

var banner = new Banner();
banner.initialize("canvas");