• HTML5简单入门系列(九)


    前言

    上篇本来应该就是最后一篇了,但是楼主总觉得没有写上一个简单应用,不算是完整的学习系列。所以增加一篇关于动画的应用,对一个开源动画的介绍(很基础,非楼主原创)。

    本篇介绍一个基于Canvas的发光加载动画(这里可下载源码)。算是对之前系列的各个知识点的一个总结吧。 

    我们先看看最终的效果截图:


    新建一个html和一个js文件

    html文件引入该js,并加了一个背景黑色,大体如下这样:

     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>HTML5 Canvas发光Loading动画DEMO演示</title>
     6     <style>
     7         body {
     8             background: #000;
     9         }
    10     </style>
    11 </head>
    12 <body>
    13     <canvas id="c"></canvas>
    14     <script src="js/index.js"></script>
    15 </body>
    16 </html>

    在画图之前,我们要确定一下简单的数据结构。

    看效果图可以知道,我们是要画弧线,所有的动画都是基于这个弧线来操作的,那我们就要确定该弧线的坐标、半径、弧度起始点等。

    要让其动起来,即旋转起来,我们需要旋转速度(弧度),当前旋转角度等。

    我们整理成如下变量:

     1 var c = document.getElementById('c'),
     2 ctx = c.getContext('2d'),
     3 cw = c.width = 400,
     4 ch = c.height = 300,
     5 rand = function (a, b) { return ~~((Math.random() * (b - a + 1)) + a); },//获取a到b之间的整数值
     6 dToR = function (degrees) { return degrees * (Math.PI / 180); },//角度变弧度
     7 circle = {
     8 x: (cw / 2) + 5,
     9 y: (ch / 2) + 22,//圆心坐标
    10 radius: 90,//半径
    11 speed: 2,//旋转速度(角度)
    12 rotation: 0,//当前角度
    13 angleStart: 270,//圆弧起始弧度
    14 angleEnd: 90,//结束弧度
    15 hue: 220,//色调
    16 thickness: 18,//边缘粗细
    17 blur: 25//模糊度
    18 },
    19 particles = [],//亮点数组
    20 particleMax = 100,//亮点个数

    19-29行的变量示例中增加其他效果时会用到,这里可以暂时忽略。

    画弧线

    该弧线带有一个渐变效果,我们会用到的APIs有arc(),createLinearGradient()等,方法如下:

     1 renderCircle = function () {
     2         ctx.save();//保存当前作图上下文
     3         ctx.translate(circle.x, circle.y);//移动坐标原点到圆心位置
     4         
     5         ctx.beginPath();
     6         ctx.arc(0, 0, circle.radius, dToR(circle.angleStart), dToR(circle.angleEnd), true);
     7         ctx.lineWidth = circle.thickness;
     8 
     9         var gradient1 = ctx.createLinearGradient(0, -circle.radius, 0, circle.radius);
    10         gradient1.addColorStop(0, 'hsla(' + circle.hue + ', 60%, 50%, .25)');
    11         gradient1.addColorStop(1, 'hsla(' + circle.hue + ', 60%, 50%, 0)');
    12 
    13         ctx.strokeStyle = gradient1;//弧线是渐变色
    14         ctx.stroke();
    15         ctx.restore();//画完弧线之后,画其他东西之前,先恢复作图上下文
    16     },

    这里就不截图看效果了,就是一条渐变弧线。

    旋转

    这里旋转其实就很简单了,只要不停地旋转角度,在画弧线之前调用旋转API rotate()就可以了。下边是代码:

    1 updateCircle = function () {
    2         if (circle.rotation < 360) {
    3             circle.rotation += circle.speed;
    4         } else {
    5             circle.rotation = 0;
    6         }
    7     }

    我们可以在画弧线的方法中加入旋转角度(renderCircle 方法第四行加上下边这句即可):

    ctx.rotate(dToR(circle.rotation));//旋转角度,此处是动画动起来的地方。

    说到这里,其实关于动画的内容就写的差不多了,只要一个定时器不停地调用这两个方法就好了。

    不过,要注意一点,每次重新画图之前我们都要将canvas清空,我们调用clearRect或者统一写一个初始化方法即可,如下:

    1 clear = function () {
    2         ctx.globalCompositeOperation = 'destination-out';
    3         ctx.fillStyle = 'rgba(0, 0, 0, .1)';
    4         ctx.fillRect(0, 0, cw, ch);
    5         ctx.globalCompositeOperation = 'lighter';
    6     }

    定时器统一调用方法:

    1 loop = function () {
    2     clear();
    3     updateCircle();
    4     renderCircle();
    5 }

    设置定时器:

    setInterval(loop, 20);

    现在的效果已经出来了:

    剩下的就是给弧线增加效果了。

    该示例中为了更好地展示效果,设置了弧线边缘,头部发亮及小亮点显隐等多个效果,园友可运行代码查看效果。 

    完整的js代码如下:

      1 /* super inefficient right now, could be improved */
      2 
      3 //http://www.html5tricks.com/html5-canvas-shine-loading.html
      4 
      5 var c = document.getElementById('c'),
      6     ctx = c.getContext('2d'),
      7     cw = c.width = 400,
      8     ch = c.height = 300,
      9     rand = function (a, b) { return ~~((Math.random() * (b - a + 1)) + a); },//获取a到b之间的整数值
     10     dToR = function (degrees) { return degrees * (Math.PI / 180); },//角度变弧度
     11     circle = {
     12         x: (cw / 2) + 5,
     13         y: (ch / 2) + 22,//圆心坐标
     14         radius: 90,//半径
     15         speed: 2,//旋转速度(角度)
     16         rotation: 0,//当前角度
     17         angleStart: 270,//圆弧起始弧度
     18         angleEnd: 90,//结束弧度
     19         hue: 220,//色调
     20         thickness: 18,//边缘粗细
     21         blur: 25//模糊度
     22     },
     23     particles = [],//亮点数组
     24     particleMax = 100,//亮点个数
     25 
     26     //更新旋转角度
     27     updateCircle = function () {
     28         if (circle.rotation < 360) {
     29             circle.rotation += circle.speed;
     30         } else {
     31             circle.rotation = 0;
     32         }
     33     },
     34     //画弧线
     35     renderCircle = function () {
     36         ctx.save();//保存当前作图上下文
     37         ctx.translate(circle.x, circle.y);//移动坐标原点到圆心位置
     38         ctx.rotate(dToR(circle.rotation));//旋转角度,此处是动画动起来的地方。
     39         ctx.beginPath();
     40         ctx.arc(0, 0, circle.radius, dToR(circle.angleStart), dToR(circle.angleEnd), true);
     41         ctx.lineWidth = circle.thickness;
     42 
     43         var gradient1 = ctx.createLinearGradient(0, -circle.radius, 0, circle.radius);
     44         gradient1.addColorStop(0, 'hsla(' + circle.hue + ', 60%, 50%, .25)');
     45         gradient1.addColorStop(1, 'hsla(' + circle.hue + ', 60%, 50%, 0)');
     46 
     47         ctx.strokeStyle = gradient1;//弧线是渐变色
     48         ctx.stroke();
     49         ctx.restore();//画完弧线之后,画其他东西之前,先恢复作图上下文
     50     },
     51     //弧线边缘效果
     52     renderCircleBorder = function () {
     53         ctx.save();
     54         ctx.translate(circle.x, circle.y);
     55         ctx.rotate(dToR(circle.rotation));
     56         ctx.beginPath();
     57         ctx.arc(0, 0, circle.radius + (circle.thickness / 2), dToR(circle.angleStart), dToR(circle.angleEnd), true);
     58         ctx.lineWidth = 2;
     59 
     60         var gradient2 = ctx.createLinearGradient(0, -circle.radius, 0, circle.radius);
     61         gradient2.addColorStop(0, 'hsla(' + circle.hue + ', 100%, 50%, 0)');
     62         gradient2.addColorStop(.1, 'hsla(' + circle.hue + ', 100%, 100%, .7)');
     63         gradient2.addColorStop(1, 'hsla(' + circle.hue + ', 100%, 50%, 0)');
     64 
     65         ctx.strokeStyle = gradient2;
     66         ctx.stroke();
     67         ctx.restore();
     68     },
     69     //弧线顶点发亮
     70     renderCircleFlare = function () {
     71         ctx.save();
     72         ctx.translate(circle.x, circle.y);
     73         ctx.rotate(dToR(circle.rotation + 185));
     74         ctx.scale(1, 1);
     75         ctx.beginPath();
     76         ctx.arc(0, circle.radius, 30, 0, Math.PI * 2, false);
     77         ctx.closePath();
     78         var gradient3 = ctx.createRadialGradient(0, circle.radius, 0, 0, circle.radius, 30);
     79         gradient3.addColorStop(0, 'hsla(330, 50%, 50%, .35)');
     80         gradient3.addColorStop(1, 'hsla(330, 50%, 50%, 0)');
     81         ctx.fillStyle = gradient3;
     82         ctx.fill();
     83         ctx.restore();
     84     },
     85     //发亮延伸
     86     renderCircleFlare2 = function () {
     87         ctx.save();
     88         ctx.translate(circle.x, circle.y);
     89         ctx.rotate(dToR(circle.rotation + 165));
     90         ctx.scale(1.5, 1);
     91         ctx.beginPath();
     92         ctx.arc(0, circle.radius, 25, 0, Math.PI * 2, false);
     93         ctx.closePath();
     94         var gradient4 = ctx.createRadialGradient(0, circle.radius, 0, 0, circle.radius, 25);
     95         gradient4.addColorStop(0, 'hsla(30, 100%, 50%, .2)');
     96         gradient4.addColorStop(1, 'hsla(30, 100%, 50%, 0)');
     97         ctx.fillStyle = gradient4;
     98         ctx.fill();
     99         ctx.restore();
    100     },
    101     //创建亮点
    102     createParticles = function () {
    103         if (particles.length < particleMax) {
    104             particles.push({
    105                 x: (circle.x + circle.radius * Math.cos(dToR(circle.rotation - 85))) + (rand(0, circle.thickness * 2) - circle.thickness),
    106                 y: (circle.y + circle.radius * Math.sin(dToR(circle.rotation - 85))) + (rand(0, circle.thickness * 2) - circle.thickness),
    107                 vx: (rand(0, 100) - 50) / 1000,
    108                 vy: (rand(0, 100) - 50) / 1000,
    109                 radius: rand(1, 6) / 2,
    110                 alpha: rand(10, 20) / 100
    111             });
    112         }
    113     },
    114     //更新已有亮点的坐标用于动态更随展示
    115     //同时降低透明度,删除透明度过低(先创建的点调用该函数的次数最多,也就最容易变低)的亮点。
    116     updateParticles = function () {
    117         var i = particles.length;
    118         while (i--) {
    119             var p = particles[i];
    120             p.vx += (rand(0, 100) - 50) / 750;
    121             p.vy += (rand(0, 100) - 50) / 750;
    122             p.x += p.vx;
    123             p.y += p.vy;
    124             p.alpha -= .01;
    125 
    126             if (p.alpha < .02) {
    127                 particles.splice(i, 1)
    128             }
    129         }
    130     },
    131     renderParticles = function () {
    132         var i = particles.length;
    133         while (i--) {
    134             var p = particles[i];
    135             ctx.beginPath();
    136             ctx.fillRect(p.x, p.y, p.radius, p.radius);
    137             ctx.closePath();
    138             ctx.fillStyle = 'hsla(0, 0%, 100%, ' + p.alpha + ')';
    139         }
    140     },
    141     clear = function () {
    142         ctx.globalCompositeOperation = 'destination-out';
    143         ctx.fillStyle = 'rgba(0, 0, 0, .1)';
    144         ctx.fillRect(0, 0, cw, ch);
    145         ctx.globalCompositeOperation = 'lighter';
    146     }
    147 loop = function () {
    148     clear();
    149     updateCircle();
    150     renderCircle();
    151     renderCircleBorder();
    152     renderCircleFlare();
    153     renderCircleFlare2();
    154     createParticles();
    155     updateParticles();
    156     renderParticles();
    157 }
    158 
    159 
    160 ctx.shadowBlur = circle.blur;
    161 ctx.shadowColor = 'hsla(' + circle.hue + ', 80%, 60%, 1)';
    162 ctx.lineCap = 'round';
    163 
    164 setInterval(loop, 20);
    View Code

      

    小结

    本篇没有什么内容,只是一个简单应用。

    其实在上篇状态的保存和恢复中那个示例就是一个简单动画了。

    其实HTML5中动画也不算难,简单说就是画图+定时刷新,所以重点还是在HTML5 APIs的应用及与其他现有技术的交叉使用。 

  • 相关阅读:
    关于Ubuntu下在线安装Python 以python3.6为例
    PythonGUI入门一_Tkinter模块的参数
    通过浏览器实现Ubuntu下的Jupyter交互
    Python 与 匿名函数
    抓取猎聘网 职位与职位网址
    reactrouterdomV5和V6比较
    IDEA报Error:(4, 46) java: 程序包org.springframework.boot.autoconfigure不存在问题问题解决
    C++)错误提示 c2352 :非静态成员函数的非法调用
    osg roll pitch heading
    【北亚服务器数据恢复】DELL Eq PS系列服务器硬盘坏道的数据恢复案例
  • 原文地址:https://www.cnblogs.com/cotton/p/4422147.html
Copyright © 2020-2023  润新知