【Canas与艺术】模拟手电照亮墙壁上的字,有点摸金校尉的感觉
【关键点】
手电光画黄色半透明实心圆,字被照亮按距手电远近定透明度。
【效果图】
【代码】
<!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