事情是这样的,前天上午产品经理说想要做一个心愿墙,问我能不能行
我心想,这太容易了,但为了多摸一天鱼,我说还是有点挑战 的
结果下午,产品经理和设计师就给我发来了设计参考
他们说,心愿墙的设计大致是这样的,每个用户的心愿都是一个气泡,而客户的品牌是”龙“,我们希望在前端页面里用气泡呈现一个龙形的设计,每个气泡都会浮动,鼠标移上去变大,点击后展示心愿详情。
当时我的内心是这样的
我摸鱼的一天要泡汤了吗?
谁都不能阻止我摸鱼 
但首先要解决最核心的问题
龙从哪里来? 设计师说了,他可以给我一条由气泡组成的龙的设计稿,我说那等你设计稿给我,我再研究把。结果他说,已经有了,你就用这个吧
我的刀呢? 
互动问题 
请在评论区留下你遇到过的最奇葩的需求
 
拆解需求 遇到不靠谱的产品经理和设计师,前端工程师真是惨。我们顶着最后交付成品的巨锅,所有deadline感觉都只是用来压榨前端工程师的。
我们只能靠自己,因为
谁都不能阻止我摸鱼 
需求1:有鼠标交互效果(太简单) 
需求2:气泡要浮动(css动画,easy) 
需求3:气泡组成一条龙 
 
此时我脑海里响起这首烂大街的歌
左边跟我一起画个龙,在你右边画一道彩虹~
 
1 2 3 诶,画个龙 用什么画,canvas canvas能获得指定区域的像素点阵 
卧槽,有招儿了
代码时间 先用图片搜索找一张龙的剪影
将图片绘制到canvas中 1 2 3 4 5 6 7 8 9 10 11 12 var  canvas = document .getElementById("canvas" );var  ctx = canvas.getContext("2d" );var  image = new  Image();image.src = "dragon.jpg" ; image.onload = function (         canvas.width = image.width;         canvas.height = image.height;         ctx.drawImage(image,0 ,0 ); } 复制代码 
获取并裁剪画布的点阵信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var  imageData = ctx.getImageData(0 ,0 ,image.width,image.height).data;ctx.fillStyle = "#ffffff" ; ctx.fillRect(0 ,0 ,image.width,image.height); var  gap = 6 ;for  (var  h = 0 ; h < image.height; h+=gap) {    for (var  w = 0 ; w < image.width; w+=gap){             var  position = (image.width * h + w) * 4 ;             var  r = imageData[position], g = imageData[position + 1 ], b = imageData[position + 2 ];             if (r+g+b==0 ){                     ctx.fillStyle = "#000" ;                     ctx.fillRect(w,h,4 ,4 );                 }     } } 复制代码 
现在我们获得了这样一条龙的点阵信息
通过点阵信息生成气泡dom 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var  dragonContainer = document .getElementById("container" );var  dragonScale = 2 ;for  (var  h = 0 ; h < image.height; h+=gap) {    for (var  w = 0 ; w < image.width; w+=gap){             var  position = (image.width * h + w) * 4 ;             var  r = imageData[position], g = imageData[position + 1 ], b = imageData[position + 2 ];             if (r+g+b==0 ){                     var  bubble = document .createElement("img" );                     bubble.src = "bubble.png" ;                     bubble.setAttribute("class" ,"bubble" );                     var  bubbleSize = Math .random()*10 +20 ;                     bubble.style.left = (w*dragonScale-bubbleSize/2 ) + "px" ;                     bubble.style.top = (h*dragonScale-bubbleSize/2 ) + "px" ;                     bubble.style.width = bubble.style.height = bubbleSize+"px" ;                     bubble.style.animationDuration = Math .random()*6 +4  + "s" ;                     dragonContainer.appendChild(bubble);                 }     } } 复制代码 
作者:大帅老猿链接:https://juejin.cn/post/6963476650356916254   来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
关于疑问 var position = (image.width * h + w) * 4;  公式获取当前点?
参考原码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 <!DOCTYPE html > <html  lang ="en" >   <head >      <meta  charset ="UTF-8"  />      <meta  http-equiv ="X-UA-Compatible"  content ="IE=edge"  />      <meta  name ="viewport"  content ="width=device-width, initial-scale=1.0"  />      <title > Document</title >      <style >        * {         margin : 0 ;         padding : 0 ;       }       .bubble {         position : absolute;         background-color : red;       }       .wrap {         position : relative;         position : absolute;         top : 0 ;       }       canvas  {         box-sizing : border-box;       }       .wrap  > div  {         position : absolute;         transition : all 0.5s ;         cursor : pointer;       }       .wrap  > div :hover  {         transform : scale (20 );         z-index : 999 ;       }     </style >    </head >    <body >      <canvas  id ="canvas" > </canvas >      <div  class ="wrap" > </div >    </body >  </html > <script >   var  canvas = document .getElementById("canvas" );   var  ctx = canvas.getContext("2d" );   var  list = [{ x : -100 , y : -100  }];   var  image = new  Image();   image.src = "dragon.jpg" ;   image.onload = function  (     canvas.width = image.width;     canvas.height = image.height;     ctx.drawImage(image, 0, 0);     var  imageData = ctx.getImageData(0 , 0 , image.width, image.height).data;     function  fn (       var  gap = 6 ;       var  dragonScale = 2 ;       for  (var  h = 0 ; h < image.height; h += gap) {         for  (var  w = 0 ; w < image.width; w += gap) {           var  position = (image.width * h + w) * 4 ;           var  r = imageData[position],             g = imageData[position + 1],             b = imageData[position + 2];           if (r + g + b >= 0 && r + g + b <= 159) {             let  w1 = w - 10 ;             let  h1 = h - 10 ;             var  fillStyle = `rgba(${parseInt (Math .random() * 255 )} ,${parseInt (                 Math .random() * 255              )},${parseInt (Math .random() * 255 )})`;              var  bubble = document .createElement("div" );             var  bubbleSize = Math .random() * 10  + 20 ;             bubble.style.left = w1 + "px" ;             bubble.style.top = h1 + "px" ;             bubble.style.width = "5px" ;             bubble.style.height = "5px" ;             bubble.style.animationDuration = Math .random() * 6  + 4  + "s" ;             bubble.style.backgroundColor = fillStyle;             console .log(document .getElementsByClassName("wrap" )[0 ]);             document .getElementsByClassName("wrap" )[0 ].appendChild(bubble);           }         }       }     }     fn();     setInterval (() =>  {       fn();     }, 3000);     ctx.clearRect(0, 0, image.width, image.height);   }; </script > 
效果图