【关键点】
手电光画黄色半透明实心圆,字被照亮按距手电远近定透明度。
【效果图】
【代码】
<!DOCTYPE html>
<html lang="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<head>
<title>手电照亮墙上的字</title>
</head>
<body onload="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();
// 取鼠标位置
canvas.onmousemove = function(e) {
// 计算鼠标在 canvas 内的位置
var rect = canvas.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
// 输出鼠标位置
//console.log('Mouse position: x=' + x + ', y=' + y);
stage.light.x=x;
stage.light.y=y;
};
// 开幕
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.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 if(distence<150){
item.alpha=0.125;
}else{
item.alpha=0;
}
// 让字的透明度自然滑落,以达到字渐渐隐落的效果
if(item.alpha<=0){
item.alpha=0;
}else{
item.alpha-=0.05;
}
});
};
// 画背景
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="rgba(140,140,0,0.3)";
ctx.beginPath();
ctx.arc(this.light.x,this.light.y,40,0,Math.PI*2,true);
ctx.closePath();
ctx.fill();
// 内圈
ctx.fillStyle="rgba(196,196,0,0.5)";
ctx.beginPath();
ctx.arc(this.light.x,this.light.y,10,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>
END