【关键点】
使字变亮是将rgba中的alpha值提升的结果,反之即将文字变暗;
光源照亮文字是靠判断文字与光源间的距离决定的,离光源越近,其alpha值就越大。
【效果】
【代码】
<!DOCTYPE html>
<html lang="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<head>
<title>移动光源照亮墙上的字</title>
</head>
<body οnlοad="draw()">
<canvas id="myCanvas" width="100px" height="100px" style="border:0px dashed black;">
出现文字表示您的浏览器不支持HTML5
</canvas>
</body>
</html>
<script type="text/javascript">
<!--
/*****************************************************************
* 将全体代码(从<!DOCTYPE到script>)拷贝下来,粘贴到文本编辑器中,
* 另存为.html文件,再用chrome浏览器打开,就能看到实现效果。
******************************************************************/
// 常量画布宽
const Width=1200;
// 常量画布高
const Height=512;
// 文本字体大小
const FontSize=18;
// 绘图上下文
var context;
// 舞台对象
var stage;
// 肇始函数
function draw(){
// 初始化canvas
var canvas=document.getElementById('myCanvas');
canvas.width=Width;
canvas.height=Height;
context=canvas.getContext('2d');
// 准备舞台
stage=new Stage();
stage.init();
// 开幕
animate();
};
// 循环播放动画
function animate(){
stage.update();
stage.paintBg(context);
stage.paintFg(context);
if(true){
// 延时执行以免下坠太快
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
delay(90).then(() => {
window.requestAnimationFrame(animate);
});
}
}
// 舞台类
function Stage(){
// 此数组存储字位置,内容,透明度
this.letters=new Array();
// 光源
this.light={};
// 初始化粒子
this.init=function(){
var colCnt = Math.floor(Width / FontSize) ;// 列数
var rowCnt = Math.floor(Height/FontSize); // 行数
for(let i = 0;i<colCnt ; i++){
for(let j = 0;j<rowCnt ; j++){
var item={};
// x就是所在列
item.x=i*FontSize;
// y取随机数
item.y=j*FontSize;
// 取随机文字
item.text=getText();
// 透明度取最大
item.alpha=1.0;
this.letters.push(item);
}
}
// 光源初始位置
this.light.x=0;
this.light.y=Height/2+100;
}
// 更新
this.update=function(){
this.letters.forEach(function (item, i) {
// 按字到光源的距离设定不同的透明度
let distence=Math.sqrt((item.x-stage.light.x)*(item.x-stage.light.x)+(item.y-stage.light.y)*(item.y-stage.light.y));
if(distence<25){
item.alpha=1;
}else if(distence<50){
item.alpha=0.5;
}else if(distence<100){
item.alpha=0.25;
}else{
item.alpha=0;
}
// 让字的透明度自然滑落,以达到字渐渐隐落的效果
if(item.alpha<=0){
item.alpha=0;
}else{
item.alpha-=0.05;
}
});
// 用正弦曲线去改变光源位置
this.light.x+=5;
this.light.y+=Math.sin(this.light.x*10)*30;
if(this.light.x>Width){
this.light.x=0;
this.light.y=Height/2+100;
}
};
// 画背景
this.paintBg=function(ctx){
// ctx.fillStyle="black"; // 如此只是单字被照亮
ctx.fillStyle = "rgba(0, 0, 0, 0.07)";// 加上半透明蒙层,字和光源便出现了残影效果
ctx.fillRect(0,0,Width,Height);
// 作者标识
ctx.fillStyle="white";
ctx.font="12px Arial";
ctx.fillText("光源照字特效 by:逆火",Width-160,Height-15);
};
// 画前景
this.paintFg=function(ctx){
// 画被照亮的字
this.letters.forEach(function (item, i) {
ctx.fillStyle = "rgba(0, 219, 0, "+item.alpha+")";
ctx.font = FontSize + "px consolas";
ctx.fillText(item.text,item.x, item.y);
})
// 画圆表示光源
ctx.fillStyle="#ff0";
ctx.beginPath();
ctx.arc(this.light.x,this.light.y,20,0,Math.PI*2,true);
ctx.closePath();
ctx.fill();
};
}
// 取显示的文字
function getText(){
var sentence="甲乙丙丁戊己庚辛壬癸子丑寅卯辰巳午未申酉戌亥乾☷坤☵坎☲离☳震☶艮☴巽☱兑";
var n=sentence.length;
var i=Math.random()*n;
return sentence.charAt(i);
}
/*----------------------------------
这世上有的地方,
因为不断鞭挞黑暗而获得光明;
也有的地方,
因为总是粉饰黑暗,
而堕入了更深的深渊。
----------------------------------*/
//-->
</script>