使用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 ...
随机推荐
- 详细解说Java Spring的JavaConfig注解 【抄】
抄自: http://www.techweb.com.cn/network/system/2016-01-05/2252188.shtml @RestController spring4为了更方便的支 ...
- oracle数据库从入门到精通之四
序列是oracle中较为重要的概念事务对于ddl是不起作用的查询,更新,数据表,约束这些个概念要掌握.在许多数据库之中都会存在一种数据类型--自动增长列,它能够创建流水号12c之前并没有提供这样一个自 ...
- 认识UML类图元素
在Visio里,包和类的关系是包含关系,将类拖入包的文件夹之后,关系就建立了,二元关联符号可以设置为:聚合.合成.接口:空心圆+直线(唐老鸭类实现了‘讲人话’):依赖:虚线+箭头(动物和空气的关系): ...
- VR内容定制请找北京动软VR团队,长年承接VR/AR应用、游戏内容定制
最近这一拔VR及AR浪潮得到业界的热捧,与2015年年底到2016年年初乐相.蚁视.睿悦.焰火工坊等VR创业公司,陆续发布融资的信息不无关系.业界也有统计数据称,约90%的VR投资案例,发生在2015 ...
- Troubleshooting a node by using the netapp SP
Troubleshooting a node by using the SP When you encounter a problem with a node, you can use the SP ...
- sysbench 安装遇到的问题
sysbench 作为性能测试工具,提供了很多有用的参数,使用方法网络上一抓一把,这里记录下安装过程中遇到的问题已经解决办法 .tar.gz cd sysbench- ./autogen.sh ./c ...
- PHP购物车类
<?php /** * 购物车类 */ session_start(); class Cart{ private static $ins = null; private $items = arr ...
- 3.3 哈尔小波空间W0
在3.2节我们学习了关于(3.8)定义的Vj的性质.特别的,我们可以乘以系数从一个Vj空间变换到另一个.我们这节学习V0和V1的关系. 将f1(t)∈V1投影至V0 我们考虑一个属于V1的函数f1(t ...
- Oracle补习班第三天
In every triumph, there's a lot of try. 每个胜利背后都有许多尝试 Oracle管理实例组件 主要组件分为两部分例程,与数据库: 例程分为两部分SGA跟进程: S ...
- 用git管理自己读的书
福昕阅读器,可以方便地做书签和备注.使用git去管理图书和示例代码,一方面能够很好地保存这些资料,方便查找:另外一方面,无论在家,还是在公司,都能很好地同步自己学习的进度. 福昕阅读器5(视图--&g ...