canvas简单实现图片的粒子动画

试想一下,一张图片怎样取得每个像素点,在每个像素点上绘制一个粒子(圆)呢?或者说记录上每个像素点的位置?-----canvas提供了一种方法getImageData,我们来假设一个场景,首先是一张800X600的canvas画布,这张画布默认是白色的背景图,然后有一张600X400的png图片;那么首先的代码就应该是:

var canvas=document.getElementById("myCanvas");//获取canvas画布

var ctx=canvas.getContext("2d");//声明这个画布是2d
ctx.clearRect(0,0,canvas.width,canvas.height);//绘制之前先清空画布
var image = new Image();
image.src='201702081110069.png';//创建一张图片,并声明路径

现在的图片已经放上去了,但是还没有加载出来,更没有绘制到画布上,所以接下来就是要先让图片加载完成,然后绘制到画布上:

var imgData = null;
        image.onload = function(){//在图片加载完成后
            ctx.drawImage(image,0,0,400,400);//将图片绘制到画布上
            imgData=ctx.getImageData(0,0,400,400); //获取图表像素信息
        }

关键代码来了,getImageData里面就存储了我们需要的信息,那么我们就遍历这张图片的宽(600)和高(400),我们就能拿到整张图片的每个像素点,那么,透明部分我们就过滤掉!

            var pos=0;
            var data=imgData.data;    //RGBA的一维数组数据
            var nowNum=0;
            for(var i=1;i<=imgData.height;i++){
                for(var j=1;j<=imgData.width;j++){//遍历宽高
                    pos=(i-1)*imgData.width+(j-1); //取得像素位置
                    if(data[pos*4]>0){//开始过滤
                        var onePix= new Yuan(100,j,i);//创建一个圆,并把现在的宽高像素传递过去
                        copyPixels.push(onePix);//把创建好的圆放进一个数组里面
                    }
                }
            }
            //下面是圆的构造函数
            function Yuan(distance,j=rd(50,400),i=rd(50,400)){

                this.x = j; //当前J就是X轴的坐标, --->绘制时的实时位置
                this.y = i;//当前的i就是Y轴的坐标
                this.targetX = 0;//将要去的粒子位置
                this.targetY = 0;
                this.color = '#bbb';//定义粒子的颜色(其实在上面的遍历是可以拿到本身的颜色的,偷懒)
            }

当然,这只是阐述了方法,授人以鱼不如授人以渔.但是,相信很多同僚都是过来直接找代码赋值粘贴的,所以还是不多说了,上代码吧,如果有用,浪费你一秒钟帮我点个赞^_^!

 var pixels=[];  //存储第一张图片的粒子对象
 var copyPixels = [];//储存第一张图片的粒子对象
 var otherPixs = [];//存放了第二张图片的粒子对象
 // 粒子的构造函数
    function Yuan(distance,j=rd(50,400),i=rd(50,400)){
        this.x = j; //当前J就是X轴的坐标, --->绘制时的实时位置
        this.y = i;//当前的i就是Y轴的坐标
        this.targetX = 0;
        this.targetY = 0;
    }

//绘制方法
function drawPic(pixels){
        var canvas=document.getElementById("myCanvas");
        var ctx=canvas.getContext("2d");
        ctx.clearRect(0,0,canvas.width,canvas.height);//清除上一帧
        var len=pixels.length,curr_pixel=null;
        for(var i=0;i<len;i+=5){//相隔4个像素点画一个圆,减少粒子的生成
            curr_pixel=pixels[i];
            // ctx.fillStyle=curr_pixel.color;
            // ctx.fillRect(curr_pixel.x,curr_pixel.y,1,1);//第一种画圆方式
            ctx.beginPath();//第二种画圆方式
            ctx.strokeStyle = curr_pixel.color;
            ctx.arc(curr_pixel.x, curr_pixel.y,2, 0, Math.PI*2);
            ctx.fillStyle="curr_pixel.color";//填充颜色,默认是黑色
            ctx.fill();//画实心圆
            ctx.closePath()
        }
    }
//图1的绘制取点
function first(){
        var canvas=document.getElementById("myCanvas");
        var ctx=canvas.getContext("2d");
        var image = new Image();
        image.src='image1.png';
        var imageData;
        image.onload=function(){
            ctx.drawImage(image,0,0,400,400);//上下要一致
            imageData=ctx.getImageData(0,0,400,400);    //获取图表像素信息
            var pos=0;
            var data=imageData.data;    //RGBA的一维数组数据
            var nowNum=0;
            for(var i=1;i<=imageData.height;i++){
                for(var j=1;j<=imageData.width;j++){
                    pos=(i-1)*imageData.width+(j-1); //取得像素位置
                    if(data[pos*4]>0){
                        var pixel= new Yuan(500,j+600,i);
                        pixels.push(pixel);
                    }
                }
            }
            drawPic(pixels);  //绘制图像
        };
    }
//图形2绘制取点,并把图2的位置赋值给创建好的圆作为目标位置
    function second(){
        var canvas=document.getElementById("myCanvas");
        var ctx=canvas.getContext("2d");
        ctx.clearRect(0,0,canvas.width,canvas.height);
        var image = new Image();
        image.src='image2.png';
        var imgData = null;
        image.onload = function(){
            ctx.drawImage(image,0,0,400,400);
            imgData=ctx.getImageData(0,0,400,400);    //获取图表像素信息
            var pos=0;
            var data=imgData.data;    //RGBA的一维数组数据
            var nowNum=0;
            for(var i=1;i<=imgData.height;i++){
                for(var j=1;j<=imgData.width;j++){
                    pos=(i-1)*imgData.width+(j-1); //取得像素位置
                    if(data[pos*4]>0){
                        var onePix= new Yuan(100,j,i);
                        copyPixels.push(onePix);//把第二张图片的信息放入这个数组里面
                        if(pixels[nowNum]){
                            pixels[nowNum].targetX =copyPixels[nowNum].x;//把第二张图片的位置赋给粒子对象的目标位置
                            pixels[nowNum].targetY =copyPixels[nowNum].y;
                        }else{//第一张图的粒子数量不够,随机添加粒子
                            var addYuan = new Yuan(100);
                            addYuan.targetX = copyPixels[nowNum].x;
                            addYuan.targetY = copyPixels[nowNum].y;
                            pixels.push(addYuan);
                        }
                        nowNum++;
                    }
                }
            }
            if(pixels.length>copyPixels.length){//如果之前的所生成的粒子太多,让多余的粒子去一个位置
                for(var k=0;k<pixels.length;k++){
                    if(pixels[k].targetX ===0 && pixels[k].targetY ===0){
                        pixels[k].targetX = pixels[0].targetX ;
                        pixels[k].targetY = pixels[0].targetY ;
                    }else{
                        continue;
                    }
                }
            }
        }
    }
//点取完了,该进行动画了,清除上一帧,绘制下一帧,这就是动画
function animateTo(){
        //设置定时器 循环改变X,Y轴数据,然后重新绘制
        var num= 0;
        secondTimeId = setInterval(()=>{
            num= 0;//计数器,记录已经到达目标位置的粒子数量
            var leng = pixels.length;
            for(var i=0;i<leng;i++){
                if(pixels[i].x==pixels[i].targetX && pixels[i].y==pixels[i].targetY){
                    num++;
                    continue;
                }
                if(pixels[i].x<pixels[i].targetX){
                    pixels[i].x += rd(8,30);//每次刷新运动的随机距离
                    if(pixels[i].x>pixels[i].targetX){
                        pixels[i].x=pixels[i].targetX;
                    }
                }else{
                    pixels[i].x -= rd(8,30);
                    if(pixels[i].x<pixels[i].targetX){
                        pixels[i].x=pixels[i].targetX;
                    }
                }

                if(pixels[i].y<pixels[i].targetY){
                    pixels[i].y += rd(1,20);
                    if(pixels[i].y>pixels[i].targetY){
                        pixels[i].y=pixels[i].targetY;
                    }
                }else{
                    pixels[i].y -= rd(1,20);
                    if(pixels[i].y<pixels[i].targetY){
                        pixels[i].y=pixels[i].targetY;
                    }
                }
            }
            //结束掉定时器
            if(num == pixels.length){
                clearInterval(secondTimeId);
            }
            drawPic(pixels);
        },20)//每一帧刷新时间
    }
 //随机取整方式
    function rd(n,m){
        var c = m-n+1;
        return Math.floor(Math.random() * c + n);
    }
first();//执行第一个方法,页面执行的时候就会绘制出完整的图片
document.getElementById("myCanvas").onclick = function(){//注册点击事件
    second();
    animateTo();
}

最后,还要再啰嗦的问一句,赞点了吗?^_^

猜你喜欢

转载自blog.csdn.net/Arbort_/article/details/81295947
今日推荐