跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端

基于 ECharts 与 Three.js 的碳排放可视化大屏实现

本项目展示了一个基于 Web 技术的碳排放可视化大屏解决方案。核心采用 ECharts 进行多维度数据图表渲染,结合 Three.js 实现 3D 地球效果。页面布局使用 Flexbox 配合 rem 单位适配不同分辨率,涵盖教室、实验室及宿舍的用电用水统计。代码结构清晰,包含主界面模板、样式定义及交互逻辑,适合用于智慧校园或能源管理系统的参考实现。

Qiny01发布于 2026/3/28更新于 2026/7/2227 浏览
基于 ECharts 与 Three.js 的碳排放可视化大屏实现

一、效果预览

效果演示

二、技术架构

本项目采用原生 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();
}

四、关键细节

  1. 响应式适配:通过 flexible.js 动态计算 rem 基准,确保在不同分辨率下布局比例一致。
  2. 图表联动:Tab 切换时移除所有按钮的 active 类,仅高亮当前选中项,并触发对应数据更新。
  3. 性能优化:Canvas 渲染减少 DOM 操作,动画循环使用 requestAnimationFrame 保证流畅度。

以上即为整个大屏的核心实现思路,实际开发中可根据业务需求调整数据源与配色方案。

目录

  1. 一、效果预览
  2. 二、技术架构
  3. 三、核心代码解析
  4. 1. 页面结构 (view.html)
  5. 2. 样式设计 (view.css)
  6. 3. 交互逻辑 (view.js)
  7. 四、关键细节
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 如何编写高质量的 AI Skill:基于 skill-creator 最佳实践
  • Python 从入门到精通:100 课系统学习路径
  • Coze 平台 AI 智能体零基础使用教程
  • OAuth2.0 应用中 client-id 和 client-secret 的获取与配置实战
  • Android 转场动画演进历程与实战解析
  • Figma + Claude + Weavy AI 协同设计工作流实践
  • OpenClaw 3.8 发布:ACP 溯源、备份工具与安全增强
  • 模拟算法实战:核心概念与经典案例解析
  • ROS2 功能包创建与 CMake 编译链路详解
  • 旋转位置编码 RoPE:从 2D 到 nD 的扩展与原理
  • 平台、记忆、评测——AI 竞赛正在换挡
  • Python 调用 ChatGPT、通义千问与讯飞星火文本总结实测对比
  • 模拟算法实战:替换问号、提莫攻击、Z 字形变换等五题详解
  • Wave Terminal 跨平台终端工具安装与使用指南
  • Qwen2.5-72B-GPTQ-Int4 实战:vLLM 推理与 Chainlit 可视化集成
  • 微信视频号视频加密逆向:WebAssembly 解密记录
  • 基于 Dify 与 LangBot 搭建飞书智能体对话机器人
  • Java AES 加密算法实现与模式详解
  • VS Code 扩展推荐指南:提升开发效率的必备插件
  • Java 21 虚拟线程日志优化与百万级并发追踪最佳实践

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online