前端动画-序列帧动画

来源:转载

前端写动画的情况不是很多,毕竟性能不是很好。一般网页动效,现在基本用css3就完成了。


这里说道说道 用 js脚本完成的动画。


可能很多刚入行的新手觉得写动画很复杂,有抵触心理,确实用脚本可能会涉及到一些逻辑及其设计模式,复杂的程序对技术水平要求比较高。


这里不会深入探究,只做简单引导,希望大家能快速上手写出绚丽吊炸天的动画特效.


废话太多,下面进入正题,本文先讲序列帧动画。


效果预览 源码地址
脚本动画原理

所谓动画,简单讲就是在时间轴上改动元素外貌或者位置。就好比手机拍摄视频,记录下景物的变化。


什么是序列帧

就是一帧一帧的图像文件,如这匹可爱的小马:



序列帧动画

把上面的小马从左到右,从上到下,播放一遍,每次展示一匹马的宽度和高度就成了动画


代码实现

为了提高性能,这里用canvas实现


新建index.html文件
<!DOCTYPE html>
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html; charset=utf-8">
<metaid="viewport"name="viewport"content="width=device-width,height=device-height,initial-scale=1,user-scalable=no">
<title>序列帧动画</title>
<styletype="text/css">
* {
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<!-- 画布容器 -->
<divid="donglegend"></div>
<scripttype="text/javascript">
//书写脚本
</script>
</body>
</html>

分析搭建代码框架

一切从简,面向过程开始


//需要一个主函数 main 作为 程序启动入口
functionmain(){}
//需要创建一个canvas画布
functionsetCanvas(){}
//需要加载图片
functionloadResource(){}
// 加载完图片需要 把图片画到画布
functiondraw(){}
// 需要一个主循环函数,就是一个定时器,不断刷新画布
functionloop(){}
// 在loop循环函数里调用 show函数(作用一会就知道了)
functionshow(){}
// 想想还缺少什么,为了方便画图片,可以写一个函数把图片按照区块 划分
functiondivideCoordinate(){}

具体功能函数实现
var _W = window.innerWidth,
_H = window.innerHeight,
_speed = 1000 / 10, //定时器执行频率
loopTimer = null, //保存定时器id
canvasObj = null, //画布
context = null, // 画布环境句柄
imageList = [], // 加载完图片存放地址
animateList = [], // 划分图片区域结果
animateAction = 0, // 序列帧图片第几行
animateCurframe = 0; // 序列帧图片某行第几帧
main();
functionmain(){
setCanvas("donglegend", _W, _H);
loadResource({
'id': 'dongsheng',
'src': 'images/dongsheng.jpg'
});
}
/**
* [setCanvas 创建画布]
* @param {[string]} id [元素容器]
* @param {[number]} w[画布宽度]
* @param {[number]} h[画布高度]
*/
functionsetCanvas(id, w, h){
var object = document.getElementById(id);
object.innerHTML = '<canvas id="' + id + '_canvas" width="' + _W +'" height="'+_H+'">' +
'</canvas>';
canvasObj = document.getElementById(id + "_canvas");
context = canvasObj.getContext("2d");
}
/**
* [loadResource 加载图片]
* @param{[object]} item [{id: "xx", src: "xx"}]
*/
functionloadResource(item){
var image = new Image();
image.onload = function(){
imageList[item.id] = image;
animateList = divideCoordinate(image.width, image.height, 2, 4);
loop();
}
image.src = item.src;
}
/**
* [divideCoordinate 按区域划分序列帧图片]
* @param{[type]} w [总宽度]
* @param{[type]} h [总高度]
* @param{[type]} row [总行数]
* @param{[type]} col [总列数]
* @return {[type]} [划分结果数组集]
*/
functiondivideCoordinate(w, h, row, col){
var i, j, cw = w / col, ch = h / row, r = [], c;
for (i = 0; i < row; i++) {
c = [];
for (j = 0; j < col; j++) {
c.push({x : cw * j, y : ch * i, width : cw, height : ch});
}
r.push(c);
}
return r;
};
/**
* [loop 程序主循环,控制页面不断刷新]
* @return {[type]} [description]
*/
functionloop(){
if (loopTimer) {
clearInterval(loopTimer);
}
loopTimer = setInterval(function(){
show();
}, _speed)
}
/**
* [show 清空画布,展示画布]
* @return {[type]} [description]
*/
functionshow(){
context.fillRect(0, 0, _W, _H);
draw(context, imageList['dongsheng'], animateList);
}
/**
* [draw 画图片到画布]
* @param{[type]} c[画布环境句柄]
* @param{[type]} bitmapData [图片资源]
* @param{[type]} list [划分区域数组]
*/
functiondraw(c, bitmapData, list){
if(animateCurframe >= list[animateAction].length-1){
animateCurframe = 0;
animateAction++;
if(animateAction > list.length-1){
animateAction = 0;
}
}else{
animateCurframe++;
}
var p = list[animateAction][animateCurframe];
c.drawImage(
bitmapData,
p.x,
p.y,
p.width,
p.height,
(_W - p.width)/2,
(_H - p.height)/3,
p.width,
p.height
)
}

结语

至此,最简单版本的序列帧动画就完成了,可以自己下载源码修改自己想要的效果


旨在理解动画的原理,后续会详细更新 位移动画,比如小球弹跳等等。


分享给朋友:
您可能感兴趣的文章:
随机阅读: