HTML5简单入门系列(九)
前言
上篇本来应该就是最后一篇了,但是楼主总觉得没有写上一个简单应用,不算是完整的学习系列。所以增加一篇关于动画的应用,对一个开源动画的介绍(很基础,非楼主原创)。
本篇介绍一个基于Canvas的发光加载动画(这里可下载源码)。算是对之前系列的各个知识点的一个总结吧。
我们先看看最终的效果截图:
新建一个html和一个js文件
html文件引入该js,并加了一个背景黑色,大体如下这样:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HTML5 Canvas发光Loading动画DEMO演示</title>
<style>
body {
background: #;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<script src="js/index.js"></script>
</body>
</html>
在画图之前,我们要确定一下简单的数据结构。
看效果图可以知道,我们是要画弧线,所有的动画都是基于这个弧线来操作的,那我们就要确定该弧线的坐标、半径、弧度起始点等。
要让其动起来,即旋转起来,我们需要旋转速度(弧度),当前旋转角度等。
我们整理成如下变量:
var c = document.getElementById('c'),
ctx = c.getContext('2d'),
cw = c.width = ,
ch = c.height = ,
rand = function (a, b) { return ~~((Math.random() * (b - a + )) + a); },//获取a到b之间的整数值
dToR = function (degrees) { return degrees * (Math.PI / ); },//角度变弧度
circle = {
x: (cw / ) + ,
y: (ch / ) + ,//圆心坐标
radius: ,//半径
speed: ,//旋转速度(角度)
rotation: ,//当前角度
angleStart: ,//圆弧起始弧度
angleEnd: ,//结束弧度
hue: ,//色调
thickness: ,//边缘粗细
blur: //模糊度
},
particles = [],//亮点数组
particleMax = ,//亮点个数
19-29行的变量示例中增加其他效果时会用到,这里可以暂时忽略。
画弧线
该弧线带有一个渐变效果,我们会用到的APIs有arc(),createLinearGradient()等,方法如下:
renderCircle = function () {
ctx.save();//保存当前作图上下文
ctx.translate(circle.x, circle.y);//移动坐标原点到圆心位置 ctx.beginPath();
ctx.arc(, , circle.radius, dToR(circle.angleStart), dToR(circle.angleEnd), true);
ctx.lineWidth = circle.thickness; var gradient1 = ctx.createLinearGradient(, -circle.radius, , circle.radius);
gradient1.addColorStop(, 'hsla(' + circle.hue + ', 60%, 50%, .25)');
gradient1.addColorStop(, 'hsla(' + circle.hue + ', 60%, 50%, 0)'); ctx.strokeStyle = gradient1;//弧线是渐变色
ctx.stroke();
ctx.restore();//画完弧线之后,画其他东西之前,先恢复作图上下文
},
这里就不截图看效果了,就是一条渐变弧线。
旋转
这里旋转其实就很简单了,只要不停地旋转角度,在画弧线之前调用旋转API rotate()就可以了。下边是代码:
updateCircle = function () {
if (circle.rotation < ) {
circle.rotation += circle.speed;
} else {
circle.rotation = ;
}
}
我们可以在画弧线的方法中加入旋转角度(renderCircle 方法第四行加上下边这句即可):
ctx.rotate(dToR(circle.rotation));//旋转角度,此处是动画动起来的地方。
说到这里,其实关于动画的内容就写的差不多了,只要一个定时器不停地调用这两个方法就好了。
不过,要注意一点,每次重新画图之前我们都要将canvas清空,我们调用clearRect或者统一写一个初始化方法即可,如下:
clear = function () {
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = 'rgba(0, 0, 0, .1)';
ctx.fillRect(, , cw, ch);
ctx.globalCompositeOperation = 'lighter';
}
定时器统一调用方法:
loop = function () {
clear();
updateCircle();
renderCircle();
}
设置定时器:
setInterval(loop, );
现在的效果已经出来了:
剩下的就是给弧线增加效果了。
该示例中为了更好地展示效果,设置了弧线边缘,头部发亮及小亮点显隐等多个效果,园友可运行代码查看效果。
完整的js代码如下:
/* super inefficient right now, could be improved */ //http://www.html5tricks.com/html5-canvas-shine-loading.html var c = document.getElementById('c'),
ctx = c.getContext('2d'),
cw = c.width = ,
ch = c.height = ,
rand = function (a, b) { return ~~((Math.random() * (b - a + )) + a); },//获取a到b之间的整数值
dToR = function (degrees) { return degrees * (Math.PI / ); },//角度变弧度
circle = {
x: (cw / ) + ,
y: (ch / ) + ,//圆心坐标
radius: ,//半径
speed: ,//旋转速度(角度)
rotation: ,//当前角度
angleStart: ,//圆弧起始弧度
angleEnd: ,//结束弧度
hue: ,//色调
thickness: ,//边缘粗细
blur: //模糊度
},
particles = [],//亮点数组
particleMax = ,//亮点个数 //更新旋转角度
updateCircle = function () {
if (circle.rotation < ) {
circle.rotation += circle.speed;
} else {
circle.rotation = ;
}
},
//画弧线
renderCircle = function () {
ctx.save();//保存当前作图上下文
ctx.translate(circle.x, circle.y);//移动坐标原点到圆心位置
ctx.rotate(dToR(circle.rotation));//旋转角度,此处是动画动起来的地方。
ctx.beginPath();
ctx.arc(, , circle.radius, dToR(circle.angleStart), dToR(circle.angleEnd), true);
ctx.lineWidth = circle.thickness; var gradient1 = ctx.createLinearGradient(, -circle.radius, , circle.radius);
gradient1.addColorStop(, 'hsla(' + circle.hue + ', 60%, 50%, .25)');
gradient1.addColorStop(, 'hsla(' + circle.hue + ', 60%, 50%, 0)'); ctx.strokeStyle = gradient1;//弧线是渐变色
ctx.stroke();
ctx.restore();//画完弧线之后,画其他东西之前,先恢复作图上下文
},
//弧线边缘效果
renderCircleBorder = function () {
ctx.save();
ctx.translate(circle.x, circle.y);
ctx.rotate(dToR(circle.rotation));
ctx.beginPath();
ctx.arc(, , circle.radius + (circle.thickness / ), dToR(circle.angleStart), dToR(circle.angleEnd), true);
ctx.lineWidth = ; var gradient2 = ctx.createLinearGradient(, -circle.radius, , circle.radius);
gradient2.addColorStop(, 'hsla(' + circle.hue + ', 100%, 50%, 0)');
gradient2.addColorStop(., 'hsla(' + circle.hue + ', 100%, 100%, .7)');
gradient2.addColorStop(, 'hsla(' + circle.hue + ', 100%, 50%, 0)'); ctx.strokeStyle = gradient2;
ctx.stroke();
ctx.restore();
},
//弧线顶点发亮
renderCircleFlare = function () {
ctx.save();
ctx.translate(circle.x, circle.y);
ctx.rotate(dToR(circle.rotation + ));
ctx.scale(, );
ctx.beginPath();
ctx.arc(, circle.radius, , , Math.PI * , false);
ctx.closePath();
var gradient3 = ctx.createRadialGradient(, circle.radius, , , circle.radius, );
gradient3.addColorStop(, 'hsla(330, 50%, 50%, .35)');
gradient3.addColorStop(, 'hsla(330, 50%, 50%, 0)');
ctx.fillStyle = gradient3;
ctx.fill();
ctx.restore();
},
//发亮延伸
renderCircleFlare2 = function () {
ctx.save();
ctx.translate(circle.x, circle.y);
ctx.rotate(dToR(circle.rotation + ));
ctx.scale(1.5, );
ctx.beginPath();
ctx.arc(, circle.radius, , , Math.PI * , false);
ctx.closePath();
var gradient4 = ctx.createRadialGradient(, circle.radius, , , circle.radius, );
gradient4.addColorStop(, 'hsla(30, 100%, 50%, .2)');
gradient4.addColorStop(, 'hsla(30, 100%, 50%, 0)');
ctx.fillStyle = gradient4;
ctx.fill();
ctx.restore();
},
//创建亮点
createParticles = function () {
if (particles.length < particleMax) {
particles.push({
x: (circle.x + circle.radius * Math.cos(dToR(circle.rotation - ))) + (rand(, circle.thickness * ) - circle.thickness),
y: (circle.y + circle.radius * Math.sin(dToR(circle.rotation - ))) + (rand(, circle.thickness * ) - circle.thickness),
vx: (rand(, ) - ) / ,
vy: (rand(, ) - ) / ,
radius: rand(, ) / ,
alpha: rand(, ) /
});
}
},
//更新已有亮点的坐标用于动态更随展示
//同时降低透明度,删除透明度过低(先创建的点调用该函数的次数最多,也就最容易变低)的亮点。
updateParticles = function () {
var i = particles.length;
while (i--) {
var p = particles[i];
p.vx += (rand(, ) - ) / ;
p.vy += (rand(, ) - ) / ;
p.x += p.vx;
p.y += p.vy;
p.alpha -= .; if (p.alpha < .) {
particles.splice(i, )
}
}
},
renderParticles = function () {
var i = particles.length;
while (i--) {
var p = particles[i];
ctx.beginPath();
ctx.fillRect(p.x, p.y, p.radius, p.radius);
ctx.closePath();
ctx.fillStyle = 'hsla(0, 0%, 100%, ' + p.alpha + ')';
}
},
clear = function () {
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = 'rgba(0, 0, 0, .1)';
ctx.fillRect(, , cw, ch);
ctx.globalCompositeOperation = 'lighter';
}
loop = function () {
clear();
updateCircle();
renderCircle();
renderCircleBorder();
renderCircleFlare();
renderCircleFlare2();
createParticles();
updateParticles();
renderParticles();
} ctx.shadowBlur = circle.blur;
ctx.shadowColor = 'hsla(' + circle.hue + ', 80%, 60%, 1)';
ctx.lineCap = 'round'; setInterval(loop, );
小结
本篇没有什么内容,只是一个简单应用。
其实在上篇状态的保存和恢复中那个示例就是一个简单动画了。
其实HTML5中动画也不算难,简单说就是画图+定时刷新,所以重点还是在HTML5 APIs的应用及与其他现有技术的交叉使用。
HTML5简单入门系列(九)的更多相关文章
- HTML5简单入门系列(五)
前言 本篇将讲述HTML5的服务器发送事件(server-sent event) Server-Sent 事件 Server-Sent 事件是单向消息传递,指的是网页自动获取来自服务器的更新. 以前的 ...
- HTML5简单入门系列(六)
前言 之前几篇已经将HTML5的主要新增元素和特性简单介绍完毕,LZ一直在犹豫还要不要把其他元素也写出来,因为其实没什么东西可以写,就是自己用到时看一下就行.不过为了入门系列的完整,犹豫再三,还是决定 ...
- HTML5简单入门系列(八)
前言 本篇介绍HTML5中相对复杂的一些APIs,其中的数学知识比较多.虽然如此,但是其实API使用起来还是比较方便的. 这里说明一下,只写出API相关的JS代码,因为他们都是基于一个canvas标签 ...
- HTML5简单入门系列(一)
前言 随着HTML5的流行,LZ作为一个web开发者,也决定学习一下前端前沿技术. HTML5 是下一代的HTML,它将成为 HTML.XHTML 以及 HTML DOM 的新标准.它是W3C( Wo ...
- HTML5简单入门系列(七)
前言 本篇详细介绍canvas画布的API.说是详细介绍,也只是一些常用的API及简单实例和说明.LZ本人也还没有看完全部,下篇会介绍剩余的一些内容. 本篇的示例中,LZ加入了注释,为的是只简单介绍A ...
- HTML5简单入门系列(四)
前言 今天这篇内容主要讲述HTML 5 Web Worker(一种支持前端js多线程的技术). 工作线程(Web Worker) web worker介绍 W3C 在 HTML5 的规范中提出了工作线 ...
- HTML5简单入门系列(三)
前言 本篇介绍HTML5支持的Web存储(Web Storage)和HTML 5 应用程序缓存. 客户端存储数据介绍 HTML5 提供了两种在客户端存储数据的新方法: localStorage - 没 ...
- HTML5简单入门系列(二)
前言 上篇中写到HTML5中的画布(canvas)元素,查看了canvas其他的资料,发现这个元素相关内容太多,鉴于本系列只是基础(主要是LZ也是初学),不再做太多介绍,有机会的话再单独写相关内容.说 ...
- 07. Web大前端时代之:HTML5+CSS3入门系列~H5 地理位置
Web大前端时代之:HTML5+CSS3入门系列:http://www.cnblogs.com/dunitian/p/5121725.html 源码:https://github.com/duniti ...
随机推荐
- hibernate集合映射inverse和cascade详解
hibernate集合映射inverse和cascade详解 1.到底在哪用cascade="..."? cascade属性并不是多对多关系一定要用的,有了它只是让我们在插入或 ...
- Linux下的正则表达式(基础)
grep -n 'the' text.txt 搜寻含有the的部分(n代表现实显示行号) grep -vn 'the' text.txt 搜寻不含有the的部分(n代表现实显示行号) grep -vn ...
- javascript第二课练习
<script type="text/javascript"> window.onload=function() //网页全部加载完后执行 { va ...
- IC封装形式COF介绍
其实这个真不太懂,没有太多接触也没有比较好的资料,只能简单的了解一下了. 什么是卷带式覆晶薄膜封装 COF(Chip on film) COF是一种 IC 封装技术,是运用软性基板电路(flexibl ...
- Windows PowerShell是啥?看完本文你就懂它了
这篇文章主要介绍了Windows PowerShell是啥?Windows PowerShell是什么?Windows PowerShell有哪些特性?Windows PowerShell有什么用?看 ...
- CF 578A A Problem about Polyline
题意: There is a polyline going through points (0, 0) – (x, x) – (2x, 0) – (3x, x) – (4x, 0) – ... - ( ...
- Linux常用命令及使用技巧
本文重点讲述Linux命令的使用,命令是学习Linux必须熟练掌握的一个部分.Linux下的命令大概有600个,而常用的命令其实只有80个左右,这些常用的命令是需要灵活掌握的.虽然Linux的各个发行 ...
- 原生AJAX如何异步提交数据?
AJAX概述 AJAX:Asynchronous Javascript And XML,异步的JS和XML.2001,Google为了改进搜索的用户体验,提出了GoogleSugguest效果,正式提 ...
- To Miss Our Children Time(dp)
To Miss Our Children Time Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Jav ...
- C++ 报错 R6030 CRT not initialized
昨天,在写一个算法的时候,报错R6030 CRT not initialized. 认真检查发现,是出了比较低级的错误. 一. 会出错的代码,编译的时候不会报错,执行过程中报R6030 CRT not ...