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

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

展示了一个基于 ECharts 和 Three.js 构建的碳排放可视化大屏项目。核心功能包括多模块图表切换(教室、实验室、宿舍)、3D 地球动画展示以及响应式布局设计。代码涵盖了 HTML 结构、CSS 样式适配及 JavaScript 交互逻辑,适合前端开发者参考学习大屏开发流程。

落日余晖发布于 2026/4/8更新于 2026/8/1538 浏览
基于 ECharts 与 Three.js 的碳排放可视化大屏实现

前端可视化大屏实战:碳排放数据展示

效果预览

项目最终呈现为一个响应式的大屏界面,包含左侧、中间和右侧三个主要区域。中间核心位置展示 3D 地球模型及关键指标,两侧分布各类统计图表。整体采用深色科技风背景,支持动态切换不同场景(如教室、实验室、宿舍)的数据视图。

效果演示

技术架构概览

本项目主要依赖以下技术栈:

  • HTML/CSS: 负责页面骨架与样式布局,使用 Flexbox 实现三栏结构。
  • JavaScript (ES6+): 核心交互逻辑,处理图表渲染与事件监听。
  • ECharts: 用于绘制柱状图、折线图、饼图等常规统计图表。
  • Three.js: 用于构建中间的 3D 地球动画效果。
  • Jinja2: 模板引擎(从 url_for 推断),用于资源路径管理。

核心代码解析

1. 页面结构与资源引入 (view.html)

页面主体分为 Header、Section 和 Footer 三部分。Header 显示标题与实时时间,Section 内部通过 .column 类划分左中右三列。值得注意的是,我们使用了 flexible.js 来适配不同分辨率的设备,确保在大屏上比例协调。

<!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);
                var 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>
        <!-- 中间盒子 -->
        <div class="column">
            <!-- num 模块 -->
            <div class="num">
                <div class="globe-container">
                    <canvas id="globe-canvas"></canvas>
                </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 单位配合 flexible.js 进行自适应。背景图设置为固定定位,避免滚动时闪烁。图表容器使用了半透明边框和四角装饰,增强科技感。特别需要注意的是媒体查询部分,针对不同屏幕宽度调整了字体大小,保证移动端也能查看。

* { 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;
    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);
}
.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; }
/* ... 更多样式省略 ... */
@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 文件是核心所在,我们将不同图表封装在 IIFE 中以避免污染全局变量。每个图表模块都配置了独立的数据源,并通过 Tab 按钮触发 updateChart 函数来切换数据。

以柱状图为例,我们定义了 chartData 对象存储不同场景(教室、实验室、宿舍)的用电量数据。当用户点击 Tab 时,移除旧激活状态,更新当前类型并重新渲染 ECharts 实例。同时监听了 window.resize 事件,确保窗口缩放时图表自动适应。

// 柱状图模块
(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: { title: '实验室每日用电量统计', data: { categories: ['周一','周二','周三','周四','周五','周六','周日'], series: [{ name:'早', data:[13.85,17.78,20.12,16.77,14.69,3.46,5.72] }, { name:'晚', data:[9.05,11.72,14.37,11.42,11.62,3.17,5.63]} ] }, colors:['#EE6666','#FAC858'] },
        dormitory: { title: '宿舍每日用电量统计', data: { categories: ['周一','周二','周三','周四','周五','周六','周日'], series: [{ name:'早', data:[4.23,3.98,4.56,4.01,4.34,2.78,2.45] }, { name:'晚', data:[5.31,5.45,5.12,5.78,6.89,7.01,5.67]} ] }, colors:['#73C0DE','#3BA272'] }
    };

    document.addEventListener('DOMContentLoaded', function(){
        var barChartDom = document.querySelector('.bar .char');
        var titleElement = document.querySelector('.bar .chart-title h2');
        var tabButtons = document.querySelectorAll('.bar .tab-btn');
        if(barChartDom && titleElement && tabButtons.length >0){
            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'}, top:-3 },
                    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);
            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(); });
        }
    });
})();

4. 3D 地球动画 (initGlobe)

中间区域的地球使用了 Three.js 构建。我们通过加载纹理贴图(法线贴图、高光贴图)来增加真实感。光照系统包含环境光和方向光,模拟自然光照效果。动画循环中不断旋转地球 Mesh,营造动态视觉体验。

// 初始化 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();

    function resizeGlobe(){
        const container = document.querySelector('.globe-container');
        const width = container.clientWidth;
        const height = container.clientHeight;
        camera.aspect = width / height;
        camera.updateProjectionMatrix();
        renderer.setSize(width, height);
    }
    window.addEventListener('resize', resizeGlobe);
    resizeGlobe();
}

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();
}

5. 辅助工具

项目中还包含了 jiazai.js 用于处理资源加载缓存问题,以及 flexible.js 用于计算 Rem 基准值,确保在不同设备上的布局一致性。这些工具函数虽然不起眼,但对大屏项目的稳定性至关重要。

目录

  1. 前端可视化大屏实战:碳排放数据展示
  2. 效果预览
  3. 技术架构概览
  4. 核心代码解析
  5. 1. 页面结构与资源引入 (view.html)
  6. 2. 样式适配与布局 (view.css)
  7. 3. 图表交互逻辑 (view.js)
  8. 4. 3D 地球动画 (initGlobe)
  9. 5. 辅助工具
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • WorkBuddy 桌面智能体安装与实战指南
  • 免费使用 AI 绘画模型 Nano Banana Pro 指南
  • HTTP 请求中 GET 与 POST 的区别及应用场景
  • VS Code 中配置 GitHub Copilot 自定义 Skill 的方法
  • VS Code + GitHub Copilot 实战指南:从配置到高效协作
  • 自然语言处理在客户服务领域的应用与实战
  • Android WebView 内核升级方案与 H.265 兼容性实践
  • Ubuntu 22.04 部署 Openclaw AI 助手实战指南
  • Linux 序列化与反序列化原理及自定义协议实现
  • 无人机低空智能巡飞巡检平台:全域感知与智能决策
  • 使用扣子(Coze)搭建 AI 智能体完整指南
  • C++ 快速输入输出优化:快读与快写实现
  • 飞书机器人图片消息发送流程及常见问题解决
  • Meta 与卡内基梅隆大学提出 GaLore:全参数微调内存减少 63.3%
  • 前端与 Spring Boot 后端无感 Token 刷新实践
  • 2026 年主流 AI 编程工具横评:Cursor、Claude Code、Windsurf 与 Copilot 对比
  • 动态规划 01 背包问题详解与空间优化
  • 新机型 Copilot 键替代右 Ctrl 键的解决方案
  • Ubuntu 20.04 安装微信教程
  • NVIDIA Jetson Thor T5000 解析:产品谱系、架构性能与落地路径

相关免费在线工具

  • 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