html烟⽕源码,HTML5:烟⽕
本次⽬标:在canvas画布上绘制彩⾊⼩球并实现模拟烟花般的动画效果。
程序很简单,只需要理解canvas元素,在指定位置⽤指定颜⾊绘制圆球然后逐帧形成动画就可以了。
考虑到性能因素,在球离开视觉区域或颜⾊完全变淡后就移除对象,并在每帧补上⼀定数量的球,这样也能够保证视觉效果。
演⽰效果如下(浏览器需⽀持HTML5):
源码如下(由于结构并不复杂,代码中的注释应该能解决⼤部分疑惑,代码后⾯附有简单解析。感兴趣的话不妨复制下来⾃⾏调试):
HTML5烟⽕
//配置参数
var maxballcount = 300 //⼩球最⼤数量
var ballradius = 4//⼩球半径
var startspeedx = 2//横向初速度范围(-x到x)
var startspeedy = 6//纵向初速度范围(向上,-y到0)
var gravity = 0.1 //重⼒加速度
var colorweaken = 0.008//颜⾊衰减速度
var newballcount = 4//每轮补球最⼤数量
var tail = 0.2//⼩球拖尾效果(1为⽆,0为拖尾不消失)
//全局对象
var canvas //绘图对象
var context //绘图内容
var imgData //当前图形
var balls = new Array() //⼩球数组
var framestarttime//计算帧数开始时间
var framecount = 0//上次计数清空以来经过的帧数
var lastframecount = 0//上⼀秒的帧数
//页⾯加载
$(function () {
init()
})
//初始化
function init() {
canvas = ElementById("image")
if (!Context) self.location = "/nohtml5.html"
else {
var container = $("#container")
container.width($(window).width())
container.height($(window).height())
canvas.width = container.width()
canvas.height = container.height()
context = Context("2d")
context.font = "16px Arial"
framestarttime = new Date()
//开始动画
animeframe()
}
}
//运⾏动画
function animeframe() {
//绘制半透明遮罩,淡化上⼀帧的颜⾊以达到拖尾效果
context.fillStyle = "rgba(0,0,0," + tail + ")"
context.fillRect(0, 0, canvas.width, canvas.height)
var newballs = new Array()//下⼀帧⼩球数组
for (var i in balls) {
var ball = balls[i]
ball.speedy += gravity//重⼒
ball.x += ball.speedx
ball.y += ball.speedy
ball.alpha -= colorweaken
if (ball.x > 0 && ball.x < canvas.width && ball.y > 0 && ball.y < canvas.height && ball.alpha > 0) { //只有⼩球在界内并尚未完全透明时才显⽰并保留到下⼀帧
newballs.push(ball)
drawball(ball)
}
}
//如果数量不⾜(初始,或有球出界),则补球,但不能超过最⼤数量
if (newballs.length < maxballcount) {
for (var i = 0; i < Math.min(newballcount, maxballcount - newballs.length); i++) {
newballs.push(generaterandomball())
}
}
//交换帧
balls = newballs
newballs = null
//计算并在左上⾓绘制帧数
var thisframetime = new Date()
if (thisframetime - framestarttime >= 1000) {
lastframecount = framecount
framecount = 0
framestarttime = thisframetime
}
framecount++
context.fillStyle = "#000"
context.fillRect(0, 0, 80, 40)
context.fillStyle = "#FF0"
context.fillText("FPS:" + lastframecount, 10, 20)
requestAnimationFrame(animeframe)
}
//绘制单个⼩球
function drawball(ball) {
if (!ball) return
context.beginPath()
context.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, true)
context.closePath()
context.fillStyle = "rgba(" + lor + "," + ball.alpha + ")"
context.fill()
}
//⽣成随机颜⾊和速度的球
function generaterandomball() {
var ball = new Object()
//初始位置在中央区域
ball.x = und(Math.random() * canvas.width / 10) + (canvas.width / 2 - canvas.width / 20) ball.y = und(Math.random() * canvas.height / 10) + (canvas.height / 2 - canvas.height / 20) ball.r = ballradius
ball.alpha = 1
//⼩球初速度,横向随机,纵向默认向上
ball.speedx = und(Math.random() * startspeedx * 2) - startspeedx
ball.speedy = -und(Math.random() * startspeedy)
return ball
}
//⽣成RGB字符串格式的颜⾊
function randomcolor() {
var yellow = und(Math.random() * 255)
return "255," + yellow + ",0"
}
body {
margin: 0px;
}
#container {
width: 100%;
height: 100%;
}
#image {
background-color: #000;
}
代码解析:
在设置各项基本参数的值之后,执⾏init()⽅法初始化页⾯;
初始化画布尺⼨和基本对象,然后执⾏animeframe()开始动画;
每个animeframe()显⽰⼀帧动画,结束后递归⾃⼰显⽰下⼀帧;
每帧要通过各⼩球的位置和速度计算运动轨迹,并计算重⼒加速度对纵向速度的影响;
canvas动画⼩球出界则从数组中移除。这⾥使⽤的是相反的⽅法:只有检测到在界内的才添加到新数组,循环完成后将新旧数组交换;
运动中的⼩球颜⾊逐渐变淡(增加alpha透明度);
使⽤drawball()⽅法绘制⼩球;
如果⼩球数量太少则补球;
⽣成随机球的⽅法是generaterandomball(),颜⾊在全红(255,0,0)到全黄(255,255,0)间随机选择。只需要第⼆个值取随机即可;每秒统计帧数并显⽰在左上⾓。
补注:旧版代码使⽤的是setTimeout实现动画。加⼊⼀段兼容性脚本后,改⽤requestAnimationFrame代替setTimeout来达到更好的性能,并在左上⾓加⼊帧数显⽰(⽤于测试不同浏览器和设备上的性能)
脚本如下(已保存到单独的requestAnimationFrame.js⽂件中):
//requestAnimationFrame动画⽅法的兼容性
(function() {
var lastTime = 0;
var vendors = ['webkit', 'moz'];
for(var x = 0; x < vendors.length && !questAnimationFrame; ++x) {
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || // Webkit中此取消
⽅法的名字变了
window[vendors[x] + 'CancelRequestAnimationFrame'];
}
if (!questAnimationFrame) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
var id = window.setTimeout(function() {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
}());

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。