HTML5技术

用 canvas 做个好玩的网站背景 - WAxes

字号+ 作者:H5之家 来源:CnBlogs 2015-11-13 10:25 我要评论( )

不知不觉又好久没更过博客了,老调新弹一下,之前做的一个小效果,觉得蛮有意思的,也有朋友问是怎么做的,就分享一下,写个博文吧。 先上demo吧: 上面这个demo是最早写的,后来做了点小修改后就用到了自己的网站上当个banner,有兴趣的也可以看看效果: ,

  不知不觉又好久没更过博客了,老调新弹一下,之前做的一个小效果,觉得蛮有意思的,也有朋友问是怎么做的,就分享一下,写个博文吧。

  先上demo吧:   

  上面这个demo是最早写的,后来做了点小修改后就用到了自己的网站上当个banner,有兴趣的也可以看看效果:    ,至少同事说还是挺酷炫的。这种效果其实很早之前就有了的,我也是在一个网站上看到类似的效果,发现这个创意不错,而且难度很小,就花了一个午休的时间写了一下。

  接下来就分析一下怎么实现把。

  这种效果一眼看过去,就知道其实就是一堆粒子在进行无序的运动。然后当粒子与粒子之间的距离小于一定值后,就进行连线,并且根据距离的大小来对线条的粗细进行一些更改,就可以做出这种有点像蛛网的感觉了。原理很简单,直接上代码:

var dots = []; for (var i = 0; i < 200; i++) { var x = Math.random() * (canvas.width + 2*extendDis) - extendDis; var y = Math.random() * (canvas.height + 2*extendDis) - extendDis; var xa = (Math.random() * 2 - 1)/1.5; var ya = (Math.random() * 2 - 1)/1.5; dots.push({x, y, xa, ya}) }

  首先,用一个数组,装载两百个分散在canvas各处的粒子对象,并且给每个对象一个随机的运动趋势。也就是xa和ya,用于表示垂直和水平的运动趋势。其实就是一个用于每次循环的时候进行叠加的值。

  实例化好两百个粒子对象后。就可以让他们开始运动:

dot.x += dot.xa; dot.y += dot.ya; // 遇到边界将速度反向 dot.xa *= (dot.x > (canvas.width + extendDis) || dot.x < -extendDis) ? -1 : 1; dot.ya *= (dot.y > (canvas.height + extendDis) || dot.y < -extendDis) ? -1 : 1; // 绘制点 ctx.fillStyle = `rgba(${rgb},${rgb},${rgb},1`; ctx.fillRect(dot.x - 0.5, dot.y - 0.5, 1, 1);

  运动的逻辑也很简单,每次给粒子更新新的状态,其实就是根据此前初始化粒子的时候给予的xa和ya,进行一个累加,就可以形成运动的效果了。

  当然,粒子不能往一个方向无限的运动下去,所以我们还需要判断粒子是否运动到边界了,如果运动到了边界,就把运动趋势进行反转。也就做出了一种粒子反弹的效果。上面的extendDis其实是我为了让粒子反弹点在canvas外而定义的一个变量,用于控制粒子跑到离开canvas多远后才进行反弹。

  当然,每次运动完都对粒子进行一个绘制。这一段代码会放到一个叫move的function里。

  

  就上面的一些代码,就完成了粒子的初始化,以及运动了。接下来就是画线了。逻辑也很简单,就是遍历,逐个粒子计算距离,当两个比较的粒子之间的距离小于某个值,就进行画线。代码如下:

/** * 逐个对比连线 * @param ndots */ function bubDrawLine(ndots){ var ndot; dots.forEach(function (dot) { move(dot); (var i = 0; i < ndots.length; i++) { ndot = ndots[i]; if (dot === ndot || ndot.x === null || ndot.y === null) continue; var xc = dot.x - ndot.x; var yc = dot.y - ndot.y; (xc > ndot.max || yc > lineDis) continue; dis = xc * xc + yc * yc; ( dis > lineDis ) continue; ratio; (ndot === warea && dis < 20000) { dot.x -= xc * 0.01; dot.y -= yc * 0.01; } // 计算距离比 ratio = (lineDis - dis) / lineDis; // 粒子间连线 ctx.beginPath(); ctx.lineWidth = ratio / 2; ctx.strokeStyle = `rgba(${rgb},${rgb},${rgb},${ratio + 0.2}`; ctx.moveTo(dot.x, dot.y); ctx.lineTo(ndot.x, ndot.y); ctx.stroke(); } // 将已经计算过的粒子从数组中删除 ndots.splice(ndots.indexOf(dot), 1); }); }

  逻辑也比较简单,就是遍历数组,把遍历到的粒子跟其他粒子进行逐个比对。当距离小于上面的lineDis的时候,就进行连线。为了减少计算量,每次计算过的粒子将会从用于计算的ndots数组中删除,避免重复计算。同时如果两个粒子的垂直距离和水平距离大于lineDis,那也就没必要再算两个粒子的距离了,直接不做处理,从而减少计算量。

  其实这个计算用的还是所谓的笨方法,我此前有在想有什么更好的计算方法能更好的优化计算效率呢。然后想了一个方法并且进行了一个测试,就是先对粒子根据x轴进行快速排序,然后按顺序进行比较,当比较到的粒子的水平距离大于lineDis的时候,就不用再比下去了。因为后面的都肯定会比当前粒子要更远,想着就按照这样会减少计算量应该会提升效率。但是我对两个不同的计算方法都进行了耗时比较,结果还是原来的笨方法的性能更优。因为这个新方法每次都要重新排序,这个计算量也是蛮大的。然后就暂时没想到其他了,如果读者有更好的idea不妨分享一下。

  

  同事有问我那个鼠标划过,粒子会聚起来的效果很神奇,怎么做的,其实这个效果比想象中简单很多,而且在上面的代码里我也给出来了。再给出一段保存鼠标位置的代码,很简单,就是鼠标移动的时候保存鼠标位置。

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • canvas知识点 - H.U.C-王子

    canvas知识点 - H.U.C-王子

    2017-04-16 10:02

  • canvas实现黑客帝国矩形阵 - 风雨后见彩虹

    canvas实现黑客帝国矩形阵 - 风雨后见彩虹

    2017-03-30 09:00

  • canvas画直角坐标系 - shbwh-tswq

    canvas画直角坐标系 - shbwh-tswq

    2017-03-18 10:02

  • 列表总结Canvas和SVG的区别 - 妙音天女

    列表总结Canvas和SVG的区别 - 妙音天女

    2017-03-17 10:00

网友点评