Canvas基礎-粒子動畫Part1

網頁上各類酷炫的粒子動畫看的人眼花繚亂,實際上原理卻很是簡單。javascript

獲取像素信息

首先咱們須要畫張圖到Canvas上,這裏由於我懶的扣圖(其實是不會),就找了張jpeg的白底圖片。實際上用png的透明圖會好不少。html

https://user-gold-cdn.xitu.io/2016/11/29/294750e6a92a0a929f7ac79a367fb2dd.jpg

必定要等圖片加載完再畫,這很重要,能夠用判斷圖片的complete屬性和設置onload方法來等圖片加載完才初始化。
另外繪製圖片是有跨域限制的,本地看的話,要麼你的圖片服務器支持跨域,要麼你就跑個本地服務器吧。java

var img = new Image();
    img.src = "images.jpeg";

    if(img.complete){
        init()
    } else {
        img.onload = function(){
            init()
        }
    }複製代碼

圖片獲取完以後咱們就能夠開始得到圖片的像素信息了,接口很簡單:git

context.getImageData(x,y,width,height)得到畫布上指定矩形的像素數據。github

ctx.drawImage(img, sx, sy);
    var imgData = ctx.getImageData(sx, sy, imgW, imgH);複製代碼

拿到像素數據,不要太簡單好嗎?! 由於這裏我是把圖片畫在畫布中間的,因此起始點不是(0,0),得到的矩形寬高則爲圖片的寬高。canvas

打印出來看看數據是什麼樣子的。跨域

https://user-gold-cdn.xitu.io/2016/11/29/f6edc1d8156f386772e2ec78d9acfad8.jpg

首先返回的是個ImageData對象,屬性有data和width,height,這還不是重點,data的類型是個Uint8ClampedArray(此處一臉蒙逼), 看起來是個二維數組,數組裏面一堆的數字是什麼鬼(二臉蒙逼)數組

還好有文檔:服務器

  • Uint8ClampedArray對象是一個8位無符號整數的類型化數組,裏面的值都是0-255。
  • 這堆數字表明的是rgba的值,可是每一個數字只表明一個,好比說第一個數字0,表明第一個像素的R值,第二個數字0表明第一個像素的G值,第三第四個0分別表明第一個像素的B值和Alpha值,最後出來第一個像素就是個全透明的顏色,第五個數字就表明第二個像素的R值了。

實際上,圖像是二維的,是由height決定行數,width決定列像素的行列式。post

作粒子動畫首先須要把圖片粒子化,把位置給找準,這樣出來的東西纔不會是亂七八糟的,因此咱們拿到每一個點的位置信息保存下來就能夠了。

for(var x=0; x<imgData.width; x+=6) {
        for(var y=0; y<imgData.height; y+=6) {
            var i = (y*imgData.width + x) * 4;
            if(imgData.data[i+3] > 128 && imgData.data[i] < 100){
                var dot = new Dot(x, y, 2);
                dotList.push(dot);
            }
        }
    }複製代碼

兩重循環就不說了,這裏有幾個地方簡單解釋一下:

  • 循環條件中有個x+=6,y+=6這裏爲何不是1呢?由於是作粒子化,每一個點之間須要有一些空隙纔看的出來,因此不用每一個點都拿,隔一段距離拿一個點就能夠了,這裏的6有點相似於取樣的概念。
  • 內側循環有個if判斷語句,[i+3]指的是像素中Alpha的值,大於128是用於過濾掉一些透明像素的。後面那個imgData.data[i] < 100由於我用的是個白底黑字的jpeg文件,因此還須要把不像黑色的像素過濾掉,由於大都只有黑白兩色,因此就簡單判斷了R值小於100,因此就像以前說的,仍是用png圖片比較好。
  • Dot對象是用來保存每取樣的個像素點信息的,這裏我只保存了x,y信息,第三個參數是半徑的值,這裏就直接寫死了2,實際上還能夠考慮保存像素點的rgba信息以及半徑作個隨機數。
function Dot(centerX, centerY, radius) {
        this.x = centerX;
        this.y = centerY;
        this.radius = radius;
    }複製代碼

最後一步就是把保存下來的信息畫到Canvas上。

function draw(){
        var imgW = img.width,
            imgH = img.height,
            sx = winWidth/2-imgW/2,
            sy = winHeight/2-imgH/2;

        ctx.clearRect(0, 0, winWidth, winHeight);

        ctx.fillStyle = "#000";

        for(var i=0; i<dotList.length; i+=1){
            curDot = dotList[i];
            ctx.save();
            ctx.beginPath();
            ctx.arc(sx+curDot.x, sy+curDot.y, curDot.radius, 0, 2*Math.PI);
            ctx.fill();
            ctx.restore();
        }
    }複製代碼

最後出來的效果:

https://user-gold-cdn.xitu.io/2016/11/29/d6ef6b2f1ac3aa3a6d05b1e91716fd88.jpg

粒子化基本就寫到這裏,下篇講講用粒子化的東西作動畫吧,最近事情比較多,懶癌又犯了。

源碼地址: github.com/bob-chen/ca…

Part 2 地址:gold.xitu.io/post/57dd27…

Part 3 地址: gold.xitu.io/post/57e7a7…

參考

www.w3school.com.cn/tags/canvas…

msdn.microsoft.com/zh-cn/libra…

www.cnblogs.com/axes/p/3500…

相關文章
相關標籤/搜索