【Canvas与艺术】移动光源照亮墙上的字
【关键点】
使字变亮是将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 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(); // 开幕 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>
END