前言
上篇本来应该就是最后一篇了,但是楼主总觉得没有写上一个简单应用,不算是完整的学习系列。所以增加一篇关于动画的应用,对一个开源动画的介绍(很基础,非楼主原创)。
本篇介绍一个基于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启动过程
系统BIOS是当你点击开机键是第一个运行的程序.1. 首先主板需要接收到一个稳定的电源供给信号.如果没有得到稳定的电源供给系统自动关闭.2. 当接受到一个稳定的电源供给信号,处理器会启动,当处理器启动 ...
-
Myeclipse其实和Eclipse差不多的, 至少不输出来的项目时一模一样的
http://zhidao.baidu.com/link?url=LiaDdzRYJtarYvpL_co-Zgno31Az7QiS0VFxGm351K3gWa225oU6-NFEfkalJB3lGV6 ...
-
magento 图片缓存是如何生成的
Varien_Image_Adapter_Gd2 类 ,里面有个save()方法,通过图片格式拼出来的方法 call_user_func_array($this->_getCallback(' ...
-
1934. Black Spot(spfa)
1934 水题 RE了N久 后来发现是无向图 #include <iostream> #include<cstring> #include<algorithm> # ...
-
【转】.. Android应用内存泄露分析、改善经验总结
原文网址:http://wetest.qq.com/lab/view/107.html?from=ads_test2_qqtips&sessionUserType=BFT.PARAMS.194 ...
-
让WPF的Popup不总置顶的解决方案
使用WPF的Popup的时候会发现有一个问题,它总是会置顶,只要Popup的StayOpen不设置为False,它就一直呆在最顶端,挡住其他的窗口. 解决方案是继承Popup重新定义控件PopupEx ...
-
Python:对象
#!/usr/bin/python3 #对象实例 class Person: num=200 def __init__(self,name,sex): self.name=name self.sex= ...
-
Qt学习 之 数据库(支持10种数据库)
Qt 提供了 QtSql 模块来提供平*立的基于 SQL 的数据库操作.这里我们所说的“平*立”,既包括操作系统平台,有包括各个数据库平台.另外,我们强调了“基于 SQL”,因为 NoSQL 数据 ...
-
C#实现分页组件
分页无论是前端和后端,基本都有广泛应用!下面通过一个小小案例完成这个分页效果: 参数含义:string urlFormat: 要传给服务器端的URL地址格式,方便在点超链接时进行相应的跳转 long ...
-
yyyy-MM-dd&#39;T&#39;HH:mm:ss.SSS&#39;Z&#39;即UTC时间,与String日期转换
本文为博主原创,未经允许不得转载: 最近在使用一个时间插件的时候,接收到的时间格式是 ’2017-11-27T03:16:03.944Z’ ,当我进行双向数据绑定的时候,由后台传过来的时间绑定到时间 ...