【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 ο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>

END

相关推荐
某柚啊1 天前
iOS移动端H5键盘弹出时页面布局异常和滚动解决方案
前端·javascript·css·ios·html5
huangql5202 天前
截图功能技术详解:从原理到实现的完整指南
前端·html5
java水泥工3 天前
基于Echarts+HTML5可视化数据大屏展示-电信厅店营业效能分析
前端·echarts·html5·大屏展示
月光技术杂谈3 天前
用Deepseek 实现一个基于web的扣图应用
前端·javascript·html5·ccs·tensorflow.js·canvas api
.生产的驴4 天前
React useEffect组件渲染执行操作 组件生命周期 监视器 副作用
前端·css·react.js·ajax·前端框架·jquery·html5
ZTLJQ5 天前
植物大战僵尸HTML5游戏完整实现教程
前端·游戏·html5
Hello123网站5 天前
300多个Html5小游戏列表和下载地址
前端·html·html5
rising start6 天前
前端基础一、HTML5
前端·html·html5
tryCbest7 天前
Html5实现弹出表单
html5
xhload3d7 天前
智慧钢厂高炉冶炼仿真分析 | 图扑数字孪生
3d·智慧城市·html5·webgl·数字孪生·可视化·热力图·智慧工厂·工业互联网·工业组态·高炉炼铁·数字工厂·高炉炉体·智慧高炉·高炉