当前位置: 首页 > 后端技术 > Node.js

前端开发——让算法“动起来”

时间:2023-04-03 16:24:36 Node.js

文当然,在我们不知道具体操作细节之前,我们可以先假设一下我们可以用什么来实现它。根据之前看过的排序动画,我将它们分成1.Js来操作Dom,然后搭配简单的css2.Canvas动画。查了资料,发现有人用d3库来完成。作为一个有(被)梦想(坑)和(很多)想法的前端,你得从一开始就考虑如何实现多种算法。如果实现单步运行(如果可以的话,必须要有回退的功能),如何实现动画速度的控制等等。当然,一下子幻想这么多是不现实的。我们得找个简单的例子看看,然后一步步深入。先来看下效果图之后我们分析源代码:css:#field{width:500px;height:510px;background:black;position:relative}.bar{position:absolute;bottom:0;background:orange;border:1px纯棕色;宽度:24px}html:

javascript:!function(d){varbars=[].slice.call(d.querySelectorAll('.bar'));vararr=[8,10,3,5,6,9,2,4,7,1];变种状态=[];vardraw=function(){varbar,s;s=state.shift()||[];for(barinbars){bars[bar].style.height=25*s[bar]+'px';bars[bar].style.left=25*bar+'px';}}varsort=function(arr){for(vari=0;我arr[j+1]){arr[j]=arr[j]+arr[j+1];arr[j+1]=arr[j]-arr[j+1];arr[j]=arr[j]-arr[j+1];(JSON.parse(JSON.stringify(arr)));}}}}排序(arr);setInterval(draw,500);}(document)整个过程其实已经很清楚了,只是有些代码让我一时糊涂了,经过google和群里的朋友请教,终于解开了迷惑。我们先来明确一下这段代码的思路。首先这个动画是把大小和宽度设置死的。并且排序数组的个数需要和html结构中的条数保持一致。1、html中的bar是一个长方体,宽度为24px,边框为1px。因此,在代码中动态改变left时,需要设置为25.2。在js代码中,使用了一个匿名立即函数来包装代码。bars=[].slice.call(d.querySelectorAll('.bar'));本节将获取到的节点列表转化为对象数组,方便单独修改每根柱。3.设置一个状态空数组来保存每个状态,记住这是动画的关键。4.state.shift()将数组临时模拟成一个队列,draw函数根据最先出队的内容重新排列列表。配合setInterval(draw,400)可以组成一个动画序列。5sort函数和我们之前介绍的冒泡排序一样,只是多了一句state.push(JSON.parse(JSON.stringify(arr)));奇怪,为什么先JSON.stringify,再JSON.parse。这里需要大家慎重考虑。想想你在哪里看到的?深拷贝?是的,它是深拷贝。对于深拷贝不理解的,我在这里给出它的意思:深拷贝就是拷贝变量值,对于非基本类型变量,递归到基本类型变量再拷贝。这两天也整理了一下深拷贝,但是一直没明白为什么要在这里这么写。起初我认为这是错误的。一开始我以为arr是一个数字数组。深拷贝一个中间变量操作不也是一样吗,所以加了几行代码vartemp=arrstate.push(temp);然后动画消失,页面变成最后一个排序的页面。这时群里有人提醒我,浅拷贝会修改原来的数组。我只是根据state.push做出反应。在sort里面,每次push都是为了保存交换后的排序数组的状态。如果我用temp替换它,那么状态将全部包含相同的最后排序状态。而JSON.parse(JSON.stringify(arr))在不改变arr原有数组的情况下对arr进行深拷贝,所以它像快照一样将每一个sort的状态推送到state,然后配合setInterval逐一筛选形成动画.一个简单的排序动画,其实包含了很多有价值的内容。回过头来看,套用公式(方法)还不容易吗?让我们把之前学过的插入排序改一下:functionexchange(array,i,j){vart=array[i];数组[i]=数组[j];数组[j]=t;}varsort2=function(numbers){for(vari=0;i0&&numbers[j]新生数据并排序css:body{background-color:black;文本对齐:居中;}#restart{颜色:白色;font-family:monospace;}javascript:!function(){varcanvas=document.getElementById('canvas');变种数据=[];canvas.width=window.innerWidth-30;canvas.height=window.innerHeight-35;CreateData(IntRandom(300,100));使成为();函数重启(){数据=[];CreateData(IntRandom(300,100));}functionCreateData(val){for(vari=0;i<=val;i++)data[i]=IntRandom(500,10);}functionBubbleSort(){vartemp;for(vari=0;i<=data.length-1;i++){if(data[i]>data[i+1]){temp=data[i];数据[i]=数据[i+1];数据[i+1]=温度;}}}functionDraw(){varposX=0,posY=canvas.height;for(vari=0;i<=data.length-1;i++){c.fillStyle=RandomColor(i);c.fillRect(posX,canvas.height,5,-data[i]);铭文-;posX+=6;}}document.onclick=function(){清除();重新开始();};函数Render(){requestAnimationFrame(Render);清除();冒泡排序();画();}functionClear(){c.fillStyle="black";c.fillRect(0,0,canvas.width,canvas.height);}functionRandomColor(i){varn=Math.random()*360;return"hsl("+parseInt(i)+",100%,50%)"}functionIntRandom(max,min){returnMath.floor(Math.random()*max+min);}}()这代码其实是有缺陷的,不过没关系,在下面的分析中我们可以边看边改1。首先是常规的canvas操作。如果对canvas不熟悉,建议刷一下立面的相关部分。具体操作是获取整个浏览器屏幕的长度,减去一部分作为画布的长宽。这是为了使生成的序列不会适合浏览器的边缘。CreateData()方法是随机生成一堆高度随机的矩形。BubbleSort()是一种常见的冒泡排序,但是这里我们看到它只是一个冒泡算法,并没有像之前那样做一系列的快照。(这就涉及到我们提到的缺陷)draw()方法是从屏幕左边坐标为0的点开始的,这个posY其实是没有用的,因为我们的高度是根据一堆矩形数组随机生成的生成数据前的随机高度。posX自增维持区间。RandomColor()此方法根据高度更改颜色。然后就是这段代码的核心render()。之前我们看到操作dom的版本,动画效果是通过setInterval(draw,500)实现的,那么动画效果是从哪里来的呢?我们可以看到这里使用了HTML5API:requestAnimationFrame的好处是保证它跟随浏览器的绘制。如果浏览器的绘制间隔为16.7ms,则按这个间隔绘制;如果浏览器的绘图间隔是10ms,就会在10ms的时候绘制。不会有透支问题,动画也不会掉帧。这从我们的渲染图也可以看出,动画确实非常流畅。但是,这段代码是有问题的。问题是它没有设置暂停标志,就是会一直刷新浏览器,时间一长就会卡死。而如果你细心的话,你会发现我们之前看到的冒泡排序只有一层循环。render()方法通过在循环中调用它们来将这些无序数组按顺序堆叠起来。..而且动画过于流畅,无法仔细观察排序过程,需要修改。到这里我们停下来想一想,如何改变呢?想想之前js是怎么操作dom版本的?我们也可以进去,只要把排序算法改成和之前一样。然后按如下方式更改渲染:varfps=1;//每秒多少帧varlastExecution=newDate().getTime();functionRender(){if(state.length>0){//动画播放,不播放完继续varnow=newDate().getTime();if((now-lastExecution)>(1000/fps)){Clear();画();lastExecution=newDate().getTime();}requestAnimationFrame(Render);但是需要注意的是,当你要重新设置requestAnimationFrame时,需要指明varstopId=requestAnimationFrame(Render);然后配合cancelAnimationFrame(stopId)暂停和继续。最终效果如下:有了上面的基础,你就可以开始自己搭建自己的排序动画了。这就是本文的全部内容。文末所有代码及其他补充内容已放在github上,会持续更新。有兴趣的可以去看看,敲出来。visualgo.netDavidGalles教授的排序动画Canvas+JS实现排序动画