10分钟在UE里跑一个数据大屏
先说结论:你不需要懂前端,也不需要写 C++,10 分钟就能在 UE 里跑一个带实时图表、设备列表、告警面板的数据大屏,和三维场景联动。 跟着下面四步走,每一步都有完整代码,复制粘贴就能跑。
WebNativeBrowser 是面向 UE 5.1–5.8 的高性能企业级跨平台 Web UI 插件,提供 GPU 直通渲染、双向消息通道、透明交互和开箱即用的演示页面。

第 1 步:安装插件(2 分钟)
- 从 GitHub Release 下载你 UE 版本对应的 zip
- 解压到项目的
Plugins/目录下 - 目录名改成
WebNativeBrowser(⚠️ 必须是这个名字) - 重新打开项目
YourProject/
├── Plugins/
│ └── WebNativeBrowser/ ← 放这里
├── Content/
└── YourProject.uproject
打开项目后,编辑器会提示重新编译。编译完成即安装成功。
第 2 步:创建数据大屏页面(3 分钟)
在 YourProject/Content/WebUI/ 下创建 dashboard.html,复制以下代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; background: transparent; font-family: "Microsoft YaHei", sans-serif; }
.dashboard {
display: grid;
grid-template-columns: 300px 1fr 1fr;
grid-template-rows: 80px 1fr 1fr;
gap: 12px;
width: 100%;
height: 100%;
padding: 16px;
}
.header {
grid-column: 1 / -1;
background: linear-gradient(135deg, rgba(0,20,60,0.9), rgba(0,40,100,0.9));
border: 1px solid rgba(0,150,255,0.3);
border-radius: 8px;
display: flex; align-items: center; padding: 0 32px;
}
.header h1 { color: #00e5ff; font-size: 28px; letter-spacing: 4px; }
.device-panel {
grid-row: 2 / 4;
background: rgba(0,20,50,0.85);
border: 1px solid rgba(0,150,255,0.3);
border-radius: 8px;
padding: 16px;
overflow-y: auto;
}
.device-panel h3 { color: #00e5ff; margin-bottom: 12px; }
.device-item {
display: flex; justify-content: space-between; align-items: center;
padding: 10px 12px; margin-bottom: 6px;
background: rgba(0,100,200,0.15);
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
}
.device-item:hover { background: rgba(0,150,255,0.3); }
.device-item .name { color: #e0e0e0; font-size: 14px; }
.device-item .status { font-size: 12px; padding: 2px 8px; border-radius: 4px; }
.status-running { background: rgba(0,200,100,0.3); color: #4cff8d; }
.status-alarm { background: rgba(255,50,50,0.3); color: #ff6b6b; }
.status-stopped { background: rgba(150,150,150,0.3); color: #aaa; }
.chart-box {
background: rgba(0,20,50,0.85);
border: 1px solid rgba(0,150,255,0.3);
border-radius: 8px;
overflow: hidden;
}
.alarm-panel {
background: rgba(0,20,50,0.85);
border: 1px solid rgba(0,150,255,0.3);
border-radius: 8px;
padding: 16px;
}
.alarm-panel h3 { color: #ff6b6b; margin-bottom: 12px; }
.alarm-item {
padding: 8px 12px; margin-bottom: 4px;
background: rgba(255,50,50,0.12);
border-left: 3px solid #ff4444;
border-radius: 4px;
color: #ff9999; font-size: 13px;
}
.alarm-item .time { color: #888; font-size: 11px; }
</style>
</head>
<body>
<div class="dashboard">
<!-- 顶部标题栏 -->
<div class="header">
<h1>智慧工厂 · 实时监控大屏</h1>
</div>
<!-- 左侧设备列表 -->
<div class="device-panel">
<h3>设备列表</h3>
<div id="device-list"></div>
</div>
<!-- 中间实时温度趋势图 -->
<div class="chart-box" id="chart-temperature"></div>
<!-- 右上产能柱状图 -->
<div class="chart-box" id="chart-output"></div>
<!-- 右下告警面板 -->
<div class="alarm-panel">
<h3>实时告警</h3>
<div id="alarm-list"></div>
</div>
</div>
<script>
// ========== 模拟数据 ==========
const devices = [
{ id: 'd001', name: '1号注塑机', status: 'running', temp: 185, output: 42 },
{ id: 'd002', name: '2号注塑机', status: 'running', temp: 192, output: 38 },
{ id: 'd003', name: '3号冲压机', status: 'alarm', temp: 245, output: 15 },
{ id: 'd004', name: '4号冲压机', status: 'running', temp: 178, output: 40 },
{ id: 'd005', name: '5号机械臂', status: 'stopped', temp: 32, output: 0 },
{ id: 'd006', name: '6号机械臂', status: 'running', temp: 45, output: 28 },
];
const alarms = [
{ device: '3号冲压机', msg: '温度超过安全阈值 (245°C)', time: '14:32:15' },
{ device: '5号机械臂', msg: '设备离线超过 30 分钟', time: '14:28:01' },
];
// ========== 渲染设备列表 ==========
function renderDevices() {
const container = document.getElementById('device-list');
container.innerHTML = devices.map(d => `
<div class="device-item" onclick="onDeviceClick('${d.id}')">
<span class="name">${d.name}</span>
<span class="status status-${d.status}">${
d.status === 'running' ? '运行中' :
d.status === 'alarm' ? '告警' : '已停机'
}</span>
</div>
`).join('');
}
function onDeviceClick(deviceId) {
const device = devices.find(d => d.id === deviceId);
// 通知 UE:用户在网页中点击了设备
WebNative.send("Dashboard.Device.Click", {
deviceId: device.id,
deviceName: device.name,
status: device.status
});
}
// ========== 渲染告警列表 ==========
function renderAlarms() {
const container = document.getElementById('alarm-list');
container.innerHTML = alarms.map(a => `
<div class="alarm-item">
<div><strong>${a.device}</strong> — ${a.msg}</div>
<div class="time">${a.time}</div>
</div>
`).join('');
}
// ========== 温度趋势图 (ECharts) ==========
function renderTemperatureChart() {
const chart = echarts.init(document.getElementById('chart-temperature'));
const runningDevices = devices.filter(d => d.status === 'running');
chart.setOption({
backgroundColor: 'transparent',
title: { text: '设备温度趋势', left: 16, top: 12, textStyle: { color: '#00e5ff', fontSize: 14 } },
tooltip: { trigger: 'axis' },
legend: { bottom: 8, textStyle: { color: '#aaa' } },
grid: { top: 60, bottom: 40, left: 50, right: 20 },
xAxis: {
type: 'category',
data: ['14:00','14:05','14:10','14:15','14:20','14:25','14:30'],
axisLine: { lineStyle: { color: '#333' } },
axisLabel: { color: '#888' },
},
yAxis: {
type: 'value', name: '°C',
axisLine: { lineStyle: { color: '#333' } },
splitLine: { lineStyle: { color: 'rgba(255,255,255,0.06)' } },
axisLabel: { color: '#888' },
},
series: runningDevices.map(d => ({
name: d.name,
type: 'line',
smooth: true,
data: Array.from({length: 7}, () => d.temp + Math.floor(Math.random() * 20 - 10)),
showSymbol: false,
lineStyle: { width: 2 },
})),
});
window.addEventListener('resize', () => chart.resize());
}
// ========== 产能柱状图 (ECharts) ==========
function renderOutputChart() {
const chart = echarts.init(document.getElementById('chart-output'));
chart.setOption({
backgroundColor: 'transparent',
title: { text: '今日产能 (件)', left: 16, top: 12, textStyle: { color: '#00e5ff', fontSize: 14 } },
tooltip: { trigger: 'axis' },
grid: { top: 60, bottom: 30, left: 50, right: 20 },
xAxis: {
type: 'category',
data: devices.map(d => d.name),
axisLabel: { color: '#888', rotate: 20 },
axisLine: { lineStyle: { color: '#333' } },
},
yAxis: {
type: 'value',
axisLabel: { color: '#888' },
splitLine: { lineStyle: { color: 'rgba(255,255,255,0.06)' } },
},
series: [{
type: 'bar',
data: devices.map(d => ({
value: d.output,
itemStyle: {
color: d.status === 'alarm' ? '#ff4444' :
d.status === 'running' ? '#00b4d8' : '#555'
}
})),
barWidth: 24,
}],
});
window.addEventListener('resize', () => chart.resize());
}
// ========== 监听 UE 消息 ==========
WebNative.on("Scene.Device.Focus.Result", (messageBody) => {
const { deviceId } = JSON.parse(messageBody);
// UE 回复:镜头已聚焦到设备,前端可以做高亮
console.log('UE 已聚焦设备:', deviceId);
});
// ========== 初始化 ==========
renderDevices();
renderAlarms();
renderTemperatureChart();
renderOutputChart();
</script>
</body>
</html>
第 3 步:在 UE 中加载(3 分钟)
3.1 创建 Widget Blueprint
- Content Browser 右键 → User Interface → Widget Blueprint
- 命名为
WBP_DataDashboard - 打开,从 Palette 搜索 WebNative Browser,拖入 Canvas
3.2 设置加载路径
选中 WebNative Browser 控件,在 Details 面板设置:
| 属性 | 值 |
|---|---|
| Initial URL | E:/YourProject/Content/WebUI/dashboard.html |
⚠️ 路径改成你的实际项目路径。
3.3 绑定消息事件
- 选中 WebNative Browser 控件
- Details 面板底部找到 Events,点击 On Message Received 旁边的
+ - 蓝图会自动创建 Event Graph 节点
3.4 显示到视口
打开 Level Blueprint 或任意 Actor 蓝图,在 BeginPlay 添加:
Event BeginPlay
→ Create Widget (Class: WBP_DataDashboard)
→ Add to Viewport
第 4 步:跑起来并添加 UE 联动(2 分钟)
点击 Play,看到数据大屏显示在 UE 视口中。
现在加上双向联动——点击设备列表中的设备,UE 端收到消息:
在 WBP_DataDashboard 的 Event Graph 中:
Event On Message Received (FunctionName, MessageBody)
→ Branch (FunctionName == "Dashboard.Device.Click")
→ Print String (MessageBody) ← 先打印看看收到什么
Play 后点击网页中的设备条目,UE 的 Output Log 会打印:
{"deviceId":"d003","deviceName":"3号冲压机","status":"alarm"}
到此,Web 数据大屏 + UE 双向通信的完整链路就跑通了。
接下来可以做什么
这个 Demo 对应 3 个真实生产场景的入口:
| 方向 | 扩展方式 |
|---|---|
| 数据实时化 | 把模拟数据换成 WebSocket 实时推送的生产数据 |
| 三维联动 | UE 收到 Dashboard.Device.Click 后,镜头飞到对应设备并高亮 |
| 透明叠加 | 把面板背景改成透明,叠加在 UE 三维场景上,面板间隙可以看到场景 |
WebNativeBrowser 让这个过程简单在哪
| 如果没有 WebNativeBrowser | 用 WebNativeBrowser |
|---|---|
| 自己编译 CEF、处理多平台二进制 | 下载 zip,放进 Plugins,完成 |
| 自己处理 Web → UE 消息通道 | 三行 JS + 一个蓝图事件 |
| GPU 渲染手动配置、怕依赖没打进包 | 自动识别 GPU 后端,自动打包运行时文件 |
| 白屏了抓瞎,没有 DevTools | Ctrl+F12 一键打开 Chrome DevTools |
| Linux/ARM64 平台自己踩坑 | 已完成国产 CPU/GPU/系统适配 |
如果这篇帮你 10 分钟跑通了数据大屏,欢迎点赞收藏。WebNativeBrowser 支持 UE 5.1–5.8,覆盖 Windows / Linux x86_64 / Linux ARM64,已完成国产 GPU 专项适配。
GitHub:https://github.com/starTechnology1994/uewebbrowser
商务合作 / 授权咨询:startechnology1994@163.com

9399

被折叠的 条评论
为什么被折叠?



