本文将带你一步步了解如何使用 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 和后端数据接口,您可以轻松构建一个功能全面、动态更新的数据可视化大屏。本示例通过展示图表、动态填充表格数据和地图展示等功能,帮助用户实现实时数据的可视化展示。