使用 Flask、echarts 和 jQuery 构建数据大屏的完整指南
在当今数据驱动的世界中,构建一个直观且交互性强的大屏展示系统对于企业决策至关重要。本文将详细介绍如何使用 Flask 作为后端框架,echarts 作为前端可视化库,以及 jQuery 进行动态交互,开发一个功能强大的数据大屏。我们将通过一个实际案例,图文并茂地展示整个开发过程。
目录
- 项目概述
- 环境搭建
- 后端开发:Flask
- 前端开发:HTML、CSS、JavaScript
- 引入必要的库
- 布局设计
- 使用 echarts 创建图表
- 使用 jQuery 实现动态数据加载
- 整合前后端
- 运行与测试
- 完整代码示例
- 总结
项目概述
本项目旨在构建一个数据大屏,展示实时或定期更新的数据图表。我们将使用 Flask 作为后端服务器,提供数据接口;前端使用 HTML、CSS 进行布局设计,echarts 进行数据可视化,jQuery 进行动态数据请求和页面交互。
主要功能
- 数据展示:通过多种图表(如柱状图、折线图、饼图等)展示数据。
- 实时更新:定时从后端获取最新数据,动态更新图表。
- 交互性:用户可以通过交互元素(如下拉菜单、按钮)切换不同的数据视图。
环境搭建
1. 安装 Python 和 Flask
确保已安装 Python(建议 3.6 及以上版本)。然后使用 pip 安装 Flask:
pip install Flask
2. 创建项目目录
创建一个新的项目文件夹,例如 data_dashboard
,并在其中创建以下文件:
data_dashboard/
│
├── app.py
├── templates/
│ └── index.html
├── static/
│ ├── css/
│ │ └── styles.css
│ ├── js/
│ │ └── scripts.js
│ └── images/
│ └── (可选的图像文件)
└── data/
└── (数据文件,如 JSON、CSV 等)
后端开发:Flask
1. 创建 Flask 应用
在 app.py
中编写以下代码:
from flask import Flask, render_template, jsonify
import json
import random
import time
from datetime import datetime
app = Flask(__name__)
# 示例数据生成函数
def generate_sample_data():
timestamp = int(time.time())
return {
'timestamp': timestamp,
'value': random.randint(10, 100)
}
# 数据接口
@app.route('/api/data')
def get_data():
data = generate_sample_data()
return jsonify(data)
# 首页路由
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
2. 解释
- 路由
/api/data
:提供一个简单的 API 接口,返回一个包含时间戳和随机值的 JSON 对象。这模拟了从数据库或外部数据源获取数据的过程。 - 路由
/
:渲染前端页面index.html
。
前端开发:HTML、CSS、JavaScript
1. 引入必要的库
在 templates/index.html
中引入 Bootstrap(用于快速布局)、jQuery、echarts 以及自定义的 CSS 和 JavaScript 文件:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>数据大屏</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
<!-- 引入 echarts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
</head>
<body>
<div class="container-fluid">
<h1 class="text-center my-4">数据大屏展示</h1>
<div class="row">
<!-- 柱状图 -->
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header">月度销售数据</div>
<div class="card-body">
<div id="barChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
</div>
<!-- 折线图 -->
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header">网站访问趋势</div>
<div class="card-body">
<div id="lineChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
</div>
<!-- 饼图 -->
<div class="col-md-4">
<div class="card mb-4">
<div class="card-header">用户分布</div>
<div class="card-body">
<div id="pieChart" style="width: 100%; height: 300px;"></div>
</div>
</div>
</div>
<!-- 实时数据展示 -->
<div class="col-md-8">
<div class="card mb-4">
<div class="card-header">实时数据</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<tr>
<th>时间</th>
<th>值</th>
</tr>
</thead>
<tbody id="dataTableBody">
<!-- 动态填充数据 -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- 引入 jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- 引入自定义脚本 -->
<script src="{{ url_for('static', filename='js/scripts.js') }}"></script>
</body>
</html>
2. 布局设计
上述 HTML 使用 Bootstrap 的网格系统将页面分为多个部分:
- 柱状图:展示月度销售数据。
- 折线图:展示网站访问趋势。
- 饼图:展示用户分布。
- 实时数据展示:以表格形式展示最新的数据记录。
3. 使用 echarts 创建图表
在 static/js/scripts.js
中编写以下代码:
$(document).ready(function() {
// 初始化柱状图
var barChart = echarts.init(document.getElementById('barChart'));
var barOption = {
title: {
text: '月度销售数据'
},
tooltip: {},
xAxis: {
type: 'category',
data: ['一月','二月','三月','四月','五月','六月']
},
yAxis: {
type: 'value'
},
series: [{
name: '销售额',
type: 'bar',
data: [120, 200, 150, 80, 70, 110],
itemStyle: {
color: '#5470C6'
}
}]
};
barChart.setOption(barOption);
// 初始化折线图
var lineChart = echarts.init(document.getElementById('lineChart'));
var lineOption = {
title: {
text: '网站访问趋势'
},
tooltip: {},
xAxis: {
type: 'category',
data: ['周一','周二','周三','周四','周五','周六','周日']
},
yAxis: {
type: 'value'
},
series: [{
name: '访问量',
type: 'line',
data: [150, 230, 224, 218, 135, 147, 260],
itemStyle: {
color: '#91CC75'
}
}]
};
lineChart.setOption(lineOption);
// 初始化饼图
var pieChart = echarts.init(document.getElementById('pieChart'));
var pieOption = {
title: {
text: '用户分布'
},
tooltip: {
trigger: 'item'
},
legend: {
top: '5%',
left: 'center'
},
series: [{
name: '访问来源',
type: 'pie',
radius: '50%',
data: [
{value: 1048, name: '搜索引擎'},
{value: 735, name: '直接访问'},
{value: 580, name: '邮件营销'},
{value: 484, name: '联盟广告'},
{value: 300, name: '视频广告'}
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
formatter: '{b}: {c} ({d}%)'
}
}]
};
pieChart.setOption(pieOption);
// 实时数据更新
function fetchData() {
$.ajax({
url: '/api/data',
method: 'GET',
success: function(response) {
var data = response;
// 更新表格
var tableRow = '<tr><td>' + datetimeConverter(data.timestamp) + '</td><td>' + data.value + '</td></tr>';
$('#dataTableBody').prepend(tableRow);
// 保持表格最多显示10条记录
if ($('#dataTableBody tr').length > 10) {
$('#dataTableBody tr').last().remove();
}
// 更新柱状图
barOption.xAxis.data.push(datetimeConverter(data.timestamp).split(' ')[1]);
barOption.series[0].data.push(data.value);
barChart.setOption(barOption);
// 更新折线图
lineOption.xAxis.data.push(datetimeConverter(data.timestamp).split(' ')[1]);
lineOption.series[0].data.push(data.value);
lineChart.setOption(lineOption);
// 更新饼图(示例中不涉及动态更新)
},
error: function(error) {
console.error('数据获取失败:', error);
}
});
}
// 转换时间戳为可读的日期时间格式
function datetimeConverter(timestamp) {
var date = new Date(timestamp * 1000);
var year = date.getFullYear();
var month = ('0' + (date.getMonth() + 1)).slice(-2);
var day = ('0' + date.getDate()).slice(-2);
var hours = ('0' + date.getHours()).slice(-2);
var minutes = ('0' + date.getMinutes()).slice(-2);
var seconds = ('0' + date.getSeconds()).slice(-2);
return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;
}
// 每隔5秒获取一次数据
setInterval(fetchData, 5000);
// 初始获取数据
fetchData();
});
4. 解释
- 初始化图表:使用 echarts 初始化三个图表(柱状图、折线图、饼图),并设置初始数据。
- 实时数据更新:
- 使用
setInterval
每隔 5 秒调用fetchData
函数,从后端获取最新数据。 - 更新表格中的数据记录。
- 将新数据添加到柱状图和折线图的系列数据中,并刷新图表。
- 表格最多显示 10 条记录,超过则删除最早的记录。
- 使用
整合前后端
1. 静态文件引用
在 templates/index.html
中通过 {{ url_for('static', filename='路径') }}
引用静态文件(如 CSS 和 JS)。
2. 启动静态文件夹
确保 Flask 应用能够访问静态文件夹。在 app.py
中已经通过 render_template
函数指定了模板路径。
运行与测试
1. 启动 Flask 应用
在项目根目录下运行:
python app.py
2. 访问应用
打开浏览器,访问 http://127.0.0.1:5000/
,即可看到数据大屏展示。
3. 效果展示
以下是数据大屏的预期效果:
完整代码示例
1. app.py
from flask import Flask, render_template, jsonify
import json
import random
import time
from datetime import datetime
app = Flask(__name__)
# 示例数据生成函数
def generate_sample_data():
timestamp = int(time.time())
return {
'timestamp': timestamp,
'value': random.randint(10, 100)
}
# 数据接口
@app.route('/api/data')
def get_data():
data = generate_sample_data()
return jsonify(data)
# 首页路由
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
2. templates/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>数据大屏</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
<!-- 引入 echarts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
</head>
<body>
<div class="container-fluid">
<h1 class="text-center my-4">数据大屏展示</h1>
<div class="row">
<!-- 柱状图 -->
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header">月度销售数据</div>
<div class="card-body">
<div id="barChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
</div>
<!-- 折线图 -->
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header">网站访问趋势</div>
<div class="card-body">
<div id="lineChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
</div>
<!-- 饼图 -->
<div class="col-md-4">
<div class="card mb-4">
<div class="card-header">用户分布</div>
<div class="card-body">
<div id="pieChart" style="width: 100%; height: 300px;"></div>
</div>
</div>
</div>
<!-- 实时数据展示 -->
<div class="col-md-8">
<div class="card mb-4">
<div class="card-header">实时数据</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<tr>
<th>时间</th>
<th>值</th>
</tr>
</thead>
<tbody id="dataTableBody">
<!-- 动态填充数据 -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- 引入 jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- 引入自定义脚本 -->
<script src="{{ url_for('static', filename='js/scripts.js') }}"></script>
</body>
</html>
3. static/css/styles.css
body {
background-color: #f8f9fa;
}
.card {
background-color: #ffffff;
}
.card-header {
background-color: #007bff;
color: #ffffff;
font-weight: bold;
}
4. static/js/scripts.js
$(document).ready(function() {
// 初始化柱状图
var barChart = echarts.init(document.getElementById('barChart');
var barOption = {
title: {
text: '月度销售数据'
},
tooltip: {},
xAxis: {
type: 'category',
data: ['一月','二月','三月','四月','五月','六月']
},
yAxis: {
type: 'value'
},
series: [{
name: '销售额',
type: 'bar',
data: [120, 200, 150, 80, 70, 110],
itemStyle: {
color: '#5470C6'
}
}]
};
barChart.setOption(barOption);
// 初始化折线图
var lineChart = echarts.init(document.getElementById('lineChart');
var lineOption = {
title: {
text: '网站访问趋势'
},
tooltip: {},
xAxis: {
type: 'category',
data: ['周一','周二','周三','周四','周五','周六','周日']
},
yAxis: {
type: 'value'
},
series: [{
name: '访问量',
type: 'line',
data: [150, 230, 224, 218, 135, 147, 260],
itemStyle: {
color: '#91CC75'
}
}]
};
lineChart.setOption(lineOption);
// 初始化饼图
var pieChart = echarts.init(document.getElementById('pieChart');
var pieOption = {
title: {
text: '用户分布'
},
tooltip: {
trigger: 'item'
},
legend: {
top: '5%',
left: 'center'
},
series: [{
name: '访问来源',
type: 'pie',
radius: '50%',
data: [
{value: 1048, name: '搜索引擎'},
{value: 735, name: '直接访问'},
{value: 580, name: '邮件营销'},
{value: 484, name: '联盟广告'},
{value: 300, name: '视频广告'}
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
formatter: '{b}: {c} ({d}%)'
}
}]
};
pieChart.setOption(pieOption);
// 实时数据更新
function fetchData() {
$.ajax({
url: '/api/data',
method: 'GET',
success: function(response) {
var data = response;
// 更新表格
var tableRow = '<tr><td>' + datetimeConverter(data.timestamp) + '</td><td>' + data.value + '</td></tr>';
$('#dataTableBody').prepend(tableRow);
// 保持表格最多显示10条记录
if ($('#dataTableBody tr').length > 10) {
$('#dataTableBody tr').last().remove();
}
// 更新柱状图
barOption.xAxis.data.push(datetimeConverter(data.timestamp).split(' ')[1]);
barOption.series[0].data.push(data.value);
barChart.setOption(barOption);
// 更新折线图
lineOption.xAxis.data.push(datetimeConverter(data.timestamp).split(' ')[1]);
lineOption.series[0].data.push(data.value);
lineChart.setOption(lineOption);
// 更新饼图(示例中不涉及动态更新)
},
error: function(error) {
console.error('数据获取失败:', error);
}
});
}
// 转换时间戳为可读的日期时间格式
function datetimeConverter(timestamp) {
var date = new Date(timestamp * 1000);
var year = date.getFullYear();
var month = ('0' + (date.getMonth() + 1)).slice(-2);
var day = ('0' + date.getDate()).slice(-2);
var hours = ('0' + date.getHours()).slice(-2);
var minutes = ('0' + date.getMinutes()).slice(-2);
var seconds = ('0' + date.getSeconds()).slice(-2);
return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;
}
// 每隔5秒获取一次数据
setInterval(fetchData, 5000);
// 初始获取数据
fetchData();
});
总结
通过本文,我们详细介绍了如何使用 Flask、echarts 和 jQuery 构建一个数据大屏。整个过程包括环境搭建、后端开发、前端设计以及前后端整合。通过实际代码示例和图文说明,展示了如何实现实时数据展示和动态图表更新。希望本文能为您的数据可视化项目提供有益的参考。