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 ...
随机推荐
- linux系统结构和系统命令初步
以上是第五课和第14课笔记 linux 基本结构: 系统构成:kernel,Modules,Lib,(Shell,Tool)系统引导:BIOS -> Bootlooder -> Kerne ...
- HDU 5492(DP) Find a path
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5492 题目大意是有一个矩阵,从左上角走到右下角,每次能向右或者向下,把经过的数字记下来,找出一条路径是 ...
- block(三)揭开神秘面纱(上)
block到底是什么 我们使用clang的rewrite-objc命令来获取转码后的代码. 1.block的底层实现 我们来看看最简单的一个block: [caption id="attac ...
- 25045操作标准子程序集41.C
/* ;程 序 最 后 修 改 时 间 0-4-3 23:43 ;软 件 标 题:25045操作标准子程序集41 ;软 件 说 明:25045 I2C 串行EEPROM 驱动 ;___________ ...
- 一道有关球赛队员分配的C++程序题目
题目描述: 两个球队进行比赛,各出三人.甲队为a,b,c三人,乙队为x,y,z三人.已经抽签决定比赛名单. 有人向队员打听比赛安排的名单.a说他不和x比,c说他不和x,z比,请编程找出三队赛手的名单. ...
- 我的Android进阶之旅------>Android拍照小例子
今天简单的学习了一下android拍照的简单实现. 当然该程序是个小例子,非常简单,没有什么复杂的操作,但是可以学习到Android 拍照API流程. 1.在布局文件中添加一个 surfaceView ...
- VBA清除Excelpassword保护,2003/2007/2010均适用
Sub Macro1() ' ' Breaks worksheet and workbook structure passwords. Jason S ' probably originator of ...
- linux中萌翻了的cowsay命令
想要让你的linux萌翻吗? 首先需要安装cowsay软件 命令如下:sudo apt-get update;sudo apt-get install cowsay 然后对其输入命令,默认情况下,动物 ...
- IoC容器Autofac正篇之类型注册(四)
Autofac类型注册 类型注册简单的从字面去理解就可以了,不必复杂化,只是注册的手段比较丰富. (一)类型/泛型注册 builder.RegisterType<Class1>(); 这种 ...
- NET中级课--文件,流,序列化3
1.序列化:将对象及状态保存起来. 反序列化就是逆操作. 2.NET提供了一个接口:System.runtime.serialization.IFormatter接口, 还有实现了这个接口的类Bina ...