|
|
请马上登录,朋友们都在花潮里等着你哦:)
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 马黑黑 于 2022-8-14 09:41 编辑
我们需要在 HTML5 画布 canvas 上模拟字符雨。帖子尺寸应受到帖子外框限制,所以设定必要的CSS:
<style>
#papa { left: -214px; width: 1024px; height: 640px; background: black url('/data/attachment/forum/202208/14/074919yeeelef1ee9yj1en.jpg') no-repeat center/cover; box-shadow: 3px 3px 20px #000; position: relative; }
#canv { position: absolute; opacity: .75; }
</style>
父框有背景图,所以给画布设置一点点透明度(opacity: .75),令背景图片隐约可见。
接着是HTML代码:
<div id="papa">
<canvas id="canv" width="1024" height="640"></canvas>
</div>
HTML中,暂时没有其他元素,仅是父元素+画布这么简单的结构,以减少对核心代码理解的干扰。
下面是重点,JS部分。说明一下,下面的解释会用到两个变量,w、h,它们是画布的宽高,赋值方法在后面所附的帖子完整代码里可以找到。
首先解决输出的字符问题。第一,我们需要一个字符集合,用一个数组变量存储,它可以是酱紫:
let texts = ('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ').split('');
或更简单,反正只要有合适的字符集合就成。为了高逼格,这回我们把键盘上的可打印字符都用上,其实也不多吧,对应的ASCII码,十进制的32是空格,我们不要,就从33开始,然后最后一个是 ~,十进制编码是126,这样总共94个,可以用js内置方法 String.fromCharCode(编码) 获得字符:
let texts = Array.from(Array(94), (x,k) => String.fromCharCode(33+k));
上面语句,我们用JS高效的构建数组方法之一,快速建立了一个 texts 数组,根据ASCII对照表,它应该包含的字符是键盘常规键位上可打印输出的字符,总之比数字加字母的字符丰富,给马上营造出来的代码雨增添更多的字符样式。
第二,设计字符输出列。将来,随机出现的字符应该是自左向右依次排列开来,一列能有多少个字符需要计算,而这个计算又得依据单个字符的宽度,所以,我们还需要几个变量:
let fontsize = 16; //设定字号
let columns = Math.floor(w / fontsize) - 1; //计算所需列 :宽度除以字宽的列数,用Math.floor确保是整数,再减1(并配套后续的操作)让字符不顶边
let drops = new Array(columns); //根据列数创建一个空 drops 数组,将来用于装载每个输出字符的相关信息
以上这些变量,在JS里,可以合起来一同声明,只用一个 let 关键字(声明的变量间用小角逗号隔开,可以分行写也可以不分行):
let texts = Array.from(Array(94), (x,k) => String.fromCharCode(33+k)), //字符集
fontsize = 16, //字号
columns = Math.floor(w / fontsize) - 1, //列数
drops = new Array(columns); //输出列中单字标识数组,存储输出行的单字标识
最后,我们编写一个立即执行函数,就大功告成:
(function draw(){
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; //一定透明度的填充色
ctx.fillRect(0, 0, w, h); //用上面底色覆盖画布(以保留字符落下的痕迹,其实是拖尾效果的应用)
//ctx.clearRect(0,0,w,h); //清空画布 测试用 :观察字符落下的行为等
ctx.fillStyle = '#0f0'; //字符填充颜色
ctx.font = fontsize + 'px arial'; //设定字体
//下面用for语句根据drops数组处理每一个输出的字符
for(var j = 0; j < drops.length; j ++){
let text = texts[Math.floor(Math.random() * texts.length)]; //随机从字符集合数组texts中获得输出字符
ctx.fillText(text, j * fontsize + fontsize / 2 + 1, drops[j] * fontsize); //该字符输出:X坐标和Y坐标均与字宽息息相关
//下面设定两种可能:字符对应的 drops 数组元素如果大于 h(画布高度)或大于一个随机数,这两种可能,只要符
//合其中一个,则令元素值为0重头再来,如此反复,从而形成字符雨的错落感 //字符高度如果大于画布高度 或 伪随机数大于 0.95 (Math.random() 取值在 0-0.99999... 之间)
if(drops[j]*fontsize > h || Math.random() > 0.95){
drops[j] = 0;
}
drops[j]++; //字符对应的数组元素值自增(其值初始时为空,++表示加1,空值加任何数空值就是数值,JS的宽松变量类型特性
}
requestAnimationFrame(draw); //请求动画帧
//setTimeout(draw, 34); //如果需要控制代码雨下落速度,可以考虑使用这个替代请求动画帧
})();
【附】本机测试用的帖子完整代码
<style>
#papa { margin: auto; width: 1024px; height: 640px; background: black url('pic/hacker.jpg') no-repeat center/cover; box-shadow: 3px 3px 20px #000; position: relative; }
#canv { position: absolute; opacity: .75; }
#disc { position: absolute; width: 40px; height: 40px; left: 10px; bottom: 10px; background: conic-gradient(red,orange,yellow,green,teal,blue,purple); mask: radial-gradient(transparent 4px,red 0); -webkit-mask: radial-gradient(transparent 4px,red 0); border-radius: 50%; cursor: pointer; animation: rot 2s linear infinite; }
#lrcbox { position: absolute; left: 60px; bottom: 10px; font: bold 22px / 40px sans-serif; color: #859670; text-shadow: 2px 2px 4px #222; }
@keyframes rot { to { transform: rotate(360deg); } }
</style>
<div id="papa">
<span id="lrcbox">黑客帝国</span>
<canvas id="canv" width="1024" height="640"></canvas>
<span id="disc"></span>
</div>
<script type="text/javascript">
let ctx = canv.getContext('2d');
let w = canv.width, h = canv.height;
let texts = Array.from(Array(94), (x,k) => String.fromCharCode(33+k)),
fontsize = 16,
columns = Math.floor(w / fontsize) - 1,
drops = new Array(columns),
aud = new Audio();
aud.src = 'https://music.163.com/song/media/outer/url?id=1809135506.mp3';
aud.loop = true;
aud.autoplay = true;
disc.style.animationPlayState = aud.paused ? 'paused' : 'running';
disc.onclick = () => aud.paused ? aud.play() : aud.pause();
aud.addEventListener('playing',() => disc.style.animationPlayState = 'running');
aud.addEventListener('pause',() => disc.style.animationPlayState = 'paused');
(function draw(){
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
ctx.fillRect(0, 0, w, h);
ctx.fillStyle = '#0f0';
ctx.font = fontsize + 'px arial';
for(var j = 0; j < drops.length; j ++){
let text = texts[Math.floor(Math.random() * texts.length)];
ctx.fillText(text, j * fontsize + fontsize / 2 + 1, drops[j] * fontsize);
if(drops[j]*fontsize > h || Math.random() > 0.95){
drops[j] = 0;
}
drops[j]++;
}
requestAnimationFrame(draw);
})();
</script>
|
评分
-
| 参与人数 3 | 威望 +130 |
金钱 +260 |
经验 +130 |
收起
理由
|
加林森
| + 30 |
+ 60 |
+ 30 |
很给力! |
小辣椒
| + 50 |
+ 100 |
+ 50 |
赞一个! |
红影
| + 50 |
+ 100 |
+ 50 |
赞一个! |
查看全部评分
|