d3.js+react实现算法可视化:排序篇

来源:互联网 发布:刷贴软件 编辑:程序博客网 时间:2024/06/14 23:34
知道d3.js已经很长时间了,直到去年才好好看了一些教程写了一些demo,当时还是3.x版。最近这几天在看React、react-router之类的,想自己写些东西出来,刚好想到该复习下d3.js,自己就做了这个算法可视化的demo,目前只做了排序,包括冒泡排序、插入排序、选择排序、归并排序、快速排序,之后有时间的话会继续做其他的数据结构与算法的可视化。


目前有很多算法可视化的网站,比如新加坡的National University of Singapore就有个visualgo:点击打开链接


visualgo的算法已经很齐全了,而且界面、交互都很不错,比起我的demo那就强太多了安静
我的demo演示地址:点击打开链接(起了个山寨味很浓的名字,VisualCompute)


使用npm+jspm搭建工程,使用react-router + d3.js 操作svg图像,顺便使用了Materialize当UI(关于select控件有个坑,onChange事件获取不到)。






基本思路:


由于react建议不直接操作dom,所以d3的选择器也就用不上了,svg都是由react进行render,react的方便之处在于每次更新state后会重新render一下dom,所以在排序的时候,每当数据发生变化,就更新state。d3的优势就在于可以进行比例变换,根据数据的大小,把svg的高度变换的一个指定的范围,这样免得图形过大或过小。而且d3还能生成动画,不过我这里暂时没用上。


所以比较关键的地方就在于,如何更新state?


对于一个排序算法,比如冒泡排序,每次数据发生变化时怎么样通知外界呢?通过回调函数?但是在算法可视化过程中要有能力暂停算法,然后更新dom,之后再继续运行算法(比如要支持用户手动点击“下一步”),所以我觉得纯粹使用callback似乎有些麻烦。刚开始想的是保存每一步中间结果,这样不仅可以让算法“下一步”,还能“上一步”观察结果,不过后来突然想到es6的generator,generator可以生成迭代器啊!而且还把控制权限交给了外界!有外界决定这个generator是否要运行下一步,感觉很适合。由于之前一直没有用过generator,想想还是趁此机会用下吧。




ES6 Generator


这里先把阮一峰老师的博客搬过来:Generator 函数的含义与用法


基本语法


使用function*(){}定义,返回的是一个迭代器,函数内部使用yield产出数据,每次迭代器调用next会获得下一个yield产出的数据
[javascript] view plain copy
function* Generator(){  
    yield 1;  
    let v = yield 2;  
    yield v;  
}  
  
var iterator = Generator();  
console.log(iterator);//输出{},只有调用next后才有数据  
console.log(iterator.next());//{ value: 1, done: false }  
console.log(iterator.next());//{ value: 2, done: false }  
console.log(iterator.next());//{ value: undefined, done: false }, yield并不能把值传给v,yield*+generator可以  
console.log(iterator.next());//{ value: undefined, done: true }  
使用yield*可以产出迭代器
[javascript] view plain copy
function* Generator1(){  
    yield 1;  
    let v = yield* Generator2();//这里使用的是yield*,会把Generator2的控制器接入,如果使用yield,则还需要调用next一次后才能得到迭代器  
    yield v;  
}  
function* Generator2(){  
    yield 2;  
    return 3;//这里的return会传给Generator1中的v  
}  
var iterator = Generator1();  
console.log(iterator.next());//{ value: 1, done: false }  
console.log(iterator.next());//{ value: 1, done: false }  
console.log(iterator.next());//{ value: 3, done: false }  
console.log(iterator.next());//{ value: undefined, done: true }  
下面就以冒泡排序来说明下demo中的实现


Generator+冒泡排序


冒泡排序JS实现:
[javascript] view plain copy
var data = [  
    {v:5,color:"blue"},  
    {v:6,color:"blue"},  
    {v:2,color:"blue"},  
    {v:0,color:"blue"},  
    {v:7,color:"blue"},  
    {v:3,color:"blue"},  
    {v:9,color:"blue"}  
];//这里定义一些svg柱状图的参数,包括高度和颜色两种属性  
  
function bubbleSort(data){  
    var length = data.length;  
    for(var i=0;i<length;i++){  
        for(var j=0;j<length-1;j++){  
            if(data[j].v>data[j+1].v){  
                //交换  
                let t = data[j].v;  
                data[j].v = data[j+1].v;  
                data[j+1].v = t;  
            }  
        }  
    }  
}  
bubbleSort(data);  
console.log(data.map(v=>v.v));//[ 0, 2, 3, 5, 6, 7, 9 ]  


generator+冒泡
[javascript] view plain copy
function* bubbleSort(data){  
    var length = data.length;  
    for(var i=0;i<length;i++){  
        for(var j=0;j<length-1;j++){  
            data[j].color = colorYellow;//把当前这步的数据标黄  
            yield data;//产出数据  
            if(data[j].v>data[j+1].v){  
                //交换  
                data[j].color = data[j+1].color = colorRed;//把要交换的数据标红  
                yield data;//产出数据  
                let t = data[j].v;  
                data[j].v = data[j+1].v;  
                data[j+1].v = t;  
                yield data;//产出交换位置后的数据  
            }  
            resetColor(data);//重置数据color颜色属性  
        }  
    }  
}  


这个generator版的冒泡排序可以有外界调用next方法进行下一步运算,而且会把data返回出来,由于data中的一些数据发生变化,这时候通过react的setstate方法可以实现dom的更新,调用示例如下:


[javascript] view plain copy
/**********处理各种算法************/  
       var iter = bubbleSort(data);  
       var go = function() {  
           let currentData = iter.next();  
           if(!currentData.done){  
    //更新state  
               this.setState( (prevState) => {return {"data":currentData.value}});  
               setTimeout(go,500);  
           }  
       }.bind(this);  
       setTimeout(go,0);  






冒泡的最后效果如下:


其他排序都是差不多的思路,只不过在快速排序和归并排序中用到了yield* 。




 源码


demo的源码可以在本文开头提到的连接上复制下来,也可以在这里找到:https://Git.oschina.NET/liuyaqi/VisualCompute


要使用npm install和jspm install




宁波隆胸医院http://www.iyestar.com/xbzx/