有些节日活动 (圣诞节啦什么的~) 页面上有雪花飘落的效果, 看着挺炫的, 所以自己也来写一个, 代码比较简单, 看着还不错~
便于查看效果, 请运行下面代码:
代码片段 1
- <!doctype html>
- <html>
- <head>
- <meta charset="utf-8">
- <title>snow</title>
- <style>
- body{ text-align: center;}
- canvas{background: url(http://upload.cankaoxiaoxi.com/2015/0202/1422859364285.jpg) 0 0 no-repeat;}
- </style>
- </head>
- <body>
- <canvas width="800" height="600" id="c1"></canvas>
- <script>
- function rnd(n, m){
- return Math.floor(Math.random()*(m-n) + n);
- };
- function d2a(n){
- return n*Math.PI/180;
- };
- // 在画布中生成雪花:
- var oC = document.getElementById("c1");
- var gd = oC.getContext("2d");
- var maxW = 800;
- var maxH =600;
- var arr = [];
- var width = 20;
- for(var i=0; i<100; i++){
- arr.push({
- "left":rnd(0, 800),
- "top":rnd(0, 600),
- "deg":rnd(-10, 10),
- "scale":rnd(2, 10)
- });
- }
- setInterval(function(){
- gd.clearRect(0, 0, oC.width, oC.height);
- gd.save();
- for(var i=0; i<arr.length; i++){
- var h = 0.5 * arr[i].scale;
- arr[i].left = arr[i].left + Math.tan(d2a(arr[i].deg))*h;
- arr[i].top = arr[i].top + h;
- // 若已在画面外则删除
- if(arr[i].left <0 || arr[i].left> maxW || arr[i].top> maxH){
- arr.splice(i--, 1);
- continue;
- }
- var width_i = arr[i].scale;
- var ra = gd.createRadialGradient(arr[i].left, arr[i].top, width_i/4, arr[i].left, arr[i].top, width_i);
- ra.addColorStop(0, "rgba(255,255,255,1)");
- ra.addColorStop(1, "rgba(255,255,255,0.1)");
- gd.fillStyle = ra;
- gd.beginPath();
- gd.arc(arr[i].left, arr[i].top, width_i, 0, 2*Math.PI);
- gd.fill();
- }
- gd.restore();
- }, 16);
- // 不断增加新的雪花
- function next(){
- setTimeout(function(){
- if(arr.length <200){
- for(var i=0; i<20; i++){
- arr.push({
- "left":rnd(0, 800),
- "top":0,
- "deg":rnd(-10, 10),
- "scale":rnd(2, 10)
- });
- }
- }
- next();
- }, Math.random()*200+500);
- };
- next();
- </script>
- </body>
- </html>
下面把主要代码拿出来详细解释:
1, 页面打开时, 先随机生成 100 个雪花飘落在页面上, 位置, 飘落角度, 大小都随机. 所有的雪花信息都存在数组 arr 中:
- for(var i=0; i<100; i++){
- arr.push({
- "left":rnd(0, 800),
- "top":rnd(0, 600),
- "deg":rnd(-10, 10),
- "scale":rnd(2, 10)
- });
- }
2, 用定时器随机时间间隔, 不断生成新的雪花, 但是位置是从 top=0 开始, left 随机.
这里测试的时候遇到一个问题: 当页面打开着, 又去看别的页面, 过了会再看这个雪花页面时会发现有一坨雪花, 很影响视觉效果, 而且会卡. 所以这里页面中的雪花数量维持在 200 个以下, 所以当少于 200 个时才生成新的雪花.
- function next(){
- setTimeout(function(){
- if(arr.length <200){
- for(var i=0; i<20; i++){
- arr.push({
- "left":rnd(0, 800),
- "top":0,
- "deg":rnd(-10, 10),
- "scale":rnd(2, 10)
- });
- }
- }
- next();
- }, Math.random()*200+500);
- };
- next();
3. 用定时器不断刷新雪花的显示. 根据角度计算下一个位置. 考虑到不断产生的雪花会影响页面性能, 所以超出背景区域的雪花予以删除, 即删除 arr 中的元素:
- setInterval(function(){
- gd.clearRect(0, 0, oC.width, oC.height);
- gd.save();
- for(var i=0; i<arr.length; i++){
- var h = 0.5 * arr[i].scale;
- arr[i].left = arr[i].left + Math.tan(d2a(arr[i].deg))*h;
- arr[i].top = arr[i].top + h;
- // 若已在画面外则删除
- if(arr[i].left < 0 || arr[i].left> maxW || arr[i].top> maxH){
- arr.splice(i--, 1);
- continue;
- }
- var width_i = arr[i].scale;
- var ra = gd.createRadialGradient(arr[i].left, arr[i].top, width_i/4, arr[i].left, arr[i].top, width_i);
- ra.addColorStop(0, "rgba(255,255,255,1)");
- ra.addColorStop(1, "rgba(255,255,255,0.1)");
- gd.fillStyle = ra;
- gd.beginPath();
- gd.arc(arr[i].left, arr[i].top, width_i, 0, 2*Math.PI);
- gd.fill();
- }
- gd.restore();
- }, 16);
有一个地方需要注意下, 就是我写的雪花不是用的图片而是用 createRadialGradient 渐变填充的圆形, 这个渐变填充比较耗费性能, 如果页面上东西多的话, 可以直接用较小的雪花图片代替.
来源: http://www.qdfuns.com/article/16354/4cc3b16507e91fc22aee1164a5d08c6e.html