一、效果预览
二、技术架构
本项目采用原生 HTML/CSS/JavaScript 构建,核心依赖 ECharts 处理二维数据图表,结合 Three.js 渲染三维地球效果。页面布局使用 Flexbox 配合 rem 单位适配不同分辨率,涵盖教室、实验室及宿舍的用电用水统计。
三、核心代码解析
1. 页面结构 (view.html)
主界面通过语义化标签划分头部、主体和侧边栏。头部展示标题与实时时间,主体分为左中右三列,分别承载柱状图、3D 地球数据和饼图。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/view.css') }}">
</head>
<body>
<!-- 头部盒子 -->
<header>
<div class="container">
<h1>碳排放可视化大屏</h1>
</div>
<div class="showTime"></div>
<script>
var t = null;
t = setTimeout(time, 1000);
function time() {
clearTimeout(t);
a = new Date();
var y = a.getFullYear();
var mt = a.getMonth() + 1;
var day = a.getDate();
var h = a.getHours();
var m = a.getMinutes();
var s = a.getSeconds();
document.querySelector(".showTime").innerHTML = '当前时间:' + y + "年" + mt + "月" + day + "-" + h + "时" + m + "分" + s + "秒";
t = setTimeout(time, 1000);
}
</script>
</header>
<!-- 页面主体部分 -->
<section class="box">
<!-- 左侧盒子 -->
<div class="column">
<!-- 左侧柱状图模块 -->
<div class="public bar right-chart-module">
<div class="chart-title">
<h2></h2>
<div class="chart-tabs">
<button class="tab-btn active" data-type="classroom">教室</button>
<button class="tab-btn" data-type="lab">实验室</button>
<button class="tab-btn" data-type="dormitory">宿舍</button>
</div>
</div>
<div class="char" id="leftBarChart"></div>
<div class="public-one"></div>
</div>
<div class="public bar">
<h2>无纸化考试次数</h2>
<div class="chart-tabs">
<div class="char" id="horizontalBarChart"></div>
</div>
<div class="public-one"></div>
</div>
</div>
<!-- 中间盒子 -->
<div class="column">
<!-- num 模块 -->
<div class="num">
<div class="globe-container">
<canvas id="globe-canvas"></canvas>
</div>
<div class="globe-data">
<div class="data-row">
<div class="data-item">
<div class="data-value" id="global-temp">12</div>
<div class="data-label">没想好</div>
</div>
<div class="data-item">
<div class="data-value" id="co2-level">419</div>
<div class="data-label">没想好</div>
</div>
</div>
<div class="data-row">
<div class="data-item">
<div class="data-value" id="china-emission">10.5</div>
<div class="data-label">没想好</div>
</div>
<div class="data-item">
<div class="data-value" id="world-emission">4.7</div>
<div class="data-label">没想好</div>
</div>
</div>
</div>
</div>
</div>
<!-- 右侧盒子 -->
<div class="column">
<!-- 右侧柱状图模块 -->
<div class="public bar right-chart-module">
<div class="chart-title">
<h2></h2>
<div class="chart-tabs">
<button class="tab-btn active" data-type="classroom">教室</button>
<button class="tab-btn" data-type="lab">实验室</button>
<button class="tab-btn" data-type="dormitory">宿舍</button>
</div>
</div>
<div class="char" id="vehicleChart"></div>
<div class="public-one"></div>
</div>
<!-- 饼图模块 -->
<div class="public pie">
<div class="chart-title">
<h2></h2>
<div class="chart-tabs">
<button class="tab-btn active" data-time="morning">早</button>
<button class="tab-btn" data-time="evening">晚</button>
</div>
</div>
<div class="char" id="pieChart"></div>
<div class="public-one"></div>
</div>
</div>
</section>
<script src="{{ url_for('static', filename='js/echarts.js') }}"></script>
<script src="{{ url_for('static', filename='js/echarts.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/view.js') }}"></script>
<script src="{{ url_for('static', filename='js/flexible.js') }}"></script>
<script src="{{ url_for('static', filename='js/jiazai.js') }}"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => window.dispatchEvent(new Event('resize')), 300);
});
</script>
</body>
</html>
2. 样式设计 (view.css)
样式部分重点在于深色主题背景、发光边框以及响应式字体大小。使用了 rem 单位配合媒体查询来保证在不同屏幕下的显示效果。
* { margin: 0; padding: 0; box-sizing: border-box; }
li { list-style: none; }
@font-face { font-family: electronicFont; src: url(/static/font/ziti.TTF); }
html { font-size: 100px; overflow: hidden; width: 100%; height: 100%; }
body { font-family: Arial, Helvetica, sans-serif; margin: 0; padding: 0; background: url(/static/images/bei.jpg) no-repeat; background-size: cover; background-attachment: fixed; line-height: 1.15; width: 100%; height: 100%; overflow: hidden; }
header { position: relative; height: 1.11rem; background: url(/static/images/head.png) no-repeat top center; background-size: 100% 100%; width: 100%; }
header .container h1 { font-size: 0.51rem; color: #fff; text-align: center; line-height: 1.07rem; -webkit-text-stroke: 2px #00f7ff; text-shadow: 0 0 10px rgba(0, 247, 255, 0.5); }
header .showTime { position: absolute; right: 0.4rem; top: 0; line-height: 1rem; color: #2680ce; font-size: 0.27rem; font-family: 'electronicFont'; white-space: nowrap; }
.box { display: flex; min-width: 1024px; max-width: 1920px; width: 100%; height: calc(100% - 1.11rem); margin: 0 auto; padding: 0.13rem; overflow: hidden; }
.box .column { flex: 3; height: 100%; display: flex; flex-direction: column; }
.box .column:nth-child(2) { flex: 5; margin: 0 0.13rem; }
.box .public { position: relative; height: 5.6rem; border: 1px solid rgba(25, 186, 139, 0.17); background: url(/static/images/bian.png) rgba(255, 255, 255, 0.04); padding: 0 0.2rem 0.53rem; margin-bottom: 0.2rem; width: 100%; }
/* ... 更多样式省略,实际项目中建议拆分文件 */
@media screen and (max-width: 1024px) { html { font-size: 42px !important; } }
@media screen and (min-width: 1920px) { html { font-size: 80px !important; } }
3. 交互逻辑 (view.js)
JS 部分负责图表初始化、数据更新及 3D 场景渲染。ECharts 配置项较为复杂,建议将通用配置提取为函数。Three.js 部分用于加载地球模型并添加光照效果。
// 柱状图模块
(function() {
const chartData = {
classroom: {
title: '教室每日用电量统计',
data: {
categories: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
series: [
{ name: '早', data: [6.28, 9.55, 8.69, 8.63, 6.64, 4.17, 2.69] },
{ name: '晚', data: [5.71, 8.65, 5.32, 5.91, 5.77, 3.17, 1.85] }
]
},
colors: ['#5470C6', '#91CC75']
},
// lab 和 dormitory 数据略...
};
document.addEventListener('DOMContentLoaded', function() {
var barChartDom = document.querySelector('.bar .char');
if (barChartDom) {
var barChart = echarts.init(barChartDom);
var currentType = 'classroom';
function updateChart(type) {
const data = chartData[type].data;
const colors = chartData[type].colors;
const barOption = {
color: colors,
title: { text: chartData[type].title, left: 'center', textStyle: { fontSize: 16, color: '#fff' } },
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: { data: ['早', '晚'], textStyle: { color: '#fff' }, top: 20 },
grid: { top: '20%', left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: { type: 'category', data: data.categories, axisLine: { lineStyle: { color: '#fff' } }, axisLabel: { color: '#fff', interval: 0 } },
yAxis: { type: 'value', name: '用电量 (千瓦)', nameTextStyle: { color: '#fff', padding: [0, 0, 0, 30] }, axisLine: { show: true, lineStyle: { color: '#fff' } }, axisLabel: { color: '#fff' }, splitLine: { lineStyle: { color: 'rgba(255, 255, 255, 0.2)' } } },
series: [
{ name: '早', type: 'bar', barWidth: '30%', barGap: '50%', data: data.series[0].data },
{ name: '晚', type: 'bar', barWidth: '30%', data: data.series[1].data }
]
};
barChart.setOption(barOption);
}
updateChart(currentType);
var tabButtons = document.querySelectorAll('.bar .tab-btn');
tabButtons.forEach(button => {
button.addEventListener('click', function() {
tabButtons.forEach(btn => btn.classList.remove('active'));
this.classList.add('active');
currentType = this.dataset.type;
updateChart(currentType);
});
});
window.addEventListener('resize', function() { barChart.resize(); });
}
});
})();
// 3D 地球初始化
function initGlobe() {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('globe-canvas'), antialias: true, alpha: true });
renderer.setSize(400, 300);
renderer.setClearColor(0x000000, 0);
const geometry = new THREE.SphereGeometry(5, 64, 64);
const material = new THREE.MeshPhongMaterial({ color: 0x156289, emissive: 0x072534, shininess: 5, transparent: true, opacity: 0.8, wireframe: false });
const textureLoader = new THREE.TextureLoader();
material.map = textureLoader.load('/static/images/img.png');
material.bumpMap = textureLoader.load('https://threejs.org/examples/textures/planets/earth_normal_2048.jpg');
material.specularMap = textureLoader.load('https://threejs.org/examples/textures/planets/earth_specular_2048.jpg');
const earth = new THREE.Mesh(geometry, material);
scene.add(earth);
const ambientLight = new THREE.AmbientLight(0x333333);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 3, 5);
scene.add(directionalLight);
camera.position.z = 12;
function animate() {
requestAnimationFrame(animate);
earth.rotation.y += 0.002;
renderer.render(scene, camera);
}
animate();
}
if (typeof THREE === 'undefined') {
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js';
script.onload = initGlobe;
document.head.appendChild(script);
} else {
initGlobe();
}
四、关键细节
- 响应式适配:通过
flexible.js动态计算rem基准,确保在不同分辨率下布局比例一致。 - 图表联动:Tab 切换时移除所有按钮的
active类,仅高亮当前选中项,并触发对应数据更新。 - 性能优化:Canvas 渲染减少 DOM 操作,动画循环使用
requestAnimationFrame保证流畅度。
以上即为整个大屏的核心实现思路,实际开发中可根据业务需求调整数据源与配色方案。


