• JavaScript动画实例:粒子文本


    1.粒子文本的实现原理

          粒子文本的实现原理是:使用两张 canvas,一张是用户看不到的canvas1,用来绘制文本;另一张是用户看到的canvas2,用来根据canvas1中绘制的文本数据来生成粒子。

         先在canvas1中用如下的语句绘制待显示的文本。

        ctx1.font = '100px PingFang SC';

        ctx1.textAlign = 'center';

        ctx1.baseline = 'middle';

        ctx1.fillText('Happy New Year',canvas1.width/2, canvas1.height/2);

          然后使用canvas API的getImageData方法,获取一个ImageData对象,这个对象用来描述 canvas 指定区域内的像素数据。语句为:

           var imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data;

          这样imgData中保存了canvas1指定区域内所有像素点的rgba值,它是一个数组。由于每个像素点有 rgba 四个值,所以这个数组的长度也就是“像素点数量 * 4”。

          最后通过遍历imgData数组,可以判断在canvas1中,哪些点是有色彩的(处于文本中间),哪些点是没有色彩的(不在文本上),把那些有色彩的像素位置记下来,然后在用户可见canvas2上生成粒子并绘制粒子即可。具体编程遍历imgData数组时,可以根据透明度,也就是 rgba 中的第4个元素是否不为0来判断该像素是否在文本中。

          为此,创建一个自定义的粒子类Particle,该类中每个粒子对象有坐标位置(x,y)、半径radius和颜色color等4个属性;有一个方法draw(),用于绘制粒子。

    编写的HTML代码如下。

    <html>

    <head>

    <title>普通粒子文本</title>

    </head>

    <body>

    <canvas id="myCanvas1" style="position: absolute; " hidden></canvas>

    <canvas id="myCanvas2" style="position: absolute;"></canvas>

    <script>

       var canvas1=document.getElementById('myCanvas1');

       ctx1= canvas1.getContext('2d');

       var canvas2=document.getElementById('myCanvas2');

       ctx2= canvas2.getContext('2d');

       canvas1.width = canvas2.width = window.innerWidth;

       canvas1.height = canvas2.height = window.innerHeight;

       ctx1.font = '100px PingFang SC';

       ctx1.textAlign = 'center';

       ctx1.baseline = 'middle';

       ctx1.fillText('Happy New Year',canvas1.width/2, canvas1.height/2);

       var imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data;

       function  Particle(x,y,radius,color)

       {

            this.x = x;

            this.y = y;

            this.radius = radius;

            this.color = color;

        }

        Particle.prototype.draw= function()

        {

            ctx2.beginPath();

            ctx2.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);

            ctx2.fillStyle = this.color;

            ctx2.fill();

            ctx2.closePath();

        }

        var  particles = [];

        var  skip =1;

        for (var y = 0; y < canvas1.height; y +=skip)

        {

            for (var x = 0; x < canvas1.width; x += skip)

            {

                var opacityIndex = (x + y * canvas1.width) * 4 + 3;

                if (imgData[opacityIndex] > 0)

                {

                    var hue = Math.floor(Math.random() * 360);

                    var color=`hsl(${hue}, 100%, 50%)`;

                    particles.push(new Particle(x,y,2,color));

                }

            }

        }

        for (var particle of particles)

        {

            particle.draw();

        }

    </script>

    </body>

    </html>

          在浏览器中打开包含这段HTML代码的html文件,可以看到在浏览器窗口中绘制出如图1所示的粒子文本。

     

    图1  skip=1时显示的粒子文本

          由图1可以看出拼凑文本的粒子非常密集,这是因为程序中遍历的步长skip=1,这样扫描了canvas1指定区域内的所有像素点。实际上在形成粒子文本时,无需所有像素点一个像素一个像素地扫,可以增大skip值,使得最后产生的粒子稀疏些。

          例如,将程序中的语句“skip=1”修改为“skip=4”,则在浏览器窗口中绘制出如图2所示的粒子文本。

    图2  skip=4时显示的粒子文本

    2.粒子文本的动态效果

          了解了普通粒子文本的实现原理后,可以为拼凑文本的粒子添加一些动态动效。从2个方面着手。

          (1)给粒子赋予一些随机的位移,避免看上去过于整齐。

          (2)粒子的大小随机产生,在创建粒子时对粒子初始半径radius 进行random 取随机值。另外为了让粒子半径动态改变,增加一个属性dynamicRadius,代表粒子的渲染半径,它根据粒子的初始半径radius,采用三角函数进行平滑改变。

    编写如下的HTML代码。

    <html>

    <head>

    <title>粒子文本的动态效果</title>

    </head>

    <body>

    <canvas id="myCanvas1" style="position: absolute; " hidden></canvas>

    <canvas id="myCanvas2" style="position: absolute;"></canvas>

    <script>

       var canvas1=document.getElementById('myCanvas1');

       ctx1= canvas1.getContext('2d');

       var canvas2=document.getElementById('myCanvas2');

       ctx2= canvas2.getContext('2d');

       canvas1.width = canvas2.width = window.innerWidth;

       canvas1.height = canvas2.height = window.innerHeight;

       ctx1.font = '120px PingFang SC';

       ctx1.textAlign = 'center';

       ctx1.baseline = 'middle';

       ctx1.fillText('Happy New Year',canvas1.width/2, canvas1.height/2);

       var imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data;

       function  Particle(x,y,radius,color)

       {

            this.x = x;

            this.y = y;

            this.radius = radius;

            this.color = color;

            this.dynamicRadius = radius;

        }

        Particle.prototype.draw= function()

        {

            ctx2.beginPath();

            ctx2.arc(this.x, this.y,this.dynamicRadius, 0, 2 * Math.PI, false);

            ctx2.fillStyle = this.color;

            ctx2.fill();

            ctx2.closePath();

        }

        Particle.prototype.update= function()

        {

            this.dynamicRadius =3+2*Math.sin(new Date()/1000%1000*this.radius);

        }

        function random(min,max)

        {

           return Math.random() * ( max - min ) + min;

        }

        var  particles = [];

        var  skip =4;

        for (var y = 0; y < canvas1.height; y +=skip)

        {

            for (var x = 0; x < canvas1.width; x += skip)

            {

                var opacityIndex = (x + y * canvas1.width) * 4 + 3;

                if (imgData[opacityIndex] > 0)

                {

                    var hue = Math.floor(Math.random() * 360);

                    var color=`hsl(${hue}, 100%, 50%)`;

                    particles.push(new Particle(x+random(1,3),y+random(1,3),random(1,4),color));

                }

            }

        }

        for (var particle of particles)

        {

            particle.draw();

        }

        function loop()

        {

            requestAnimationFrame(loop);

            ctx2.clearRect(0,0,canvas2.width,canvas2.height);

            for (var particle of particles)

            {

               particle.update();

               particle.draw();

            }

        }

        loop();

    </script>

    </body>

    </html>

          在浏览器中打开包含这段HTML代码的html文件,可以看到在浏览器窗口中呈现出如图3所示的粒子文本动态效果。

     

    图3  粒子文本的动态效果 

  • 相关阅读:
    [leetcode]34.Find First and Last Position of Element in Sorted Array找区间
    [leetcode]278. First Bad Version首个坏版本
    [leetcode]367. Valid Perfect Square验证完全平方数
    [leetcode]45. Jump Game II青蛙跳(跳到终点最小步数)
    [leetcode]55. Jump Game青蛙跳(能否跳到终点)
    [leetcode]26. Remove Duplicates from Sorted Array有序数组去重(单个元素只出现一次)
    [leetcode]27. Remove Element删除元素
    [leetcode]20. Valid Parentheses有效括号序列
    [leetcode]15. 3Sum三数之和
    C#中的局部类型
  • 原文地址:https://www.cnblogs.com/cs-whut/p/13334882.html
Copyright © 2020-2023  润新知