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);

小结

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

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

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

时间: 2024-10-10 05:05:01

HTML5简单入门系列(九)的相关文章

HTML5简单入门系列(五)

前言 本篇将讲述HTML5的服务器发送事件(server-sent event) Server-Sent 事件 Server-Sent 事件是单向消息传递,指的是网页自动获取来自服务器的更新. 以前的做法是网页不断的询问(向服务器发送请求)是否有可用的更新.通过服务器反馈之后,获得更新. 轮训方案 我们使用上篇HTML5简单入门系列(四)web worker的技术简单实现一下该轮训方案,主动向服务器询问是否有更新. 由于web worker不能访问document等对象,是不能和jQuery连用

HTML5简单入门系列(六)

前言 之前几篇已经将HTML5的主要新增元素和特性简单介绍完毕,LZ一直在犹豫还要不要把其他元素也写出来,因为其实没什么东西可以写,就是自己用到时看一下就行.不过为了入门系列的完整,犹豫再三,还是决定简单写一下其他元素(看到其他深入的HTML5,LZ就不写到这里了,因为LZ也没掌握,这里有篇深入剖析HTML5,各位可以看看). HTML5 新增元素介绍 input类型 新增的输入类型元素有: email url number range Date pickers (date, month, we

HTML5简单入门系列(三)

前言 本篇介绍HTML5支持的Web存储(Web Storage)和HTML 5 应用程序缓存. 客户端存储数据介绍 HTML5 提供了两种在客户端存储数据的新方法: localStorage - 没有时间限制的数据存储 sessionStorage - 针对一个 session 的数据存储 sessionStorage存储的数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁.因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储. localStorag

HTML5简单入门系列

前言 本篇详细介绍canvas画布的API.说是详细介绍,也只是一些常用的API及简单实例和说明.LZ本人也还没有看完全部,下篇会介绍剩余的一些内容. 本篇的示例中,LZ加入了注释,为的是只简单介绍API确实挺无聊,也不那么容易理解,看代码看效果才最直接. canvas APIs canvas 基础api 介绍 在初始化Javascript函数中,用canvas标签的id获得canvas的DOM对象,并用getContext() 方法获得这个canvas的“2d”上下文对象,之后使用上下文对象调

HTML5简单入门系列(一)

前言 随着HTML5的流行,LZ作为一个web开发者,也决定学习一下前端前沿技术. HTML5 是下一代的HTML,它将成为 HTML.XHTML 以及 HTML DOM 的新标准.它是W3C( World Wide Web Consortium)和WHATWG(Web Hypertext Application Technology Working Group)合作的结果,在2014年10月29日宣布完成.他们为 HTML5 建立的一些规则:1.新特性应该基于 HTML.CSS.DOM 以及

HTML5简单入门系列(四)

前言 今天这篇内容主要讲述HTML 5 Web Worker(一种支持前端js多线程的技术). 工作线程(Web Worker) web worker介绍 W3C 在 HTML5 的规范中提出了工作线程(Web Worker)的概念,工作线程允许开发人员编写能够长时间运行而不被用户所中断的后台程序, 去执行事务或者逻辑,并同时保证页面对用户的及时响应.工作线程的出现使得在 Web 页面中进行多线程编程成为可能.众所周知,传统页面中(HTML5 之前)的 JavaScript 的运行都是以单线程的

03.Web大前端时代之:HTML5+CSS3入门系列~H5功能元素

Web大前端时代之:HTML5+CSS3入门系列:http://www.cnblogs.com/dunitian/p/5121725.html 2.功能元素 1.hgroup 对网页或区段(section)的标题进行组合 2.figure <figure> 标签规定独立的流内容(图像.图表.照片.代码等等). figure 元素的内容应该与主内容相关,但如果被删除,则不应对文档流产生影响. Figcaption figure的标题 一般格式: <figure> <figcap

04. Web大前端时代之:HTML5+CSS3入门系列~HTML5 表单

Web大前端时代之:HTML5+CSS3入门系列:http://www.cnblogs.com/dunitian/p/5121725.html ? 待续.... 04. Web大前端时代之:HTML5+CSS3入门系列~HTML5 表单

06. Web大前端时代之:HTML5+CSS3入门系列~HTML5 画布

Web大前端时代之:HTML5+CSS3入门系列:http://www.cnblogs.com/dunitian/p/5121725.html