数据可视化大屏设计与实现
本文将带你一步步了解如何使用 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)!