使用generator生成排序动画
相信作为一个程序猿,大家应该都已经看过一些排序算法的过程教学动画,现在我来总结一下自己使用ES6的generator实现动画的过程,以作为自己对generator的使用实践的一个记录。
为什么用generator实现?
因为对于计算机而言排序是一个十分短暂的过程,然而动画却不是。动画的生成需要获取当前帧的状态,也就是当前数列的状态,若是我们在计算过程中插入动画的播放,也就是在交换时播放交换动画,由于动画播放是异步的,当你完成了这一次的交换两个数的动画播放,排序已经完成了,数列的状态已经是有序,你已经无法在根据数列状态生成后面的动画并播放。有人可能想到,那可以等到动画播放完再进行下一次的比较和交换,然而我并没有想到如何监听交换动画结束的状态的方法,所以我没有实现这种动画播放的同步化。
一个解决方法时,计算过程中发生交换,不播放动画,只生成动画的“帧”并保存,等排序完毕,"帧”也全部生成完毕,然后逐帧显示形成动画就可以了。但是这种方法缺点在于需要保存帧的数据,也就是每一瞬间动画的状态。因此可以每生成一帧便渲染一次,渲染完后再进行后面的比较和交换。但是这样帧与帧之间的时间间隔变得难以控制,因为你在渲染完这帧后渲染下一帧的时间就是继续开始计算并发生下一次交换并生成帧数据的时间,这个时间十分短,几乎接近0,因此这样的动画是不可控并且短暂的。若是想让帧与帧之间固定一个时间间隔,就必须使用setTimeout()或setInterval(),但这样又会产生之前的异步问题了。因此可以使用generator,了解generator的应该明白,它是一个状态机,代表函数内部的执行状态,当执行到某一语句时就会将这个状态“冻结",并且返回该语句的结果,只有调用generator的next()方法,才能继续执行函数内部语句直到下一个"冻结"产生为止。这里我利用了generator的"冻结”特性,当需要交换时,冻结状态,进行两个数交换动画的渲染和播放,这里我可以设置这个交换动画有多少帧,多长时间后进行下一次交换的计算(我用的setInterval,在回调函数中调用next进行下一次交换的计算)。
代码如下(只是部分关键代码):
function* bubbleSort(array, compare, sorter) {
let i = 0, j = 0, l = array.length;
for (i = 0; i < l; ++i) {
for (j = 0; j < l - i - 1; ++j) {
if (!compare(array[j], array[j + 1])) {
yield* swap(j, j + 1, sorter); //嵌套generator函数
[array[j], array[j + 1]] = [array[j + 1], array[j]];
[sorter.states[j], sorter.states[j + 1]] = [sorter.states[j + 1], sorter.states[j]];
}
}
}
}
function* swap(a, b, sorter) {
yield* rise(a, b, sorter); //交换上升动画
yield* move(a, b, sorter); //交换平移动画
yield* down(a, b, sorter); //交换下降动画
}
function *rise(a, b, sorter) {
let stateA = sorter.states[a],
stateB = sorter.states[b];
//一次循环更新一次状态,形成一个新帧的信息
for (let i = 1; i <= FRAME_NUMBER; ++i) {
stateA.y -= sorter.divideLineHeight / FRAME_NUMBER;
stateB.y -= sorter.divideLineHeight / FRAME_NUMBER;
yield; //“冻结”状态,进行渲染
}
}
function *down(a, b, sorter) {
let stateA = sorter.states[a],
stateB = sorter.states[b];
for (let i = 1; i <= FRAME_NUMBER; ++i) {
stateA.y += sorter.divideLineHeight / FRAME_NUMBER;
stateB.y += sorter.divideLineHeight / FRAME_NUMBER;
yield;
}
}
function *move(a, b, sorter) {
let stateA = sorter.states[a],
stateB = sorter.states[b],
p = sorter.numbers[a] < sorter.numbers[b],
dist = Math.abs(stateA.x - stateB.x);
for (let i = 0; i < FRAME_NUMBER; ++i) {
if (!p) {
stateA.x += dist / FRAME_NUMBER;
stateB.x -= dist / FRAME_NUMBER;
} else {
stateA.x += dist / FRAME_NUMBER;
stateB.x -= dist / FRAME_NUMBER;
}
yield;
}
}
sort(type) {
if (type == sortType.bubble) {
this.sort = bubbleSort(this.numbers, (a, b) => {
return a - b < 0;
}, this);
}
this.animation = setInterval((() => {
//此语句是进行generator更新,若generator到达最后一个状态,停止动画
if (this.sort.next().done) {
clearInterval(this.animation);
}
//更新后渲染
this.render();
}).bind(this), 0);
}
使用generator生成排序动画的更多相关文章
- mybatis Generator生成代码及使用方式
本文原创,转载请注明:http://www.cnblogs.com/fengzheng/p/5889312.html 为什么要有mybatis mybatis 是一个 Java 的 ORM 框架,OR ...
- 【WP 8.1开发】如何动态生成Gif动画
相信如何为gif文件编码,很多朋友都会,而难点在于怎么让GIF文件中的帧动起来,也就是创建gif动画. Gif文件编码方法 先简单介绍一下编码的方法. 1.调用BitmapEncoder.Create ...
- tween.js是一款可生成平滑动画效果的js动画库。tween.js允许你以平滑的方式修改元素的属性值。它可以通过设置生成各种类似CSS3的动画效果。
简要教程 tween.js是一款可生成平滑动画效果的js动画库.相关的动画库插件还有:snabbt.js 强大的jQuery动画库插件和Tweene-超级强大的jQuery动画代理插件. tween. ...
- unity工具IGamesTools之批量生成帧动画
unity工具IGamesTools批量生成帧动画,可批量的将指定文件夹下的帧动画图片自动生成对应的资源文件(Animation,AnimationController,Prefabs) unity工 ...
- CSS3鼠标移入移出图片生成随机动画
今天分享使用html+css3+少量jquery实现鼠标移入移出图片生成随机动画,我们先看最终效果图(截图为静态效果,做出来可是动态的哟) 左右旋转 上下移动 缩放 由于时间关系我就不一步步解析各段代 ...
- JAVA 调用Axis2 code generator 生成的webservice
以下代码为调用 JAVA 调用Axis2 code generator 生成的webservice的代码. package test; import java.rmi.RemoteException; ...
- PHP使用JPG生成GIF动画图片,基于php_imagick_st-Q8.dll
PHP使用php_imagick_st-Q8.dll类库,把JPG图片连接生成GIF动画图片,需要事先下载好php_imagick_st-Q8.dll,文件,并配置php.ini文件,启用php_im ...
- python 将png图片格式转换生成gif动画
先看知乎上面的一个连接 用Python写过哪些[脑洞大开]的小工具? https://www.zhihu.com/question/33646570/answer/157806339 这个哥们通过爬气 ...
- spring boot+mybatis+generator生成domain大小写问题
之前遇到一个问题,用generator生成数据库对应的domain,以前都是好好的,那天突然生成的domain都是小写的,因为我数据库里是大写的,后来找到解决办法, <table tableNa ...
随机推荐
- git代理,windows命令行代理,linux命令行代理
下载不动设置代理:git config --global http.proxy http://127.0.0.1:1080git config --global https.proxy https:/ ...
- 用msbuild构建应用
msbuild是微软提供的一个用于生成应用程序的平台,你可以通过一个xml配置文件来控制和处理你的软件工程.它也集成到了vs里面,它不依赖于vs. xml配置(架构)的组成元素: 项目文件 属性 项 ...
- MyBatis入门学习教程-调用存储过程
一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存储过程 create table p_user( id int primary key auto_incr ...
- My Interface
一.创建Myinterface接口 public interface Myinterface { static final String MyifName="我的接口"; stat ...
- How Garbage Collection Really Works
Java Memory Management, with its built-in garbage collection, is one of the language's finest achiev ...
- JQuery 上传文件插件 Uploadify1
基于jquery的文件上传控件,支持ajax无刷新上传,多个文件同时上传,上传进行进度显示,删除已上传文件. <link href="~/Content/themes/uploadif ...
- [MySQL] 高可用架构MMM简单介绍
一.来源及原理: 众所周知,MySQL自身提供了AB复制(主从复制),然后可以很轻松实现master-master双向复制,同时再为其中一个Master节点搭建一个Slave库. 这样就实现了MySQ ...
- H5的一些小问题
[每日壹闻]常用HTML代码解释-------六.歌曲代码(1):在这组代码中,不必管它是mms.http.rtsp,只要看尾缀是asf.wma.wmv.wmv.rm都可适用下面的代码:1. 手动播放 ...
- d3安装异常
使用npm安装D3,发现其工程名和依赖名重复,导致安装异常 http://thisdavej.com/node-newbie-error-npm-refusing-to-install-package ...
- jquery mobile button样式设置
<a href="#" class="ui-btn">提交</a> ui-btn表示按钮样式 ui-btn-a,ui-btn-b:the ...