上次编写的文章 韩式浪漫 - 落雪唯美,我们整了个雪花的效果。
咦,那么我们可不可以扩展下,整一个 黑客帝国矩阵雨的效果
呢?
答案是肯定的,下面来整活。
该效果主要完成的功能有两点:
- 矩阵雨绘制
- 红蓝药丸编写
矩阵雨绘制
我们同样使用 canvas
来实现。基本思路如下:
- 初始化画布,画笔
- 初始化矩阵雨有多少列
- 用
0
和1
的初始化绘制的字符串 - 在画布上绘制,以随机的
0
和1
填充,计算绘制的x
和y
轴的距离,并重复绘制 - 监听视图窗口的更改,更新画布的大小和矩阵雨多少列的数据
实现的代码不多,这里贴上 JavaScript
文件的代码。代码即文档,若难以理解,请结合代码中的注释去学习。
(function() {
let canvas = document.getElementById('canvas'); // 画布
let ctx = canvas.getContext('2d'); // 画笔
let width = canvas.width = window.innerWidth; // 设置 canvas 的大小,然后赋值给 width,方便后面的计算
let height = canvas.height = window.innerHeight;
let font = 12;
let cols = 0;
let dys = []; // 垂直距离的移动距离数组
let matrix = '';
let matrixSize = 20; // 矩阵雨的随机数量
for(let i = 0; i < matrixSize; i += 1) {
matrix += Math.floor(Math.random() * 2);
}
initData();
// 初始化关键数据
function initData() {
// 列数据
cols = width / font;
// 随机生成 dy 垂直移动的距离
for(let i = 0; i < cols; i += 1) {
dys[i] = Math.floor(Math.random() * cols);
}
}
function draw(){
// ctx.clearRect(0, 0, width, height);
ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
ctx.fillRect(0, 0, width, height); // 填充画布
ctx.fillStyle = "#00ff00";
ctx.font = `${font}px`;
for(let i = 0; i < cols; i += 1) {
let txt = matrix[Math.floor(Math.random() * matrixSize)];
ctx.fillText(txt, i * font, dys[i] * font);
if(dys[i] * font > height) {
dys[i] = Math.floor(Math.random() * cols);
}
dys[i] += 1; // 垂直距离的设置
}
requestAnimationFrame(draw); // 重新绘制
}
draw();
// 监听窗口更改
window.addEventListener('resize', () => {
// 重置画布的大小
width = canvas.width = window.innerWidth;
height = canvas.height = window.innerHeight;
// 重新初始化关键数据
initData();
});
})()
需要注意的是,draw()
函数中,不可添加 ctx.clearRect(0, 0, width, height);
代码,不然就是雪花飘落的效果了。读者可以放开该代码,自行验证。
clearRect 是清空画布的指定区域
疑问点🤔️?细心的读者可能会提问:怎么效果图看起来有种类似拖尾的渐变效果?
这就很有意思了。但是实现挺简单的。你可以想象一下,写上文字的多个半透明的纸张依次叠加在一起的场景。也就是下面代码实现的功能:
// 透明度是 0.05 的黑色颜料
ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
ctx.fillRect(0, 0, width, height); // 填充画布
初始化绘制是 0.05
的透明度,第二次绘画的时候,初始化的透明度视觉效果增加到了 0.1
,依次类推 0.15
,0.2
.... 一直到 1.0
或以上的时候,你就对初始化的绘制文字看不出了。
红蓝药丸编写
我们通过 css
来实现 -- box-shadow 和 linear-gradient 并结合 ::before
或者 ::after
伪元素。
// 这里使用 less 预处理器编写
.pill{
position: relative;
width: @pillWidth;
height: @pillHeight;
border-radius: @pillRadius;
// 高亮
box-shadow: 0 1px 10px rgba(255,255,255,.1),
0 15px 10px rgba(255,255,255,.1),
0 0 10px rgba(255,255,255,.1),
0 -5px 5px rgba(255,255,255,.4);
}
// 红色药丸
.red {
background: linear-gradient(180deg,#ff4213 0%,#ab4225 100%) ,
linear-gradient(180deg,#ff4213 0%,#ab4225 100%);
}
// 蓝色药丸
.blue {
background: linear-gradient(180deg,#0000ff 0%,#add8e6 100%),
linear-gradient(180deg,#0000ff 0%,#add8e6 100%);
}
.pill:after{
content: '';
display: block;
position: absolute;
top: 0;
left: 0;
width: @pillWidth;
height: @pillHeight;
border-radius: @pillRadius;
// 阴影
box-shadow: 0 0 15px rgba(56,56,56,.7) inset, // inset 表明内阴影
0 0 5px rgba(23,23,23,.5) inset,
0 -7.5px 5px rgba(23,23,23,.5) inset,
0 0 1.5px rgba( 0, 255, 0,.3),
0 9px 20px rgba( 0, 255, 0,.4),
-1.5px 0 3px rgba(0,0,0,.4) inset,
1.5px 0 1.5px rgba(0,0,0,.4) inset,
0 5px 5px rgba( 0, 255, 0, .1),
0 6px 5px rgba( 0, 255, 0, .2),
0 12px 10px rgba( 0, 255, 0,.4);
}
整体效果
实现的体验效果如下,读者可以进入阅读全部的代码👇
推荐阅读
- 韩式浪漫 - 落雪唯美 本文的灵感来源
- 创建水平滚动的正确方式【CSS 网格布局】 合理布局水平滚动