關於canvas 粒子聚合成完整圖像的實例


這是在上篇隨筆的第三種方法下進行改進的。

上篇說到的方法是在easel.js的框架下寫的粒子不規則運動效果。

這是效果圖:

現在要做的,就是將這里面運動的粒子聚合在一起,形成一張完整的圖像。

這里我會把我實現的整個過程寫下來,最后會貼整個代碼,基本每行都會加上注釋,以便能快速看懂,寫的不好的地方希望能理解,以后多多改進。

寫這樣的效果,原理是很重要的,這其中最重要的就是 getImageData 這個方法。不明白這個方法的,可以去 http://www.w3school.com.cn/tags/canvas_getimagedata.asp 這里看明白后再繼續看下文。

         getImagedata:function(){
                    //這里是原生的方法
                    var c=document.getElementById("canvas");
                    var ctx=c.getContext("2d");
                    var img = new Image();
                    img.src="../img/111.png";
                    img.onload=function(){
                        //canvas里面插入圖像;
                        ctx.drawImage(img,0,0,page.imgWidth,page.imgHeight);
                        //獲取圖像每個像素的rgba
                        var imgData=ctx.getImageData(0,0,page.imgWidth,page.imgHeight);
                        //清除插入的圖像后執行主函數
                        ctx.clearRect(0,0,page.imgWidth,page.imgHeight);
                        page.canVas._canvas();
                        //將透明度大於50的像素點位置存入數組page.dots;
                        //x+=2,y+=2;隔一個像素點取值。
                        for(var x=0;x<page.imgWidth;x+=2){
                            for(var y=0;y<=page.imgHeight;y+=2){
                                var i = (y*imgData.width + x)*4;
                                if(imgData.data[i+3] >= 50){
                                    var dot=[];
                                    dot[0]=x;
                                    dot[1]=y;
                                    page.dots.push(dot);
                                }
                            }
                        }
                    }
                }

這段代碼的目的,就是獲取透明度大於50的像素點,並將他的位置存儲起來,以便后面的粒子能夠運動到該位置。

寫到這里,忽然就不想寫了,因為發現我代碼里基本都注釋好了。算了直接上代碼吧,這里上兩份完整的代碼,第一份是我做的時候用來過度的,我把它保留下來了,第二份是在第一份的基礎上,稍微改了幾行代碼,形成的最終效果。

第一份,用來過度的代碼:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>4</title>
    <meta name="format-detection" content="telephone=no">
    <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=0,minimum-scale=1.0,maximum-scale=1.0,minimal-ui" />
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <link rel="stylesheet" href="../css/main.css"/>
</head>
<body class="hidden re">
<canvas class="ab hide" id="canvascopy"></canvas>
<canvas class="ab" id="canvas"></canvas>

<script src="../js/zepto.min.1.js"></script>
<script src="../js/createjs-2015.11.26.min.js"></script>
<script>
    $(document).ready(function(){
        var pageH,pageW;
        page= {
            init: function () {
                ////阻止body滑動
                $('body').on("touchmove", function (e) {
                    e.preventDefault();
                });
                window.addEventListener("touchstart", function (e) {
                    e.preventDefault();
                });
                $(window).resize(function () {
                    page.resize();
                });
                //設置粒子生成的圖像的寬高
                page.imgWidth = 100;
                page.imgHeight = 100;
                //存儲用來生成圖像的粒子的位置
                page.dots=[];
                page.click=0;
                //用來存儲圓點
                page.circleArray=[];
                //設置圓點數量
                page.circleLength = 2000;
                page.resize();
                page.canVas.init();
            },
            canVas:{
                init:function(){
                    page.canVas.getImagedata();
                    //page.canVas._canvas();
                    //點擊屏幕粒子聚合,分散
                    $("body").on("click",function(){
                        page.click=!page.click;
                    })
                },
                _canvas:function(){
                    stage = new createjs.Stage("canvas");
                    //循環定義圓點的屬性;
                    for(var i= 0;i< page.circleLength;i++){
                        //隨機圓點顏色
                        var color = "rgba(" + Math.floor(Math.random()*255) + "," + Math.floor(Math.random()*255) + ","+ Math.floor(Math.random()*255) +","+Math.random()+")";
                        //隨機半徑
                        var radius = Math.random()+0.5;
                        //隨機初始位置
                        var x = Math.random()*pageW;
                        var y = Math.random()*pageH;
                        //隨機每個點的“移動速度跟方向”
                        var movex = (1-Math.random()*2)*0.5;
                        var movey = (1-Math.random()*2)*0.5;
                        //畫點
                        var particle = page.canVas._drawCircle(color, radius,x,y,movex,movey);
                        //將點存入數組,用於后面調用
                        page.circleArray.push(particle);
                        //添加形狀實例到舞台顯示列表
                        stage.addChild(particle);
                    }
                    //幀率
                    createjs.Ticker.setFPS(60);
                    //更新階段將呈現下一幀
                    createjs.Ticker.addEventListener("tick", page.canVas.tick);

                },
                //圓點函數
                _drawCircle:function(color, radius,x,y,movex,movey){
                    var particle = new createjs.Shape();
                    particle.graphics.beginFill(color).drawCircle(0, 0, radius);
                    particle.x = x;
                    particle.y = y;
                    particle.movex = movex;
                    particle.movey = movey;
                    return particle;

                },
                //圓點移動
                tick:function(){
                    //粒子游離
                    if(page.click==0){
                        page.canVas.animate(0)
                    }else{//粒子聚合成圖像
                        //粒子數大於圖像有效像素點數
                        if(page.dots.length<page.circleLength){
                            page.canVas.animate2(page.dots.length)
                            page.canVas.animate(page.dots.length)
                        }else{//粒子數小於圖像有效像素點數
                            page.canVas.animate2(page.circleLength)
                        }
                    }
                    //刷新
                    stage.update();
                },
                //粒子生成圖像的動畫;
                animate2:function(num){
                    for(var j= 0;j< num;j++){
                        //圖像居中
                        page.circleArray[j].x-=((page.circleArray[j].x-((page.dots[j][0])+(pageW/2-page.imgWidth/2)))/20);

                        page.circleArray[j].y-=((page.circleArray[j].y-((page.dots[j][1])+(pageH/2-page.imgHeight/2)))/20);
                    }
                },
                //初始動畫;
                animate:function(num){
                    for(var i= num;i< page.circleLength;i++){
                        //x軸方向,不同方向,不同速度移動
                        page.circleArray[i].x+=page.circleArray[i].movex;
                        //超出屏幕,從另一邊出來,循環
                        if(page.circleArray[i].x>=pageW){
                            page.circleArray[i].x=0
                        }else if(page.circleArray[i].x<=0){
                            page.circleArray[i].x=pageW
                        }
                        //Y軸方向,不同方向,不同速度移動
                        page.circleArray[i].y+=page.circleArray[i].movey;
                        if(page.circleArray[i].y>=pageH){
                            page.circleArray[i].y=0
                        }else if(page.circleArray[i].y<=0){
                            page.circleArray[i].y=pageH
                        }
                    }
                },
                //獲取有效像素點位置
                getImagedata:function(){
                    //這里是原生的方法
                    var c=document.getElementById("canvas");
                    var ctx=c.getContext("2d");
                    var img = new Image();
                    img.src="../img/111.png";
                    img.onload=function(){
                        //canvas里面插入圖像;
                        ctx.drawImage(img,0,0,page.imgWidth,page.imgHeight);
                        //獲取圖像每個像素的rgba
                        var imgData=ctx.getImageData(0,0,page.imgWidth,page.imgHeight);
                        //清除插入的圖像后執行主函數
                        ctx.clearRect(0,0,page.imgWidth,page.imgHeight);
                        page.canVas._canvas();
                        //將透明度大於50的像素點位置存入數組page.dots;
                        //x+=2,y+=2;隔一個像素點取值。
                        for(var x=0;x<page.imgWidth;x+=2){
                            for(var y=0;y<=page.imgHeight;y+=2){
                                var i = (y*imgData.width + x)*4;
                                if(imgData.data[i+3] >= 50){
                                    var dot=[];
                                    dot[0]=x;
                                    dot[1]=y;
                                    page.dots.push(dot);
                                }
                            }
                        }
                    }
                }
            },
            resize: function () {
                pageH = $(window).height();
                pageW = $(window).width();
                $(".page").width(pageW).height(pageH);
                $('canvas').attr('width', pageW).attr('height', pageH)
            }
        };
        page.init();
    });
</script>
</body>
</html>

這里得到的效果是這樣的:

這是鏈接:https://chuyunshi.github.io/Example/chuyunshi-canvas/demo/demo4.html

第二份:這是一份自己想要的效果,等有時間在給他改進改進,做點其他的效果

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>5</title>
    <meta name="format-detection" content="telephone=no">
    <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=0,minimum-scale=1.0,maximum-scale=1.0,minimal-ui" />
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <link rel="stylesheet" href="../css/main.css"/>
</head>
<body class="hidden re">
<canvas class="ab hide" id="canvascopy"></canvas>
<canvas class="ab" id="canvas"></canvas>

<script src="../js/zepto.min.1.js"></script>
<script src="../js/createjs-2015.11.26.min.js"></script>
<script>
    $(document).ready(function(){
        var pageH,pageW;
        page= {
            init: function () {
                ////阻止body滑動
                $('body').on("touchmove", function (e) {
                    e.preventDefault();
                });
                window.addEventListener("touchstart", function (e) {
                    e.preventDefault();
                });
                $(window).resize(function () {
                    page.resize();
                });
                //設置粒子生成的圖像的寬高
                page.imgWidth = 100;
                page.imgHeight = 100;
                //存儲用來生成圖像的粒子的位置
                page.dots=[];
                page.click=0;
                //用來存儲圓點
                page.circleArray=[];
                //設置圓點數量
                page.circleLength = 0;
                page.resize();
                page.canVas.init();
            },
            canVas:{
                init:function(){
                    page.canVas.getImagedata();
                    //page.canVas._canvas();
                    //點擊屏幕粒子聚合,分散
                    $("body").on("click",function(){
                        page.click=!page.click;
                    })
                },
                _canvas:function(){
                    stage = new createjs.Stage("canvas");
                    //循環定義圓點的屬性;
                    for(var i= 0;i< page.circleLength;i++){
                        //隨機圓點顏色
                        var color = "rgba(" + page.dots[i][2] + "," + page.dots[i][3] + ","+ page.dots[i][4] +","+page.dots[i][5]+")";
                        //隨機半徑
                        var radius = 1;
                        //隨機初始位置
                        var x = Math.random()*pageW;
                        var y = Math.random()*pageH;
                        //隨機每個點的“移動速度跟方向”
                        var movex = (1-Math.random()*2)*0.5;
                        var movey = (1-Math.random()*2)*0.5;
                        //畫點
                        var particle = page.canVas._drawCircle(color, radius,x,y,movex,movey);
                        //將點存入數組,用於后面調用
                        page.circleArray.push(particle);
                        //添加形狀實例到舞台顯示列表
                        stage.addChild(particle);
                    }
                    //幀率
                    createjs.Ticker.setFPS(60);
                    //更新階段將呈現下一幀
                    createjs.Ticker.addEventListener("tick", page.canVas.tick);

                },
                //圓點函數
                _drawCircle:function(color, radius,x,y,movex,movey){
                    var particle = new createjs.Shape();
                    particle.graphics.beginFill(color).drawCircle(0, 0, radius);
                    particle.x = x;
                    particle.y = y;
                    particle.movex = movex;
                    particle.movey = movey;
                    return particle;

                },
                //圓點移動
                tick:function(){
                    //粒子游離
                    if(page.click==0){
                        page.canVas.animate(0)
                    }else{//粒子聚合成圖像
                        //粒子數大於圖像有效像素點數
                        if(page.dots.length<page.circleLength){
                            page.canVas.animate2(page.dots.length)
                            page.canVas.animate(page.dots.length)
                        }else{//粒子數小於圖像有效像素點數
                            page.canVas.animate2(page.circleLength)
                        }
                    }
                    //刷新
                    stage.update();
                },
                //粒子生成圖像的動畫;
                animate2:function(num){
                    for(var j= 0;j< num;j++){
                        //圖像居中
                        page.circleArray[j].x-=((page.circleArray[j].x-((page.dots[j][0])+(pageW/2-page.imgWidth/2)))/20);

                        page.circleArray[j].y-=((page.circleArray[j].y-((page.dots[j][1])+(pageH/2-page.imgHeight/2)))/20);
                    }
                },
                //初始動畫;
                animate:function(num){
                    for(var i= num;i< page.circleLength;i++){
                        //x軸方向,不同方向,不同速度移動
                        page.circleArray[i].x+=page.circleArray[i].movex;
                        //超出屏幕,從另一邊出來,循環
                        if(page.circleArray[i].x>=pageW){
                            page.circleArray[i].x=0
                        }else if(page.circleArray[i].x<=0){
                            page.circleArray[i].x=pageW
                        }
                        //Y軸方向,不同方向,不同速度移動
                        page.circleArray[i].y+=page.circleArray[i].movey;
                        if(page.circleArray[i].y>=pageH){
                            page.circleArray[i].y=0
                        }else if(page.circleArray[i].y<=0){
                            page.circleArray[i].y=pageH
                        }
                    }
                },
                //獲取有效像素點位置
                getImagedata:function(){
                    //這里是原生的方法
                    var c=document.getElementById("canvas");
                    var ctx=c.getContext("2d");
                    var img = new Image();
                    img.src="../img/111.png";
                    img.onload=function(){
                        //canvas里面插入圖像;
                        ctx.drawImage(img,0,0,page.imgWidth,page.imgHeight);
                        //獲取圖像每個像素的rgba
                        var imgData=ctx.getImageData(0,0,page.imgWidth,page.imgHeight);
                        //清除插入的圖像后執行主函數
                        ctx.clearRect(0,0,page.imgWidth,page.imgHeight);
                        //將透明度大於50的像素點位置存入數組page.dots;
                        //x+=2,y+=2;隔一個像素點取值。
                        for(var x=0;x<page.imgWidth;x+=2){
                            for(var y=0;y<=page.imgHeight;y+=2){
                                var i = (y*imgData.width + x)*4;
                                if(imgData.data[i+3] >= 50){
                                    var dot=[];
                                    dot[0]=x;
                                    dot[1]=y;
                                    dot[2]=imgData.data[i];
                                    dot[3]=imgData.data[i+1];
                                    dot[4]=imgData.data[i+2];
                                    dot[5]=imgData.data[i+3];
                                    page.dots.push(dot);
                                }
                            }
                        }
                        //將粒子數設置成圖像有效像素點數(建議粒子數不要超過2000,數值太大,會卡死)
                        page.circleLength = page.dots.length;
                        page.canVas._canvas();
                    }
                }
            },
            resize: function () {
                pageH = $(window).height();
                pageW = $(window).width();
                $(".page").width(pageW).height(pageH);
                $('canvas').attr('width', pageW).attr('height', pageH)
            }
        };
        page.init();
    });
</script>
</body>
</html>

效果圖:

 

這是鏈接:https://chuyunshi.github.io/Example/chuyunshi-canvas/demo/demo5.html

以及多寫了個鏈接:https://chuyunshi.github.io/Example/chuyunshi-canvas/demo/demo6.html

不要改demo7.html了。這個是下篇的鏈接。//修改於2017/6/1/14:54

最后在這里說兩句,這些都是我在網上一點點拼湊,一點點磨出來的,找到別人寫的,基本都是沒注釋的,因為不知道他的思想,看他的代碼也是有些費勁。這里我寫注釋也不是為了讓別人看着方便,是為了讓自己以后能看懂,以前寫代碼,我基本是很少注釋的,自認為自己的結構很明確在這,不需要注釋。后來慢慢的就發現注釋還是很重要的。我寫這些東西,是因為我發現,想學好一樣新的東西,就要學着把它完整的介紹給下一個一點都不懂的人聽,並能夠讓他很好的學會,這樣才算自己也學好了,好吧,這個貌似我還沒學好。好的,我說完了。聚合,離散的效果,點擊屏幕就能看到,也懶得寫按鈕了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM