欢迎加入开源鸿蒙PC社区:
https://harmonypc.csdn.net/

atomgit仓库地址: https://atomgit.com/m0_66062719/shuziyudonghuajishu
在这里插入图片描述

在这里插入图片描述

1. 项目概述

1.1 背景介绍

数字雨(Digital Rain)是经典科幻电影《黑客帝国》中标志性的视觉效果,由绿色字符从屏幕顶部倾泻而下,营造出强烈的科技感和未来感。本文详细介绍如何在鸿蒙PC平台上,基于Electron框架实现这一经典动画效果。

1.2 技术选型

维度技术版本选型理由
框架Electron18.x跨平台桌面应用框架,支持Web技术栈
渲染引擎Chromium95+高性能WebGL/Canvas支持
语言JavaScriptES6+异步编程友好,适合动画开发
UI技术HTML5 Canvas-原生2D图形渲染,性能优异
样式CSS3-现代样式特性,支持动画和渐变

1.3 功能特性

本项目实现了一个功能丰富的数字雨动画应用,主要特性包括:

  • 多种字符集支持:日文汉字、平假名、片假名、二进制、十六进制、数字、英文字母、混合模式
  • 实时参数调节:下落速度、字符密度、字体大小、颜色自定义
  • 播放控制:开始、暂停、重置功能
  • 实时状态监控:帧率显示、粒子数量统计
  • 响应式设计:自动适应窗口大小变化

2. 架构设计

2.1 整体架构

┌─────────────────────────────────────────────────────────────┐
│                      Electron主进程                         │
├─────────────────────────────────────────────────────────────┤
│  main.js                                                    │
│  ├── 创建BrowserWindow                                      │
│  ├── 加载HTML页面                                           │
│  └── 菜单与快捷键管理                                        │
└─────────────────────────────────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────────┐
│                      渲染进程                                │
├─────────────────────────────────────────────────────────────┤
│  digital_rain.html                                          │
│  ├── Canvas画布层(渲染数字雨)                              │
│  ├── 控制面板层(参数调节UI)                                │
│  └── 信息展示层(FPS/粒子数)                                │
├─────────────────────────────────────────────────────────────┤
│  digital_rain.js                                            │
│  ├── DigitalRain类(核心逻辑)                               │
│  ├── 字符管理模块                                           │
│  ├── 动画渲染模块                                           │
│  └── 事件监听模块                                           │
└─────────────────────────────────────────────────────────────┘

2.2 核心组件职责

组件职责关键方法
DigitalRain主控制器,协调整体逻辑constructor, init, animate, draw
字符管理管理不同字符集的切换charSets, getRandomChar, setCharSet
动画渲染Canvas绑定绘制draw, updateFps, resizeCanvas
事件监听用户交互处理setupEventListeners

2.3 数据流

用户操作 → DOM事件 → DigitalRain方法 → Canvas重绘
    ↓
参数变化 → 状态更新 → 下一帧渲染

3. 核心代码实现

3.1 主入口HTML结构

HTML页面采用三层结构设计:Canvas画布层负责渲染动画,控制面板层提供参数调节,信息展示层显示实时状态。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数字雨动画</title>
    <style>
        html, body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            background: #000;
            margin: 0;
            padding: 0;
        }
        #canvas {
            display: block;
            width: 100%;
            height: 100%;
        }
        .controls {
            position: fixed;
            top: 20px;
            left: 20px;
            background: rgba(0, 0, 0, 0.7);
            padding: 20px;
            border-radius: 12px;
            color: #00ff41;
            font-family: 'Courier New', monospace;
            z-index: 100;
            backdrop-filter: blur(10px);
            border: 1px solid rgba(0, 255, 65, 0.3);
        }
        .info {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: rgba(0, 0, 0, 0.7);
            padding: 15px;
            border-radius: 8px;
            color: #00ff41;
            font-family: 'Courier New', monospace;
            font-size: 12px;
            border: 1px solid rgba(0, 255, 65, 0.3);
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <div class="controls">
        <!-- 控制面板内容 -->
    </div>
    <div class="info">
        <p>帧率: <span id="fps">0</span> FPS</p>
        <p>粒子数: <span id="particles">0</span></p>
    </div>
    <script src="digital_rain.js"></script>
</body>
</html>

设计要点:

  1. 全屏Canvas:设置Canvas为全屏显示,使用display: block消除默认边距
  2. 固定定位控件:控制面板和信息面板使用position: fixed固定在屏幕角落
  3. 毛玻璃效果:通过backdrop-filter: blur(10px)实现现代感的半透明效果
  4. 科技风格配色:使用经典的绿色(#00ff41)作为主色调,配合黑色背景

3.2 DigitalRain核心类实现

这是整个应用的核心,负责初始化、渲染和控制数字雨动画。

class DigitalRain {
    constructor() {
        this.canvas = document.getElementById('canvas');
        this.ctx = this.canvas.getContext('2d');
        this.columns = [];
        this.charSets = {
            kanji: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン',
            hiragana: 'あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん',
            katakana: 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン',
            binary: '01',
            hex: '0123456789ABCDEF',
            numbers: '0123456789',
            alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
            mix: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789アイウエオかきくけこ'
        };
        this.currentCharSet = this.charSets.kanji;
        this.fontSize = 20;
        this.speed = 3;
        this.density = 50;
        this.color = '#00ff41';
        this.isRunning = false;
        this.animationId = null;
        this.fps = 0;
        this.frameCount = 0;
        this.lastFpsUpdate = Date.now();
        this.resizeCanvas();
        this.setupEventListeners();
        this.init();
    }
}

核心属性说明:

属性类型说明
canvasHTMLCanvasElementCanvas元素引用
ctxCanvasRenderingContext2D2D渲染上下文
columnsArray存储所有下落列的数据
charSetsObject字符集映射表
currentCharSetString当前使用的字符集
fontSizeNumber字符大小(px)
speedNumber基础下落速度
densityNumber列密度百分比
colorString字符颜色
isRunningBoolean动画运行状态
animationIdNumberrequestAnimationFrame返回ID
fpsNumber当前帧率

3.3 初始化与列数据结构

init()方法负责初始化列数据,根据屏幕宽度和字体大小计算列数量,并为每列生成初始状态。

init() {
    const columnsCount = Math.floor(this.canvas.width / this.fontSize);
    this.columns = [];
    
    for (let i = 0; i < columnsCount; i++) {
        if (Math.random() * 100 < this.density) {
            this.columns.push({
                x: i * this.fontSize,
                y: Math.random() * -this.canvas.height,
                chars: [],
                length: Math.floor(Math.random() * 15) + 5,
                speed: this.speed + Math.random() * 2
            });
        }
    }
    this.start();
}

列数据结构详解:

字段类型说明
xNumber列的X坐标位置
yNumber列顶部的Y坐标(初始为负值表示在屏幕外)
charsArray当前列显示的字符数组
lengthNumber列的字符长度(5-19随机)
speedNumber该列的下落速度(基础速度+随机偏移)

设计亮点:

  1. 密度控制:通过Math.random() * 100 < this.density控制列的生成概率
  2. 随机起始位置y: Math.random() * -this.canvas.height使各列起始位置错落有致
  3. 随机列长度:每列长度在5-19之间随机,形成自然的视觉效果
  4. 速度差异化:每列速度略有不同,避免机械感

3.4 核心渲染方法draw()

draw()方法是动画的核心,每帧都会被调用,负责清空画布、绘制所有字符列,并更新状态。

draw() {
    this.ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
    this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
    
    this.ctx.font = `${this.fontSize}px 'Courier New', monospace`;
    
    this.columns.forEach((column) => {
        for (let i = 0; i < column.chars.length; i++) {
            const char = column.chars[i];
            const y = column.y + i * this.fontSize;
            
            if (y > this.canvas.height) continue;
            
            const gradient = this.ctx.createLinearGradient(
                column.x, y - column.length * this.fontSize,
                column.x, y
            );
            
            const opacity = 1 - (i / column.length);
            gradient.addColorStop(0, `rgba(0, 255, 65, 0)`);
            gradient.addColorStop(0.5, `rgba(0, 255, 65, ${opacity * 0.5})`);
            gradient.addColorStop(1, this.color);
            
            this.ctx.fillStyle = i === column.chars.length - 1 ? '#ffffff' : gradient;
            this.ctx.fillText(char, column.x, y);
        }
        
        if (Math.random() < 0.01) {
            column.chars[0] = this.getRandomChar();
        }
        
        if (column.chars.length < column.length) {
            column.chars.push(this.getRandomChar());
        }
        
        column.y += column.speed;
        
        if (column.y > this.canvas.height && column.chars.length > 0) {
            column.chars.shift();
        }
    });
    
    this.updateFps();
}

渲染流程详解:

┌─────────────────────────────────────────────────────┐
│  1. 绘制半透明遮罩(产生拖尾效果)                    │
│     fillStyle: rgba(0, 0, 0, 0.05)                 │
├─────────────────────────────────────────────────────┤
│  2. 遍历每一列                                      │
│     ├─ 遍历列中每个字符                             │
│     │   ├─ 计算字符位置                            │
│     │   ├─ 创建渐变效果                            │
│     │   └─ 绘制字符(头部白色,其余渐变)           │
│     ├─ 随机替换首字符(动态效果)                   │
│     ├─ 填充新字符(列增长)                         │
│     ├─ 更新Y坐标(下落)                           │
│     └─ 移除超出屏幕的字符                         │
├─────────────────────────────────────────────────────┤
│  3. 更新帧率统计                                    │
└─────────────────────────────────────────────────────┘

关键技术点:

  1. 拖尾效果实现:使用rgba(0, 0, 0, 0.05)的半透明黑色覆盖整个画布,产生运动模糊效果
  2. 渐变透明度:通过线性渐变实现字符从上到下的透明度变化,顶端透明,底部清晰
  3. 头部高亮:列的最后一个字符(最下方)使用白色高亮,模拟电影中的效果
  4. 动态字符替换:1%概率替换列首字符,增加随机性和动感

3.5 动画控制机制

动画控制通过requestAnimationFrame实现流畅的60fps渲染,并提供开始、暂停、重置功能。

animate() {
    if (!this.isRunning) return;
    this.draw();
    this.animationId = requestAnimationFrame(() => this.animate());
}

start() {
    if (this.isRunning) return;
    this.isRunning = true;
    this.animate();
}

pause() {
    this.isRunning = false;
    if (this.animationId) {
        cancelAnimationFrame(this.animationId);
        this.animationId = null;
    }
}

reset() {
    this.pause();
    this.ctx.fillStyle = '#000';
    this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
    this.init();
}

设计考虑:

  1. 状态保护start()中检查isRunning避免重复启动
  2. 资源释放pause()中取消requestAnimationFrame避免内存泄漏
  3. 完全重置reset()清空画布后重新初始化,恢复初始状态

3.6 实时参数调节

应用支持动态调整各项参数,无需重启动画。

setSpeed(value) {
    this.speed = value;
    this.columns.forEach(column => {
        column.speed = this.speed + Math.random() * 2;
    });
}

setDensity(value) {
    this.density = value;
    const columnsCount = Math.floor(this.canvas.width / this.fontSize);
    const targetColumns = Math.floor((columnsCount * this.density) / 100);
    
    while (this.columns.length < targetColumns) {
        const newColumn = {
            x: Math.floor(Math.random() * columnsCount) * this.fontSize,
            y: Math.random() * -this.canvas.height,
            chars: [],
            length: Math.floor(Math.random() * 15) + 5,
            speed: this.speed + Math.random() * 2
        };
        const exists = this.columns.some(col => col.x === newColumn.x);
        if (!exists) {
            this.columns.push(newColumn);
        }
    }
    
    while (this.columns.length > targetColumns) {
        this.columns.pop();
    }
}

setFontSize(value) {
    this.fontSize = value;
    this.init();
}

setColor(value) {
    this.color = value;
}

setCharSet(type) {
    this.currentCharSet = this.charSets[type] || this.charSets.kanji;
}

参数调节策略:

参数调节方式是否需要重建
速度实时更新所有列的speed属性
密度动态增删列
字体大小重新初始化整个系统
颜色实时更新color属性
字符集实时切换currentCharSet

3.7 事件监听器设置

setupEventListeners()方法绑定所有用户交互事件。

setupEventListeners() {
    window.addEventListener('resize', () => {
        this.resizeCanvas();
        this.init();
    });

    document.getElementById('start-btn').addEventListener('click', () => this.start());
    document.getElementById('pause-btn').addEventListener('click', () => this.pause());
    document.getElementById('reset-btn').addEventListener('click', () => this.reset());

    document.getElementById('speed').addEventListener('input', (e) => {
        const value = parseInt(e.target.value);
        document.getElementById('speed-value').textContent = value;
        this.setSpeed(value);
    });

    document.getElementById('density').addEventListener('input', (e) => {
        const value = parseInt(e.target.value);
        document.getElementById('density-value').textContent = value;
        this.setDensity(value);
    });

    document.getElementById('font-size').addEventListener('input', (e) => {
        const value = parseInt(e.target.value);
        document.getElementById('font-size-value').textContent = value;
        this.setFontSize(value);
    });

    document.getElementById('color').addEventListener('input', (e) => {
        this.setColor(e.target.value);
    });

    document.getElementById('charset').addEventListener('change', (e) => {
        this.setCharSet(e.target.value);
    });
}

4. 性能优化策略

4.1 Canvas渲染优化

优化项实现方式效果
减少状态切换批量设置样式后统一绘制减少GPU状态切换开销
避免浮点数运算使用整数坐标提升渲染性能
复用渐变对象在循环外创建渐变减少对象创建开销
裁剪可见区域跳过屏幕外的字符减少无效绘制

4.2 帧率控制

updateFps() {
    this.frameCount++;
    const now = Date.now();
    
    if (now - this.lastFpsUpdate >= 1000) {
        this.fps = this.frameCount;
        this.frameCount = 0;
        this.lastFpsUpdate = now;
        document.getElementById('fps').textContent = this.fps;
        document.getElementById('particles').textContent = this.columns.length;
    }
}

通过每秒更新一次帧率显示,避免频繁DOM操作影响性能。

4.3 响应式处理

resizeCanvas() {
    this.canvas.width = window.innerWidth;
    this.canvas.height = window.innerHeight;
}

窗口大小变化时重新设置Canvas尺寸并初始化,确保全屏显示效果。


5. 鸿蒙PC平台适配

5.1 Electron配置要点

main.js中配置窗口属性以适配鸿蒙PC:

const { app, BrowserWindow } = require('electron');
const path = require('path');

function createWindow() {
    mainWindow = new BrowserWindow({
        width: 1200,
        height: 800,
        minWidth: 800,
        minHeight: 600,
        title: '数字雨动画',
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false,
        },
    });

    mainWindow.loadFile('digital_rain.html');
}

app.on('ready', createWindow);

5.2 鸿蒙平台特殊考虑

  1. 窗口适配:鸿蒙PC支持高DPI显示,需要确保Canvas正确处理分辨率
  2. 性能优化:针对鸿蒙PC硬件特性优化渲染性能
  3. 系统主题:考虑与鸿蒙系统深色模式的兼容性

6. 应用扩展

6.1 功能扩展建议

扩展功能实现思路
背景图片在Canvas下添加背景层
音频同步结合Web Audio API实现音乐可视化
鼠标交互鼠标位置影响字符下落方向
保存动画使用Canvas toDataURL导出GIF
预设主题提供多种配色方案选择

6.2 代码优化方向

// 优化建议:使用对象池复用字符对象
class CharObjectPool {
    constructor() {
        this.pool = [];
    }
    
    acquire() {
        return this.pool.length > 0 ? this.pool.pop() : {};
    }
    
    release(obj) {
        this.pool.push(obj);
    }
}

7. 总结

本文详细介绍了基于Electron框架在鸿蒙PC平台上实现数字雨动画的完整方案。核心技术点包括:

  1. Canvas 2D渲染:利用Canvas API实现高性能字符绘制
  2. 渐变效果:通过线性渐变模拟电影中的视觉效果
  3. 动态更新机制:使用requestAnimationFrame实现流畅动画
  4. 参数化设计:支持多种字符集和实时参数调节
  5. 响应式布局:自动适应窗口大小变化

该实现不仅还原了经典的数字雨效果,还提供了丰富的交互功能,为用户带来沉浸式的视觉体验。代码结构清晰,易于扩展和维护,适合作为学习Canvas动画和Electron开发的参考项目。


附录:完整文件清单

文件路径说明
digital_rain.html主HTML页面
digital_rain.js核心JavaScript逻辑
home.html应用中心入口(包含导航链接)
main.jsElectron主进程配置
Logo

赋能鸿蒙PC开发者,共建全场景原生生态,共享一次开发多端部署创新价值。

更多推荐