【分享】翻出过去的一个多彩泡泡屏保特效(JS+CSS版)

news/2025/3/31 22:15:56/

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

  整理文件时翻出一个好久前做的泡泡屏保的特效,纯JS+CSS做的。回想了下,是去年年初时看见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)


图片资源

151500_orkE_113740.jpg

151501_QwV0_113740.png151502_kmJp_113740.png151549_GUrw_113740.png151501_EGer_113740.png

html代码

<!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代码

/*** 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};elsereturn {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)";elsesty.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;}};}();


转载于:https://my.oschina.net/darkness/blog/360394


http://www.ppmy.cn/news/794045.html

相关文章

Android 绿色应用公约 2.0(2018 年 4 月)

Android 绿色应用公约 2.0&#xff08;2018 年 4 月&#xff09; 宗旨 这是一项旨在推动 Android 生态中的优秀应用共同维护一个更加良性的『设备体验』而发起的开放公约。 设备体验&#xff1a;影响效应超出用户与应用进行显性交互的过程之外&#xff0c;在用户感知中属于设备…

关于绿色

转自&#xff1a;http://www.iteye.com/topic/702804 关于绿色 喜欢绿色&#xff0c;喜欢雅黑&#xff0c;无可救药。在这个吵吵闹闹的软件行业&#xff0c;绿色也忽然从“春风一拂千山绿”唯美变成俗不可耐的buzzword。比如&#xff1a; 绿色软件&#xff1a;大大的buzzword。…

xXx时间屏保

2019独角兽企业重金招聘Python工程师标准>>> 龙家二少编写的Windows屏保软件一款会随着时间变化密码的纯绿色安全锁屏软件酷炫的3D效果话不多说&#xff0c;请看介绍&#xff1a; 如果您要离开电脑而又不想别人使用&#xff0c;仲么办&#xff1f;使用WindowsL键锁屏…

3D屏保:排色榜

3D屏保:排色榜 排色榜,是一个针对图形学中的色彩进行排序的DEMO,这里的色是色彩的意思,看成别的点进来的同学请自觉面壁.该DEMO可以按RGB,GBR,BRG,灰度值四种方式进行排序.排序算法为冒泡排序,之所以选择这种排序算法,是因为该算法容易实现相邻两个颜色的交换旋转. 前些天看到一…

8086纯汇编实现推箱子

推箱子 设计内容需求分析概要设计详细设计运行截图调试情况源代码 设计内容 游戏中玩家可以用键盘的上&#xff0c;下&#xff0c;左&#xff0c;右键控制小人的移动位置&#xff0c;游戏规则也十分简单&#xff0c;玩家在一个有限空间内&#xff0c;将木箱放在指定的位置。箱…

xXx时间屏保 3.6.1

更新记录 xXx时间屏保更新记录 软件简介 龙家二少编写的Windows屏保软件一款会随着时间变化密码的纯绿色安全锁屏软件酷炫的3D效果界面话不多说&#xff0c;请看介绍&#xff1a; 如果您要离开电脑而又不想别人使用&#xff0c;仲么办&#xff1f;使用WindowsL键锁屏&#x…

xXx时间屏保3.6

更新记录 xXx时间屏保更新记录 软件简介 龙家二少编写的Windows屏保软件一款会随着时间变化密码的纯绿色安全锁屏软件酷炫的3D效果界面话不多说&#xff0c;请看介绍&#xff1a; 如果您要离开电脑而又不想别人使用&#xff0c;仲么办&#xff1f;使用WindowsL键锁屏&#x…

PHP 定时任务方法封装

在PHP中&#xff0c;可以使用Cron表达式来进行定时任务的调度。以下是一个简单的示例&#xff0c;展示如何封装一个定时任务方法&#xff1a; function scheduleTask($cronExpression, $taskCallback) {$cron Cron\CronExpression::factory($cronExpression);$nextRunDate $…