React 大屏可视化实战:Three.js 与 WebSocket 实时监控系统构建

大屏可视化项目一直是前端开发中非常有挑战性的领域,它需要同时兼顾数据实时性、视觉冲击力和交互体验。本文将分享我从零构建一个安全消防演练大屏监控系统的完整过程,涵盖技术选型、架构设计、核心实现和踩坑经验。
视频
项目背景
项目目标是为消防应急指挥中心打造一个实时监控大屏平台,用于管理建筑群的消防演练、设备状态和告警信息。核心需求包括:
- 实时数据推送 — 告警、设备状态、演练进度需要秒级更新
- 3D 场景可视化 — 在三维地图上直观展示设备分布和状态
- 多维度数据图表 — 演练趋势、设备统计、建筑风险评估
- 赛博朋克风格 UI — 科技感暗色主题,适合大屏展示
技术架构
整体方案
项目采用 Monorepo 架构,使用 pnpm workspace 管理前后端:
bigScreen/
├── apps/
│ ├── front-end/ # React + Vite + TailwindCSS
│ ├── server/ # NestJS + TypeORM + PostgreSQL
│ └── ui/ # 共享 UI 组件库
├── docker-compose.yml # Redis + PostgreSQL 容器编排
└── pnpm-workspace.yaml
前端技术栈
| 技术 | 用途 |
|---|---|
| React 18 + TypeScript | UI 框架 |
| Vite 6 | 构建工具,热更新极快 |
| Three.js + React Three Fiber | 3D 场景渲染 |
| Recharts | 数据图表 |
| Socket.io | WebSocket 实时通信 |
| Zustand | 状态管理 |
| TailwindCSS | 样式方案 |
后端技术栈
| 技术 | 用途 |
|---|---|
| NestJS 11 | 企业级 Node.js 框架 |
| TypeORM + PostgreSQL | 数据持久化 |
| Redis | 缓存和消息队列 |
| Socket.io | WebSocket 服务端 |
| Passport + JWT | 认证授权 |
核心实现
1. WebSocket 实时数据推送
大屏最核心的需求就是"实时"。传统的轮询方案延迟高且浪费资源,WebSocket 是最佳选择。
后端 WebSocket 网关:
@WebSocketGateway({ cors: true })
export class WebsocketGateway {
@WebSocketServer()
server: Server;
// 客户端订阅频道
@SubscribeMessage('subscribe')
handleSubscribe(client: Socket, channels: string[]) {
channels.forEach(ch => client.join(ch));
}
// 向指定频道广播
broadcast(channel: string, event: string, data: unknown) {
this.server.to(channel).emit(event, data);
}
}
前端自定义 Hook:
const { isConnected, onAlert, onDeviceStatus } = useWebSocket({
autoConnect: true,
subscriptions: ['alerts', 'devices', 'metrics']
});
// 订阅告警事件,自动管理生命周期
useEffect(() => {
return onAlert((data) => {
notifications.push(data);
});
}, [onAlert]);
通过频道订阅机制,前端只接收自己关心的数据,避免不必要的网络开销。
2. Three.js 3D 场景渲染
使用 React Three Fiber 将 Three.js 与 React 无缝集成,实现设备在 3D 空间中的可视化:
<Canvas camera={{ position: [0, 30, 40], fov: 55 }}>
{/* 地面网格 */}
<gridHelper args={[60, 40, '#06b6d4', '#083344']} />
<mesh>
<planeGeometry args={[60, 40]} />
<meshStandardMaterial color="#0a1628" />
</mesh>
{/* 设备标记点 — 颜色反映实时状态 */}
{devices.map(d => (
<DeviceMarker key={d.id} device={d} />
))}
{/* 交互控制 */}
<OrbitControls enablePan enableZoom enableRotate />
</Canvas>
设备标记使用三色状态球(绿色正常 / 黄色警告 / 红色告警),配合脉冲环动画让状态一目了然。
3. 数据可视化图表
使用 Re
charts 绘制演练趋势图,支持多数据源叠加和自动实时更新:
<AreaChart data={drillData}>
<defs>
<linearGradient id="colorFire" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#EF4444" stopOpacity={0.3} />
<stop offset="95%" stopColor="#EF4444" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" stroke="#1e293b" />
<Area type="monotone" dataKey="fireDrills"
stroke="#EF4444" fill="url(#colorFire)" />
<Area type="monotone" dataKey="safetyTrainings"
stroke="#3B82F6" fill="url(#colorTraining)" />
</AreaChart>
图表每 3 秒通过 WebSocket 接收新数据并自动更新,实现真正的实时可视化。
4. 赛博朋克 UI 特效
大屏项目的视觉冲击力至关重要。我实现了几种标志性的赛博朋克特效:
数字雨(Matrix Rain):
使用 Canvas 逐帧绘制垂直下落的字符流,营造《黑客帝国》般的科技氛围
// 每列独立的下落速度和字符
columns.forEach((y, i) => {
const char = chars[Math.floor(Math.random() * chars.length)];
ctx.fillStyle = '#06b6d4';
ctx.fillText(char, i * fontSize, y * fontSize);
if (y * fontSize > canvas.height && Math.random() > 0.975) {
columns[i] = 0; // 重置到顶部
}
columns[i]++;
});
粒子场动画:
粒子在画布中运动、碰撞、连线,形成动态的网络效果作为背景装饰。
扫描线 + 发光特效:
通过 TailwindCSS 自定义动画实现:
// tailwind.config.js
keyframes: {
scan: {
'0%': { transform: 'translateY(0)' },
'100%': { transform: 'translateY(100vh)' }
},
glow: {
'0%, 100%': { boxShadow: '0 0 5px rgba(6,182,212,0.5)' },
'50%': { boxShadow: '0 0 20px rgba(6,182,212,0.8)' }
}
}
5. 数据安全方案
生产环境采用 AES-256-CBC 端到端加密:
- 前端使用
crypto-js加密请求体 - 后端通过 NestJS 拦截器自动解密请求、加密响应
- 封装
encryptedFetch工具函数,对业务代码完全透明
部署方案
采用 Docker 容器编排,Nginx 反向代理:
# docker-compose.yml
services:
postgres:
image: postgres:15
ports: ["5432:5432"]
redis:
image: redis:7-alpine
ports: ["6379:6379"]
前后端分别构建部署,通过 Nginx 配置域名和 SSL:
- 前端:
www.bigscreen.xingzdh.com - 后端 API:
www.bigscreen-api.xingzdh.com
踩坑与经验
Three.js 性能优化
3D 场景在大量设备标记时容易出现性能问题,关键优化:
- 实例化渲染(InstancedMesh)— 相同几何体共享一个绘制调用
- 视锥体剔除 — 只渲染摄像机可见范围内的对象
- LOD(细节层次) — 远距离设备使用简化模型
WebSocket 重连机制
网络不稳定时 WebSocket 断开很常见,需要实现指数退避重连:
const reconnect = (attempt: number) => {
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
setTimeout(() => socket.connect(), delay);
};
大屏适配方案
大屏分辨率多样(1080P、2K、4K),采用 rem + vw 混合方案:
- 基准字号根据屏幕宽度动态计算
- 布局使用 Grid + Flex 弹性组合
- 关键数字使用等宽字体(Orbitron)保证对齐
总结
这个项目让我对以下领域有了更深入的理解:
- **Web
- Socket 实时架构** — 频道订阅、心跳检测、断线重连的完整方案
- Three.js 工程化 — React Three Fiber 让 3D 开发融入 React 生态
- 大屏视觉设计 — 暗色主题、发光特效、动画节奏的平衡
- Monorepo 实践 — pnpm workspace 管理全栈项目的效率优势
- 数据安全 — 前后端加密通信的工程化落地
大屏可视化不只是"把图表放大",它是对数据理解、视觉设计和工程能力的综合考验。希望这篇文章能为正在做类似项目的你提供一些参考。
在线预览: www.bigscreen.xingzdh.com
体验账号:
operator@qq.com/operator123456项目源码: GitHub - bigScreen