阅读 1596

canvas文字粒子效果 3点饮茶,7点放工,美滋滋~

先言:

在这里插入图片描述

 今天3点多在饮茶的时候,发现有好几天没水文章了,但是太难的玩意又不会啊,咋办,突然想起电脑里还有存着一个文字粒子特效,好家伙,这不就来了,先看效果如下:

因为gif图最大5m,但是这东西演示完又不止5m,所以就用视频演示效果了~ BILINILI视频演示效果》

实现步骤(完整源码放在最后):

1.获取画布

 //获取画布
        var canvas = document.getElementById('canvas');
        var ctx = canvas.getContext('2d');
复制代码

2.绘制基本文字

 // 先在画布绘制一串文字,大小可以自己调,我这30px,6个字,大概搞个180px*30px的大小,背景色为黑色
        ctx.font = "30px fangsong";
        ctx.fillStyle = "rgb(0, 0, 0)";
        ctx.fillText("北极光之夜。",0,30,180); 
复制代码

3.获取文字的像素位置等

 // getImageData()可以获取画布上指定矩形的像素数据,把那上面文字所在区域的的像素保存起来
        var pix = ctx.getImageData(0,0,180,35);
复制代码

getImageData() 复制画布上指定矩形的像素数据。 getImageData() 方法返回 ImageData 对象,该对象拷贝了画布指定矩形的像素数据。 对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值: R - 红色 (0-255) G - 绿色 (0-255) B - 蓝色 (0-255) A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的) color/alpha 以数组形式存在,并存储于 ImageData 对象的 data 属性中。

4.画布动态适应屏幕大小

 // 画布动态适应屏幕大小
        window.addEventListener('resize',canvasResize);
        function canvasResize(){
            canvas.width = window.innerWidth;
          canvas.height = window.innerHeight;
        }
        canvasResize();
复制代码

5.设置变量

  // 这是等会绘制粒子文字的处于窗口大概位置
        var cx = canvas.width/2-(180*5/2);
        var cy = canvas.height/2-(35*5/2);
复制代码

6. 定义 Particle,实现粒子基本信息初始化方法,绘制粒子方法,更新位置方法

 //定义一个Particle类
        class Particle{
            constructor(){
                //定义一个数组,存放每个粒子的信息
                this.arr = [];
            }
            //初始化每个粒子信息
            init(){
               //循环,像素是以4个数据为一组的
                for(let i=0;i<pix.data.length/4;i++){
                     this.arr.push({
                        //文字像素本该的处于的水平位置
                        x:i%180,
                        //文字像素本该的处于的垂直位置
                        y:i/180,
                        // 透明度
                        alpha:pix.data[i*4+3],
                        //给个随机水平位置,粒子运动 mx ---》x
                        mx:Math.random()*canvas.width,
                         //给个随机垂直位置,粒子运动 my ---》y
                        my:Math.random()*canvas.height,
                        //粒子半径
                        radius:Math.random()*3,
                        //粒子速度
                        speed:Math.random()*40+40,
                        //粒子随机颜色
                        color:`rgba(${Math.random()*255}, ${Math.random()*255}, ${Math.random()*255},${pix.data[i*4+3]}`
                     })
                }
            }
            //绘制
            draw(){
                //遍历arr数组               
                this.arr.forEach(item=>{
                    //下面就是绘制每个小圆了
                    ctx.beginPath();
                    ctx.fillStyle = item.color;
                    ctx.arc(item.mx,item.my,item.radius,0,Math.PI*2,false);
                    ctx.fill();
                })
            }
            //粒子位置更新
            update(){
                   for(let i=0;i<this.arr.length;i++){
                       //粒子运动 mx ---》x , my ---》y , 采用缓动动画原理
                       //当然,如果粒子移动到原先的位置的话,岂不是太小,就文字就30px大小,所以位置改为x*5+cx,y*5+cy
                       this.arr[i].mx = this.arr[i].mx + ((this.arr[i].x*5+cx)-this.arr[i].mx)/this.arr[i].speed;
                       this.arr[i].my = this.arr[i].my + ((this.arr[i].y*5+cy)-this.arr[i].my)/this.arr[i].speed;
                   }
            }
        }      
复制代码

7. new一个 Particle,然后初始化

       const particle = new Particle();
       particle.init();
复制代码

8.执行粒子运动动画

 function step(){
        ctx.fillStyle = "rgba(0,0,0,0.1)";
          ctx.fillRect(0,0,canvas.width,canvas.height);
          particle.draw(); 
          particle.update(); 
         
          window.requestAnimationFrame(step);
       }
       window.requestAnimationFrame(step);
复制代码

window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。

9. 窗口大小改变重新初始化:

   window.addEventListener('resize',function(){
       particle.arr = [];  
       particle.init();
        cx = canvas.width/2-(180*5/2);
        cy = canvas.height/2-(35*5/2);
    })
复制代码

完整代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>北极光之夜。</title>
    <style>
        *{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body{
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: rgb(0, 0, 0);
        }
       
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <script>
        var canvas = document.getElementById('canvas');
        var ctx = canvas.getContext('2d');
        ctx.font = "30px fangsong";
        ctx.fillStyle = "rgb(0, 0, 0)";
        ctx.fillText("北极光之夜。",0,30,180); 
        var pix = ctx.getImageData(0,0,180,35);
        window.addEventListener('resize',canvasResize);
        function canvasResize(){
            canvas.width = window.innerWidth;
          canvas.height = window.innerHeight;
        }
        canvasResize();
        var cx = canvas.width/2-(180*5/2);
        var cy = canvas.height/2-(35*5/2);
        class Particle{
            constructor(){
                this.arr = [];
            }
            init(){
                for(let i=0;i<pix.data.length/4;i++){
                     this.arr.push({
                        x:i%180,
                        y:i/180,
                        alpha:pix.data[i*4+3],
                        mx:Math.random()*canvas.width,
                        my:Math.random()*canvas.height,
                        radius:Math.random()*3,
                        speed:Math.random()*40+40,
                        color:`rgba(${Math.random()*255}, ${Math.random()*255}, ${Math.random()*255},${pix.data[i*4+3]}`
                     })
                }
            }
            draw(){          
                this.arr.forEach(item=>{
                    ctx.beginPath();
                    ctx.fillStyle = item.color;
                    ctx.arc(item.mx,item.my,item.radius,0,Math.PI*2,false);
                    ctx.fill();
                })
            }
            update(){
                   for(let i=0;i<this.arr.length;i++){
                       this.arr[i].mx = this.arr[i].mx + ((this.arr[i].x*5+cx)-this.arr[i].mx)/this.arr[i].speed;
                       this.arr[i].my = this.arr[i].my + ((this.arr[i].y*5+cy)-this.arr[i].my)/this.arr[i].speed;
                   }
            }
        }      
       const particle = new Particle();
       particle.init();
   
       window.addEventListener('resize',function(){
           particle.arr = [];  
           particle.init();
            cx = canvas.width/2-(180*5/2);
            cy = canvas.height/2-(35*5/2);
        })

       function step(){
        ctx.fillStyle = "rgba(0,0,0,0.1)";
          ctx.fillRect(0,0,canvas.width,canvas.height);
          particle.draw(); 
          particle.update(); 
         
          window.requestAnimationFrame(step);
       }
       window.requestAnimationFrame(step);
    </script>
</body>
</html>
复制代码

总结:

大功告成,又可以继续饮茶了,饮到7点放工~

在这里插入图片描述 其它文章: 文字烟雾效果 html+css+js 环绕倒影加载特效 html+css 气泡浮动背景特效 html+css 简约时钟特效 html+css+js 赛博朋克风格按钮 html+css 仿网易云官网轮播图 html+css+js 水波加载动画 html+css 导航栏滚动渐变效果 html+css+js 书本翻页 html+css 3D立体相册 html+css 霓虹灯绘画板效果 html+css+js 记一些css属性总结(一) Sass总结笔记 ......等等 进我主页看更多~

文章分类
前端
文章标签