自学内容网 自学内容网

数据可视化大屏设计与实现

本文将带你一步步了解如何使用 ECharts 实现一个数据可视化大屏,并且如何动态加载天气数据展示。通过整合 HTML、CSS、JavaScript 以及后端接口请求,我们可以构建一个响应式的数据可视化页面。

1. 页面结构介绍

在此例中,整个页面分为几个主要部分:大屏展示区域、多个数据图表、动态加载的表格数据,以及地图展示等功能模块。我们将详细介绍每一部分的实现和交互。

1.1 页面整体结构

以下是页面的结构,其中包含多个图表、数据表格和地图组件:

<body>
    <!-- 放大显示的容器 -->
    <div id="overlay1" class="echarts-overlay">
        <div id="echart-large1" class="echarts-large"></div>
    </div>
    <div id="overlay2" class="echarts-overlay">
        <div id="echart-large2" class="echarts-large"></div>
    </div>
    <div id="overlay3" class="echarts-overlay">
        <div id="echart-large3" class="echarts-large"></div>
    </div>
    <div id="overlay4" class="echarts-overlay">
        <div id="echart-large4" class="echarts-large"></div>
    </div>
    <div id="overlay5" class="echarts-overlay">
        <div id="echart-large5" class="echarts-large"></div>
    </div>
    <div id="overlay6" class="echarts-overlay">
        <div id="echart-large6" class="echarts-large"></div>
    </div>
    <div id="overlay7" class="echarts-overlay">
        <div id="echart-large7" class="echarts-large"></div>
    </div>
    <div id="main" class="main">
        <div id="title" class="title">大屏可视化展板-ECharts</div>
        <div id="content" class="content">
            <div id="left-chart" class="left-chart">
                <div id="chart1" class="chart chart1"></div>
                <div id="chart2" class="chart chart2"></div>
                <div id="chart3" class="chart chart3"></div>
            </div>
            <div id="mid-chart" class="mid-chart">
                <div class="count">
                    <div id="count1" class="container number"></div>
                    <div class="container number count2">328193</div>
                </div>
                <div id="chart7" class="chart7 map"></div>
            </div>
            <div id="right-chart" class="right-chart">
                <div id="chart4" class="chart chart4"></div>
                <div id="chart5" class="chart chart5"></div>
                <div id="chart6" class="chart chart6"></div>
            </div>
        </div>
    </div>
    <div class="model_content">
        <div class="model model1">
            <div class="title-content">
                <table>
                    <thead>
                        <tr>
                            <th class="th1">城市</th>
                            <th class="th2">天气</th>
                        </tr>
                    </thead>
                </table>
            </div>
            <div class="scroll-content">
                <table>
                    <tbody id="tableBody">
                        <!-- 通过 JavaScript 插入数据 -->
                    </tbody>
                </table>
            </div>
        </div>
        <div class="model model1">
            <div class="title-content">
                <table>
                    <thead>
                        <tr>
                            <th class="th1">城市</th>
                            <th class="th2">温度</th>
                        </tr>
                    </thead>
                </table>
            </div>
            <div class="scroll-content">
                <table>
                    <tbody id="tableBody2">
                        <!-- 通过 JavaScript 插入数据 -->
                    </tbody>
                </table>
            </div>
        </div>
    </div>
    <script>
        document.addEventListener("DOMContentLoaded", function () {
            axios.get('http://localhost:5000/api/weather_data')
                .then(response => {
                    console.log("1111", response.data);
                    const tableBody = document.getElementById('tableBody');

                    if (tableBody) {
                        let rowsHTML = '';
                        response.data.forEach((item) => {
                            rowsHTML += `<tr>
                                            <td>${item.city}</td>
                                            <td>${item.weather}</td>
                                          </tr>`;
                        });
                        tableBody.innerHTML = rowsHTML;
                    }
                })
                .catch(error => {
                    console.error("Error fetching weather data", error);
                });
        });
    </script>
    <script src="chart1.js"></script>
</body>

1.2 页面布局说明

页面采用了一个主页面和多个区域:

  • Overlay 区域:用于展示大图,通常是当用户点击某个图表时,将会弹出放大的图表展示区域。
  • Main 区域:包含了标题和三个区域(左侧图表区域、中间数字和地图展示区域、右侧图表区域)。这些区域通过 ECharts 图表进行数据的动态展示。
  • Model Content 区域:包含两个表格模块,分别展示了天气信息和温度信息。表格内容通过接口返回的数据动态填充。

2. 数据可视化实现

2.1 图表部分

通过使用 ECharts 图表库,我们可以在页面的不同位置展示各种类型的图表(如折线图、柱状图、饼图等)。

<div id="chart1" class="chart chart1"></div>
<div id="chart2" class="chart chart2"></div>
<div id="chart3" class="chart chart3"></div>

2.2 动态加载天气数据

页面中的天气表格通过 Axios 从后台接口 http://localhost:5000/api/weather_data 获取天气数据,并将数据动态填充到表格中。

document.addEventListener("DOMContentLoaded", function () {
    axios.get('http://localhost:5000/api/weather_data')
        .then(response => {
            const tableBody = document.getElementById('tableBody');
            if (tableBody) {
                let rowsHTML = '';
                response.data.forEach((item) => {
                    rowsHTML += `<tr>
                                    <td>${item.city}</td>
                                    <td>${item.weather}</td>
                                  </tr>`;
                });
                tableBody.innerHTML = rowsHTML;
            }
        })
        .catch(error => {
            console.error("Error fetching weather data", error);
        });
});

3. 样式和布局

通过适当的 CSS 样式来确保页面的响应式布局,确保页面在不同的设备和分辨率下展示良好。

#main {
    display: flex;
    justify-content: space-between;
    margin-top: 20px;
}
.left-chart, .mid-chart, .right-chart {
    width: 32%;
}
.chart {
    height: 200px;
    margin-bottom: 20px;
}

4. 整合 ECharts 和数据接口

我们还需要创建 ECharts 实例并绑定到对应的 DOM 元素中。例如:

var myChart1 = echarts.init(document.getElementById('chart1'));
var option1 = {
    title: { text: '示例图表1' },
    xAxis: { data: ['A', 'B', 'C', 'D'] },
    yAxis: {},
    series: [{ data: [120, 200, 150, 80], type: 'bar' }]
};
myChart1.setOption(option1);

同样的方法可以应用到其他图表中,根据不同的需求加载对应的图表类型。

5. 完整代码

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>大屏数据可视化</title>
    <script src="echarts.js"></script>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <!-- 引入世界地图数据 -->
    <script src="world.js"></script>
    <script src="echarts-gl.min.js"></script>
    <script src="axios.min.js"></script>
    <script src="china.js"></script> <!-- 引入 china.js 文件 -->
    <script src="hunan.json"></script> <!-- 引入 china.json 文件 -->
    <link rel="icon" href="favicon.png" type="image/png">
    <link rel="stylesheet" href="index.css">
    <style>
        /* 放大后的容器 */
        .echarts-overlay {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.7);
            display: none;
            justify-content: center;
            align-items: center;
            z-index: 9999;
        }

        /* 放大的 ECharts 图表 */
        .echarts-large {
            /* margin: 50% 50%; */
            width: 100vw;
            height: 95vh;
            z-index: 9999;
        }
    </style>
</head>

<body>
    <!-- 放大显示的容器 -->
    <div id="overlay1" class="echarts-overlay">
        <div id="echart-large1" class="echarts-large"></div>
    </div>
    <div id="overlay2" class="echarts-overlay">
        <div id="echart-large2" class="echarts-large"></div>
    </div>
    <div id="overlay3" class="echarts-overlay">
        <div id="echart-large3" class="echarts-large"></div>
    </div>
    <div id="overlay4" class="echarts-overlay">
        <div id="echart-large4" class="echarts-large"></div>
    </div>
    <div id="overlay5" class="echarts-overlay">
        <div id="echart-large5" class="echarts-large"></div>
    </div>
    <div id="overlay6" class="echarts-overlay">
        <div id="echart-large6" class="echarts-large"></div>
    </div>
    <div id="overlay7" class="echarts-overlay">
        <div id="echart-large7" class="echarts-large"></div>
    </div>
    <div id="main" class="main">
        <div id="title" class="title">大屏可视化展板-ECharts</div>
        <div id="content" class="content">
            <div id="left-chart" class="left-chart">
                <div id="chart1" class="chart chart1"></div>
                <div id="chart2" class="chart chart2"></div>
                <div id="chart3" class="chart chart3"></div>
            </div>
            <div id="mid-chart" class="mid-chart">
                <div class="count">
                    <div id="count1" class="container number"></div>
                    <div class="container number count2">328193</div>
                </div>
                <div id="chart7" class="chart7 map"></div>
            </div>
            <div id="right-chart" class="right-chart">
                <div id="chart4" class="chart chart4"></div>
                <div id="chart5" class="chart chart5"></div>
                <div id="chart6" class="chart chart6"></div>
            </div>
        </div>
    </div>
    <div class="model_content">
        <div class="model model1">
            <div class="title-content">
                <table>
                    <thead>
                        <tr>
                            <th class="th1">城市</th>
                            <th class="th2">天气</th>
                        </tr>
                    </thead>
                </table>
            </div>
            <div class="scroll-content">
                <table>
                    <tbody id="tableBody">
                        <!-- 通过 JavaScript 插入数据 -->
                    </tbody>
                </table>
            </div>
        </div>
        <div class="model model1">
            <div class="title-content">
                <table>
                    <thead>
                        <tr>
                            <th class="th1">城市</th>
                            <th class="th2">温度</th>
                        </tr>
                    </thead>
                </table>
            </div>
            <div class="scroll-content">
                <table>
                    <tbody id="tableBody2">
                        <!-- 通过 JavaScript 插入数据 -->
                    </tbody>
                </table>
            </div>
        </div>
    </div>
    <script>
        document.addEventListener("DOMContentLoaded", function () {
            // 代码在页面完全加载后执行
            axios.get('http://localhost:5000/api/weather_data')
                .then(response => {
                    console.log("1111", response.data);
                    const tableBody = document.getElementById('tableBody');

                    // 如果表格主体部分存在,开始插入数据
                    if (tableBody) {
                        let rowsHTML = '';
                        for (let i = 0; i < response.data.length; i++) {
                            rowsHTML += `<tr>
                                    <td>${response.data[i].name}</td>
                                    <td>天气 ${response.data[i].values.weather}</td>
                                    </tr>`;
                        }
                        tableBody.innerHTML = rowsHTML;
                    } else {
                        console.error('tableBody元素未找到');
                    }
                })
                .catch(error => console.error('Error:', error));
        });

        document.addEventListener("DOMContentLoaded", function () {
            // 代码在页面完全加载后执行
            axios.get('http://localhost:5000/api/weather_data')
                .then(response => {
                    console.log("1111", response.data);
                    const tableBody = document.getElementById('tableBody2');

                    // 如果表格主体部分存在,开始插入数据
                    if (tableBody) {
                        let rowsHTML = '';
                        for (let i = 0; i < response.data.length; i++) {
                            rowsHTML += `<tr>
                                    <td>${response.data[i].name}</td>
                                    <td>${response.data[i].value} ℃</td>
                                    </tr>`;
                        }
                        tableBody.innerHTML = rowsHTML;
                    } else {
                        console.error('tableBody元素未找到');
                    }
                })
                .catch(error => console.error('Error:', error));
        });
    </script>
    <script src="chart1.js"></script>
    <script src="chart2.js"></script>
    <script src="chart3.js"></script>
    <script src="chart4.js"></script>
    <script src="chart5.js"></script>
    <script src="chart6.js"></script>
    <script src="chart7.js"></script>
    <script src="count1.js"></script>

    <script>
        // 监听窗口大小变化,确保 ECharts 图表自适应
        window.addEventListener('resize', function () {
            var chart1 = echarts.getInstanceByDom(document.getElementById('chart1'));
            var chart2 = echarts.getInstanceByDom(document.getElementById('chart2'));
            var chart3 = echarts.getInstanceByDom(document.getElementById('chart3'));
            var chart4 = echarts.getInstanceByDom(document.getElementById('chart4'));
            var chart5 = echarts.getInstanceByDom(document.getElementById('chart5'));
            var chart6 = echarts.getInstanceByDom(document.getElementById('chart6'));
            var chart7 = echarts.getInstanceByDom(document.getElementById('chart7'));

            if (chart1) chart1.resize();
            if (chart2) chart2.resize();
            if (chart3) chart3.resize();
            if (chart4) chart4.resize();
            if (chart5) chart5.resize();
            if (chart6) chart6.resize();
            if (chart7) chart7.resize();
        });

        let debounceTimeout;

        window.addEventListener('resize', function () {
            // 清除之前的延时调用
            clearTimeout(debounceTimeout);

            // 设置新的延时调用,在窗口大小调整停止 300 毫秒后刷新页面
            debounceTimeout = setTimeout(function () {
                if (window.innerWidth < 1200) {
                    window.location.reload();
                }
            }, 100); // 300 毫秒的延迟
        });

    </script>
</body>

</html>

index.css

.main {
    width: 100%;
    height: 100%;
    display: grid;
    grid-template-rows: 5% 95%;
    background-image: url("background.png");
    background-repeat: no-repeat;
    background-size: cover;
}

.title {
    width: 100%;
    text-align: center;
    line-height: 56.14px;
    font-size: 30px;
    font-weight: 700;
    color: aliceblue;
    text-shadow: 0px 0px 9px #159AFF;
    position: relative;
    /* 为了定位下划线 */
    color: #00f7ff;
    /* 文字颜色为科技感的蓝色 */
}

/* 下框线效果 */
.title::after {
    content: '';
    /* 创建一个空的内容来作为下框线 */
    position: absolute;
    /* 定位到标题下方 */
    left: 0;
    /* 从左边开始 */
    bottom: -2px;
    /* 离文字稍微有点距离 */
    width: 100%;
    /* 让下框线宽度与标题一致 */
    height: 3px;
    /* 下框线的高度 */
    background: linear-gradient(90deg, rgba(0, 247, 255, 0.8), rgba(255, 0, 255, 0.8));
    /* 使用渐变效果 */
    box-shadow: 0 0 10px rgba(0, 247, 255, 0.6), 0 0 15px rgba(255, 0, 255, 0.6);
    /* 加入光晕效果 */
}

.content {
    width: 100%;
    height: 100vh;
    display: grid;
    grid-template-columns: 30% 40% 30%;
}

.left-chart {
    width: 100%;
    height: 100vh;
    display: grid;
    grid-template-rows: repeat(3, 1fr);
    /* 3行平分容器高度 */
}

.mid-chart {
    width: 100%;
    height: 100vh;
    display: grid;
    grid-template-rows: 1fr 5fr;
    /* 3行平分容器高度 */
}

.right-chart {
    width: 100%;
    height: 100vh;
    display: grid;
    grid-template-rows: repeat(3, 1fr);
    /* 3行平分容器高度 */
}

.chart {
    width: 100%;
    height: 100%;
    background-image: url("kk.png");
    background-repeat: no-repeat;
    background-size: 100% 103%;
    background-position: center;
}

.chart7 {
    width: 100%;
    height: 80%;
}

@font-face {
    font-family: "DS-Digital";
    src: url("./count.ttf");
}

.number {
    text-align: center;
    font-family: DS-Digital;
    font-size: 80px;
    color: aliceblue;
    line-height: 200px;
    text-shadow: 0px 0px 9px #159AFF;
}

.count {
    display: grid;
    grid-template-columns: 1fr 1fr;
    background-image: url("VCG211513642548.png");
    background-repeat: no-repeat;
    background-size: 120% 130%;
    background-position: center;
    margin-top: 10px;
}

/* 窗口尺寸变化时调整布局 */
@media (max-width: 1200px) {
    .main {}

    .content {
        grid-template-columns: 1fr 1fr 1fr;
        /* 中等屏幕时,调整为两列 */
    }

    .title {
        font-size: 2vw;
    }
}

@media (max-width: 768px) {
    .content {
        grid-template-columns: 1fr;
        /* 小屏幕时,调整为单列 */
    }

    .title {
        font-size: 2vw;
    }
}

/* 使 model_content 定位到页面的中间下方 */
.model_content {
    position: fixed;
    /* 使用固定定位 */
    left: 50%;
    /* 使其水平居中 */
    bottom: 20px;
    /* 距离页面底部 20px */
    transform: translateX(-50%);
    /* 完全居中对齐 */
    z-index: 999;
    /* 确保浮动层在其他内容之上 */
    display: flex;
    /* 使用 flexbox 来排列两个 .model 元素 */
    gap: 50px;
    /* 两个 .model 元素之间的间隙 */
}

/* 给 model 元素设置大小和背景蒙版 */
.model {
    width: 300px;
    /* 设置每个 model 的宽度 */
    height: 200px;
    /* 设置每个 model 的高度 */
    background-color: rgba(173, 216, 230, 0.4);
    /* 设置半透明黑色背景 */
    border-radius: 10px;
    /* 设置圆角 */
    position: relative;
    /* 使其可嵌套其他内容 */
    overflow: hidden;
    /* 隐藏超出盒子的内容 */
}

/* .model1 和 .model2 可以有不同的颜色或样式,按照需要自定义 */
.model1 {
    background-color: rgba(0, 0, 0, 0.6);
    /* 半透明深黑色 */
}

.model2 {
    background-color: rgba(0, 0, 0, 0.4);
    /* 半透明浅黑色 */
}

/* 滚动内容容器 */
.scroll-content {
    display: flex;
    flex-direction: column;
    /* 垂直排列数据 */
    overflow: hidden;
    /* 隐藏超出容器的内容 */
    animation: scroll 50s linear infinite;
}

/* 控制数据项的间距 */
.scroll-content p {
    margin: 10px 0;
}

/* 表格样式 */
table {
    width: 100%;
    border-collapse: collapse;
    /* 合并边框 */
    /* 半透明背景 */
    border-radius: 8px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.title-content {
    position: relative;
    z-index: 999;
}

/* 表头样式 */
th {
    background-color: rgb(4, 45, 97);
    /* 半透明蓝色背景 */
    color: rgb(167, 165, 165);
    /* 白色文字 */
    padding: 10px;
    font-weight: bold;                                                                                                                                     
    border-bottom: 1px solid rgba(255, 255, 255, 0.3);
    text-align: center;
}

/* 表格单元格样式 */
td {
    padding: 8px;
    text-align: left;
    border-bottom: 1px solid #ddd;
    font-size: 14px;
    text-align: center;
    color: rgb(223, 218, 218);
}

/* 鼠标悬浮时改变表格行背景 */
tr:hover {
    background-color: rgba(0, 123, 255, 0.1);
}

/* 设置滚动动画 */
@keyframes scroll {
    0% {
        transform: translateY(0);
    }

    100% {
        transform: translateY(-100%);
        /* 向上滚动一个完整的容器高度 */
    }
}

api.py

from flask import Flask, jsonify
from flask_cors import CORS  # 导入CORS
import sqlite3



# 创建Flask应用实例
app = Flask(__name__)

# 启用CORS
# CORS(app)  # 这将允许所有源的请求
CORS(app, origins='http://127.0.0.1:5500')

# 定义路由和视图函数
@app.route('/')
def hello_world():
    return 'Hello, World!'

@app.route('/api/bar_data')
def get_data():
    """
    从SQLite数据库中读取数据,并将其转换为JSON格式返回。

    :return: 一个JSON格式的响应,包含从数据库中读取的数据。
    """
    conn = sqlite3.connect('database.db')
    cursor = conn.cursor()

    # 查询数据
    cursor.execute('SELECT category, sales FROM bar_data')
    rows = cursor.fetchall()

    # 将数据转换为字典列表
    data = {'categories': [row[0] for row in rows], 'sales': [row[1] for row in rows]}

    # 关闭连接
    conn.close()

    return jsonify(data)

@app.route('/api/weather_data')
def get_weather_data():
    """
    从SQLite数据库中读取数据,并将其转换为JSON格式返回。

    :return: 一个JSON格式的响应,包含从数据库中读取的数据。
    """
    conn = sqlite3.connect('database.db')
    cursor = conn.cursor()

    # 查询数据
    cursor.execute('SELECT date, city,weather, max_tem, min_tem, tem, update_time FROM weather')
    rows = cursor.fetchall()

    # 将数据转换为字典列表


    data = [
        {
            'name': row[1], 
            'value': row[5], 
            'values': {
                'weather':row[2],
                'max_tem':row[3],
                'min_tem':row[4],
                }
            } for row in rows
    ]
    # 关闭连接
    conn.close()

    return jsonify(data)



@app.route('/api/line_bar_data')
def get_line_bar_data():
    """
    从SQLite数据库中读取数据,并将其转换为JSON格式返回。

    :return: 一个JSON格式的响应,包含从数据库中读取的数据。
    """
    conn = sqlite3.connect('database.db')
    cursor = conn.cursor()

    # 查询数据
    cursor.execute('SELECT category, value FROM line_bar_data')
    rows = cursor.fetchall()
    # 将数据转换为字典列表
    data = {'categories': [row[0] for row in rows],'values': [row[1] for row in rows]}
    print(data)
    # 关闭连接
    conn.close()
    return jsonify(data)

# 启动应用
if __name__ == '__main__':
    app.run(debug=True)

6. 小结

通过结合 ECharts、Axios 和后端数据接口,您可以轻松构建一个功能全面、动态更新的数据可视化大屏。本示例通过展示图表、动态填充表格数据和地图展示等功能,帮助用户实现实时数据的可视化展示。


原文地址:https://blog.csdn.net/qq_43580271/article/details/145228382

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!