【伯乐在线编注】:Marek Brodziak 的这篇文章写于 2013 年 9 月。去年同期我们已摘编宣传过Rainday.js,该库后来已有改进更新,比下文中图片所展示的效果更好了。
————————–
最近我发布了一个有趣的项目叫做 rainyday.js。我认为这是一段再普通不过的代码,实际上,这只是我第一次在比起需要弹出警告框的程度更深层次的水平和javascript进行接触。我希望,你们中的一些人回发现他的用途以及令人感兴趣的地方。
Rainyday.js背后的意图是想创建一个使用HTML5画布渲染雨滴落在玻璃表面的Javascript 库。足够简单,然而也充满挑战,尤其是在我们试图避免因为Javascript的动画效果卡通化的同时还要保持平滑流畅。
在这篇文章中我尽力阐述综合法也是”little things”,所以跟着我一起来吧。但首先,你可能想先看看下面的Demo,让你对我所说的有个概念(点击图片在JSBin打开demo)。
Canvas 图层准备
为了使雨滴动画实现分层效果,运用了三种不同的Canvas对象,可以看到下图。
底部图层包含了原始图像,拉升到了API返回的尺寸。图像内容仅仅是画在Canvas上,然后图像开始模糊,使其看起来似乎是失去焦点。当前的实现利用Mario Klingemann的堆栈模糊算法(Stack Blur Algorithm)。
中间图层主要是一个无形的Canvas。他不是DOM树的一部分,相反,是为了渲染雨滴反射的辅助。原始图像相应的旋转和翻转使得之后的处理过程更加简单。
最后是顶层图层(镜面)是用来作雨滴的绘图。他是在第一层Canvas上直接定位。
整个概念十分简单且容易理解。用三个Canvas实例对象代替一个,使脚本代码可读性变得简单以及明显提高性能。
细看雨滴
雨滴的呈现是raindy.js最重要的一部分。当只有一个水滴来说这是简单的作业,但在更大更复杂的案例中,有许多因素就必须考虑。例如,我们必须确保水滴形状是正确并且随机的。
为了实现它,raindy.js运用一个算法来近似形成一个圆()。通过脚本呈现结果就像这样:该算法的输出是一个确定圆曲线上点的链表.绘制的雨滴是随着半径轻微变化连在一起然后将我们选择的图形反射裁剪成最终形状。
运行动画
最后,动画的最后一块拼图是“引擎”,引擎包括了三个模块。每个模块都依赖前一个模块的输出,输出结果可以在文章开头的demo中看到。他们三个模式是:
1.下雨模块:一个Javascript的计时事件可以无论何时调用rain()方法。使用用户指定的时间间隔,这个模块使新水滴随机的滴落在Canvas上。新水滴的大小是预先设置的,它允许用户控制动画中的数量和大小。用我们demo中的一个做例子,下列调用rain()方法会每隔100毫秒产生一个新雨滴加到Canvas上。这些雨滴会根据下列分布:88%的在3和6之间(最小数字是3加上0到3之间的随机数),2%的(0.9-0.88)大小是5,剩下的10%是在6和8 之间。
engine.rain([ engine.preset(3, 3, 0.88), engine.preset(5, 5, 0.9), engine.preset(6, 2, 1), ], 100);
2.重力模块
一旦一个雨滴被添加到动画,一个额外的定时事件将通过修改其在Y轴位置控制Canvas上水滴的运动(为了给定一个角度,模拟降雨下降,X轴上也做了同样处理)。现在rainyday.js提供了两种不同的重力函数GRAVITY_LINEAR(简单的重力加速度)和GRAVITY_NON_LINEAR(水滴的随机运动)选择重力函数如调用般简单。
engine.gravity = engine.GRAVITY_NON_LINEAR;
3.轨迹模块
在重力运动下降后执行的函数,为了留下痕迹。当TRAIL_NONE无法拖出尾巴是,TRAIL_DROPS函数实现小水滴的痕迹。选择一个函数包含调用
engine.trail = engine.TRAIL_DROPS;
Where to Go From Here
rainyday.js的源代码能在GitHub上找到,如果你享受这个,去看看吧。我下一个版本会致力于实现雨滴间的碰撞检测以及一些我记得的改进。任何形式的任何意见、建议和反馈(真的)是都是非常欢迎的。