javascript
翻出过去的一个多彩泡泡屏保特效(JS+CSS版)
整理文件時翻出一個好久前做的泡泡屏保的特效,純JS+CSS做的?;叵肓讼?#xff0c;是去年年初時看見XP下那個流行的泡泡屏保,突然想移植到JS版本來。但有做著才發現有不少麻煩的問題解決不好,于是沒繼續。
?
DEMO:?http://www.etherdream.com/funnyscript/bubbles/???
和XP系統自帶的那個屏保一樣,從屏幕一個角落里冒出很多泡泡,然后在屏幕里碰撞反彈。泡泡有著半透明的漸變色,并且顏色也是在不停的變換。
?
當時這個效果分析了不少時間。如果是用flash那就再簡單不過了,把泡泡蒙板的灰色通道復制到一個純色的背景層的Alpha通道就可以了。但是網頁里除非用HTML5的canvas,單憑純粹的CSS還沒那么強大的位圖處理能力。在CSS里,和透明度有關的道具也只有這幾個:png圖片,css alpha值,rgba(),chroma濾鏡,mask濾鏡,AlphaImageLoader濾鏡,以及CSS3的漸變。
?
你也許會說,這不是很簡單,給png圖片層設置各種background-color,不就可以實現顏色的變換了嗎。事實上,背景色不但混合到了半透明像素中,連泡泡外的四個邊角也給填充了,這樣就成了方塊,而不是泡泡了,并且顏色也不正確。顯然沒有這么簡單。
因為泡泡是半透明漸變的材質,chroma和mask這些過濾單色的濾鏡都派不上用場。而rgba的背景色同樣也會出現多余的背景。 AlphaImageLoader濾鏡經測試,實際顯示出來的圖片在background之上, 與<img>載入png效果一樣。而CSS3的漸變和本例的蒙板配合起來比較困難,而且兼容性也有問題。
?
本例的困難之處在于:圖片本身不僅是半透明漸變的,并且這些漸變點的顏色還能通過腳本改變??紤]了很久,既然沒有一個簡便的方法,那不如就用復雜的吧~
?
大家都知道,顏色都是RGB組成的,調整3種原色的比例,就可以變出各種顏色。我們不妨把灰色蒙板事先填入R,G,B三種純色,保存為3張圖片。這樣就有了100%的紅色泡泡,綠色泡泡,藍色泡泡。把他們疊在同個位置,然后給3張圖片設置不同的css alpha值,于是就有了各種顏色的泡泡,并且半透明的像素仍然保留!
?
于是這個彩色的問題就解決了。不過值得注意的是,藍色位于最頂層,而紅色則是最底層。即使是紅色層100%的不透明,也會被藍色和綠色層的PNG層層剝削,很明顯的減淡。所以實際顯示時,還需給藍和綠層分別加個權值,以保證紅色通道不會那么的微弱,而藍的那么的明顯。不過在IE里的顯示效果仍是藍色很明顯,不知道IE的透明度計算方式和標準瀏覽器有什么不同。。。 (2010/2/1)
?
后續:當時對ie的mask濾鏡理解不對,mask濾鏡并非是單色的過濾,而是:用指定的RGB顏色替換容器內所有點的RGB,并且Alpha'=255 - Alpha。所以ie下只要把蒙板圖片的Alpha通道取反,然后同時用AlphaImageLoader和Mask濾鏡,即可達到效果,Mask濾鏡的color參數就是泡泡的顏色。另在Webkit內核的瀏覽器下,可以使用-webkit-mask-image直接應用一個圖片蒙板!(2011/11/10)
圖片資源
html代碼
?| 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 | <!DOCTYPE?html> <html> <head> <meta?charset="utf-8"?/> <meta?http-equiv="X-UA-Compatible"?content="IE=EmulateIE7"?/> <title>CSS?Bubbles</title> <style> html,?body { ????border:?none; ????overflow:?hidden; ????height:?100%; } body?{background:?url(BG.jpg)?bottom} </style> </head> <body?onload="Demo()"> <script?src="Bubbles.js"></script> <script> var?MAX?=?5; var?i?=?0; function?Demo() { ????CreateBubble(); ????if(++i?<?MAX) ????????setTimeout(Demo,?1000); } </script> </body> </html> |
Bubbles代碼
?| 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | /** ?*?JavaScript?Bubbles ?*??By?EtherDream?2010 ?*/ +function() { ????// ????//?瀏覽器輔助 ????// ????var?_VER_?=?navigator.userAgent; ????var?_IE6_?=?/IE?6/.test(_VER_); ????var?STD?=?!!window.addEventListener; ????var?de?=?document.documentElement; ????_IE6_?&&?document.execCommand("BackgroundImageCache",?false,?true); ????// ????//?常量 ????// ????var?D?=?222;???????????? //泡泡直徑 ????var?K?=?0.999; ????var?POW_RATE?=?0.0001;?????? //補償概率 ????var?POW_RANGE?=?0.8;???? //補償范圍(基于誕生速度) ????function?SPEED_X(){return?8?+?RND()?*?4} ????function?SPEED_Y(){return?6?+?RND()?*?2} ????var?arrBubs?=?[]; ????var?iBottom; ????var?iRight; ????var?SQRT?=?Math.sqrt; ????var?ATAN2?=?Math.atan2; ????var?SIN?=?Math.sin; ????var?COS?=?Math.cos; ????var?ABS?=?Math.abs; ????var?RND?=?Math.random; ????var?ROUND?=?Math.round; ????function?Timer(call,?time) ????{ ????????var?last?=?+new?Date; ????????var?delay?=?0; ????????return?setInterval(function() ????????{ ????????????//?時間差累計 ????????????var?cur?=?+new?Date; ????????????delay?+=?(cur?-?last); ????????????last?=?cur; ????????????//?計算幀數 ????????????if(delay?>=?time) ????????????{ ????????????????call(); ????????????????delay?%=?time; ????????????} ????????},?1); ????} ????Timer(update,?17); ????CreateBubble?=?function() ????{ ????????var?bub?=?new?Bubble(); ????????bub.setX(0); ????????bub.setY(0); ????????bub.vx?=?SPEED_X(); ????????bub.vy?=?SPEED_Y(); ????????arrBubs.push(bub); ????}; ????function?update() ????{ ????????var?n?=?arrBubs.length; ????????var?bub,?bub2; ????????var?i,?j; ????????updateWall(); ????????for(i=0;?i<n;?i++) ????????{ ????????????bub?=?arrBubs[i]; ????????????bub.paint(); ????????????bub.vx?*=?K; ????????????bub.vy?*=?K; ????????????if(RND()?<?POW_RATE) ????????????{ ????????????????bub.vx?=?SPEED_X()?*?(1?+?RND()?*?POW_RANGE); ????????????????bub.vy?=?SPEED_Y()?*?(1?+?RND()?*?POW_RANGE); ????????????} ????????????bub.setX(bub.x?+?bub.vx); ????????????bub.setY(bub.y?+?bub.vy); ????????????checkWalls(bub); ????????} ????????for(i=0;?i<n-1;?i++) ????????{ ????????????bub?=?arrBubs[i]; ????????????for(j=i+1;?j<n;?j++) ????????????{ ????????????????bub2?=?arrBubs[j]; ????????????????checkCollision(bub,?bub2); ????????????} ????????} ????} ????function?updateWall() ????{ ????????iRight?=?de.clientWidth?-?D; ????????iBottom?=?de.clientHeight?-?D; ????} ????function?checkWalls(bub) ????{ ????????if(bub.x?<?0) ????????{ ????????????bub.setX(0); ????????????bub.vx?*=?-1; ????????} ????????else?if(bub.x?>?iRight) ????????{ ????????????bub.setX(iRight); ????????????bub.vx?*=?-1; ????????} ????????if(bub.y?<?0) ????????{ ????????????bub.setY(0); ????????????bub.vy?*=?-1; ????????} ????????else?if(bub.y?>?iBottom) ????????{ ????????????bub.setY(iBottom); ????????????bub.vy?*=?-1; ????????} ????} ????function?rotate(x,?y,?sin,?cos,?reverse) ????{ ????????if(reverse) ????????????return?{x:?x?*?cos?+?y?*?sin,?y:?y?*?cos?-?x?*?sin}; ????????else ????????????return?{x:?x?*?cos?-?y?*?sin,?y:?y?*?cos?+?x?*?sin}; ????} ????function?checkCollision(bub0,?bub1) ????{ ????????var?dx?=?bub1.x?-?bub0.x; ????????var?dy?=?bub1.y?-?bub0.y; ????????var?dist?=?SQRT(dx*dx?+?dy*dy); ????? ????????if(dist?<?D) ????????{ ????????????//?計算角度和正余弦值 ????????????var?angle?=?ATAN2(dy,dx); ????????????var?sin?=?SIN(angle); ????????????var?cos?=?COS(angle); ????????????//?旋轉?bub0?的位置 ????????????var?pos0?=?{x:0,?y:0}; ????????????//?旋轉?bub1?的速度 ????????????var?pos1?=?rotate(dx,?dy,?sin,?cos,?true); ????????????//?旋轉?bub0?的速度 ????????????var?vel0?=?rotate(bub0.vx,?bub0.vy,?sin,?cos,?true); ????????????//?旋轉?bub1?的速度 ????????????var?vel1?=?rotate(bub1.vx,?bub1.vy,?sin,?cos,?true); ????????????//?碰撞的作用力 ????????????var?vxTotal?=?vel0.x?-?vel1.x; ????????????vel0.x?=?vel1.x; ????????????vel1.x?=?vxTotal?+?vel0.x; ????????????//?更新位置 ????????????var?absV?=?ABS(vel0.x)?+?ABS(vel1.x); ????????????var?overlap?=?D?-?ABS(pos0.x?-?pos1.x); ????????????pos0.x?+=?vel0.x?/?absV?*?overlap; ????????????pos1.x?+=?vel1.x?/?absV?*?overlap; ????????????//?將位置旋轉回來 ????????????var?pos0F?=?rotate(pos0.x,?pos0.y,?sin,?cos,?false); ????????????var?pos1F?=?rotate(pos1.x,?pos1.y,?sin,?cos,?false); ????????????//?將位置調整為屏幕的實際位置 ????????????bub1.setX(bub0.x?+?pos1F.x); ????????????bub1.setY(bub0.y?+?pos1F.y); ????????????bub0.setX(bub0.x?+?pos0F.x); ????????????bub0.setY(bub0.y?+?pos0F.y); ????????????//?將速度旋轉回來 ????????????var?vel0F?=?rotate(vel0.x,?vel0.y,?sin,?cos,?false); ????????????var?vel1F?=?rotate(vel1.x,?vel1.y,?sin,?cos,?false); ????????????bub0.vx?=?vel0F.x; ????????????bub0.vy?=?vel0F.y; ????????????bub1.vx?=?vel1F.x; ????????????bub1.vy?=?vel1F.y; ????????} ????} ????var?APLHA?=?0.8; ????var?POW?=?[1,?APLHA,?APLHA*APLHA]; ????/****************************** ?????*?Class?Bubble ?????******************************/ ????function?Bubble() ????{ ????????var?kOpa?=?[],?kStp?=?[]; ????????var?arrFlt?=?[]; ????????var?oBox?=?document.body.appendChild(document.createElement("div")); ????????styBox?=?oBox.style; ????????styBox.position?=?"absolute"; ????????styBox.width?=?D?+?"px"; ????????styBox.height?=?D?+?"px"; ????????for(var?i=0;?i<4;?i++) ????????{ ????????????var?div?=?document.createElement("div"); ????????????var?sty?=?div.style; ????????????sty.position?=?"absolute"; ????????????sty.width?=?"222px"; ????????????sty.height?=?"222px"; ????????????oBox.appendChild(div); ????????????//?泡泡頂層 ????????????if(i?==?3) ????????????{ ????????????????if(_IE6_) ????????????????????sty.filter?=?"progid:DXImageTransform.Microsoft.AlphaImageLoader(src=heart.png)"; ????????????????else ????????????????????sty.backgroundImage?=?"url(heart.png)"; ????????????????break; ????????????} ????????????kOpa[i]?=?3?*?RND(); ????????????kStp[i]?=?0.02?*?RND(); ????????????if(STD) ????????????{ ????????????????sty.backgroundImage?=?"url(ch"?+?i?+?".png)"; ????????????????arrFlt[i]?=?sty; ????????????} ????????????else ????????????{ ????????????????sty.filter?=?"alpha?progid:DXImageTransform.Microsoft.AlphaImageLoader(src=ch"?+?i?+?".png)"; ????????????????arrFlt[i]?=?div.filters.alpha; ????????????} ????????} ????????this.styBox?=?styBox; ????????this.kOpa?=?kOpa; ????????this.kStp?=?kStp; ????????this.arrFlt?=?arrFlt; ????} ????Bubble.prototype.setX?=?function(x) ????{ ????????this.x?=?x; ????????this.styBox.left?=?ROUND(x)?+?"px"; ????}; ????Bubble.prototype.setY?=?function(y) ????{ ????????this.y?=?y; ????????this.styBox.top?=?ROUND(y)?+?"px"; ????}; ????Bubble.prototype.paint?=?function() ????{ ????????var?i,?v; ????????for(i=0;?i<3;?i++) ????????{ ????????????v?=?ABS(SIN(this.kOpa[i]?+=?this.kStp[i]?*?RND())); ????????????v?*=?POW[i]; ????????????v?=?((v?*?1e4)?>>?0)?/?1e4; ????????????this.arrFlt[i].opacity?=?STD??v?:?v*100; ????????} ????}; }(); |
總結
以上是生活随笔為你收集整理的翻出过去的一个多彩泡泡屏保特效(JS+CSS版)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基站定位(Google API)
- 下一篇: django 名词解释