一. 前言
Bootstrap
是一个流行的前端框架,而ECharts是一个流行的可视化库。
Bootstrap
可以用来设计网站和应用程序的用户界面,而ECharts可以用来创建交互式和可视化的图表。
chart.js
中文文档:http://www.bootcss.com/p/chart.js/docs/
二. 进阶使用
基本使用已经在前文有过相关介绍,链接:https://blog.csdn.net/qq_43030934/article/details/131540606
本文是基于Django+bootstrap+echart插件的一个进阶使用,基本的用法就不做过多介绍了
二. 效果图
1.日活日增统计
2. 年月数据统计
三. 示例代码
废话不多说了,直接上代码,
1. 前端
代码是根据相关项目编写的,大家可根据自己的项目进行参考使用
{% extends "base.html" %} {% load static %}
{% block main %}
{# <script src="../../../../static/js/echarts-v5.1.2.min.js"></script>#}
{% if 'is_superuser' in permissions.keys %}
<!-- daily active users statistics start -->
<section class="section" style="padding: 100px 0 30px 0">
<div class="container">
<div class="row justify-content-center">
<div class="col-12 text-center">
<div class="section-title mb-2">
<h4 class="title mb-4">用户数据统计</h4>
</div>
</div><!--end col-->
</div><!--end row-->
<div class="row mt-4 pt-2 position-relative" id="userDailyData" style="z-index: 1;">
<div class="col-lg-7 col-6 mt-4 pt-2">
<div class="counter-box text-center">
<div id="userDailyIncrease" style="width:auto;height:400px;"></div>
</div><!--end counter box-->
</div>
<div class="col-lg-5 col-6 mt-4 pt-2">
<div class="counter-box text-center">
<div id="userBaseData" style="width:auto;height:400px;"></div>
</div><!--end counter box-->
</div>
</div><!--end row-->
<div class="feature-posts-placeholder"></div>
</div><!--end container-->
</section><!--end section-->
<!-- daily active users statistics End -->
<!-- monthly/year increase users statistics start -->
<section class="section" style="padding: 30px 0 100px 0">
<div class="container">
<div class="row mt-4 pt-2 position-relative" style="z-index: 1;">
<div class="col-lg-6 col-6 mt-4 pt-2">
<div class="counter-box text-center">
<div id="userMonthlyIncrease" style="width:auto;height:400px;"></div>
</div><!--end counter box-->
</div>
<div class="col-lg-6 col-6 mt-4 pt-2">
<div class="counter-box text-center">
<div id="userYearIncrease" style="width:auto;height:400px;"></div>
</div><!--end counter box-->
</div>
</div><!--end row-->
<div class="feature-posts-placeholder"></div>
</div><!--end container-->
</section><!--end section-->
<!-- monthly/year increase users statistics End -->
{% endif %}
<!-- Document change achievement Start -->
<section class="section bg-light">
<div class="container">
<div class="row mt-4 pt-2 position-relative" id="counter" style="z-index: 1;">
<div class="col-md col-6 mt-4 pt-2">
<div class="counter-box text-center">
<img src="{% static 'images/homepage/Asset260.svg' %}" class="avatar avatar-small" alt="">
<h2 class="mb-0 mt-4"><span class="counter-value"
data-count="97">{{ quarterData.requestTotal }}</span></h2>
<h6 class="counter-head text-muted">{{ quarterData.currentQuarter }} Change requests</h6>
</div><!--end counter box-->
</div>
<div class="col-md col-6 mt-4 pt-2">
<div class="counter-box text-center">
<img src="{% static 'images/homepage/Asset189.svg' %}" class="avatar avatar-small" alt="">
<h2 class="mb-0 mt-4"><span class="counter-value"
data-count="15">{{ quarterData.completed }}</span></h2>
<h6 class="counter-head text-muted">Completed</h6>
</div><!--end counter box-->
</div>
<div class="col-md col-6 mt-4 pt-2">
<div class="counter-box text-center">
<img src="{% static 'images/homepage/Asset192.svg' %}" class="avatar avatar-small" alt="">
<h2 class="mb-0 mt-4"><span class="counter-value"
data-count="98">{{ quarterData.percentageComplete }}</span>%</h2>
<h6 class="counter-head text-muted">Request Complete</h6>
</div><!--end counter box-->
</div>
</div><!--end row-->
<div class="feature-posts-placeholder"></div>
</div><!--end container-->
</section><!--end section-->
<!-- Document change achievement End -->
{% endblock %}
{% block script %}
<script>
var MyViewVar = {
userCurActiveData: {{ userCurActiveData|safe }},
usersDataByDaily: {{ usersDataByDaily|safe }},
usersDataByMonthly: {{ usersDataByMonthly|safe }},
usersDataByYears: {{ usersDataByYears|safe }},
}
console.log(MyViewVar)
var userDailyIncreaseChart = echarts.init(document.getElementById('userDailyIncrease'));
userDailyIncreaseChart.setOption({
title: {
text: '日增日活',
x: 'center'
},
// 图表图例
legend: {
orient: 'vertical',
data: ['日活用户', '日增用户',],
left: 'right',
},
xAxis: {
name: '日',
type: 'category',
data: MyViewVar.usersDataByDaily.date_list,
boundaryGap: false,
axisLabel: {
inside: false, //刻度标签是否朝内,false朝外
interval: 1, // 设置标签全部显示
rotate: 30, // 设置标签旋转角度
maxInterval: 1000, // 设置刻度间隔
},
axisLine: {
lineStyle: {
color: '#333',
type: 'solid',
},
}
},
yAxis: {
name: '数量',
type: 'value',
axisLine: {
show: true, // 是否显示坐标轴轴线
lineStyle: {
color: '#333', // 坐标轴线线的颜色
type: 'solid', // 坐标轴线线的类型(solid实线类型;dashed虚线类型;dotted点状类型)
},
},
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
series: [
{
name: '日增用户',
data: MyViewVar.usersDataByDaily.user_increase_count_list,
type: 'line',
itemStyle: {
color: '#91CC75',
},
markPoint: {
data: [
{type: 'max', name: '最大值'},
{type: 'min', name: '最小值'}
]
},
lineStyle: {
color: '#91CC75', //线颜色
type: 'solid', //线的类型
opacity: 0.8, //线透明度
shadowBlur: 5, //阴影模糊度
shadowColor: '#999', //阴影颜色
shadowOffsetX: 2, //阴影X轴偏移量
shadowOffsetY: 2, //阴影Y轴偏移量
radius: 100 //曲线圆角半径
},
},
{
name: '日活用户',
type: 'line',
data: MyViewVar.usersDataByDaily.user_active_count_list,
itemStyle: {
color: '#FFC858',
},
markPoint: {
data: [
{type: 'max', name: '最大值'},
{type: 'min', name: '最小值'}
]
},
lineStyle: {
color: '#FFC858', //线颜色
},
},
]
});
var userBaseDataChart = echarts.init(document.getElementById('userBaseData'));
//定义饼图数据
var data = [
{value: MyViewVar.userCurActiveData.dailyActiveCount, name: '日活用户'},
{value: MyViewVar.userCurActiveData.monthlyActiveCount, name: '月活用户'},
];
//定义饼图配置项
var option = {
title: {
text: '用户当日及当月活跃人数\n' + '用户总人数:' + MyViewVar.userCurActiveData.totalCount,
x: 'center'
},
tooltip: {
trigger: 'item',
formatter: "{a} <br/>{b} : {c}<br/>" + "用户总人数:" + MyViewVar.userCurActiveData.totalCount
},
legend: {
orient: 'vertical',
left: 'right',
data: ['日活用户', '月活用户']
},
series: [
{
name: '用户基础数据统计',
type: 'pie',
radius: ['40%', '60%'],
center: ['50%', '60%'],
data: data,
label: {
show: true,
formatter: function (params) {
// 计算总数
var total = MyViewVar.userCurActiveData.totalCount;
// 显示数据项名称和百分比
return params.name + '\n' + params.value + '人' + '\n' + (params.value / total * 100).toFixed(2) + '%';
}
},
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
color: ['#FF8D5D', '#FFC858']
}
]
};
//渲染饼图
userBaseDataChart.setOption(option);
var userMonthlyIncreaseChart = echarts.init(document.getElementById('userMonthlyIncrease'));
userMonthlyIncreaseChart.setOption({
title: {
text: '月增月活',
x: 'center'
},
// 图表图例
legend: {
data: ['月活用户', '月增用户'],
left: 'right',
},
xAxis: {
name: '月',
type: 'category',
data: MyViewVar.usersDataByMonthly.month_list,
boundaryGap: false,
axisLabel: {
inside: false, //刻度标签是否朝内,false朝外
interval: 0, // 设置标签全部显示
rotate: 30, // 设置标签旋转角度
maxInterval: 1000, // 设置刻度间隔
},
axisLine: {
lineStyle: {
color: '#333',
type: 'solid',
},
},
},
yAxis: {
name: '数量',
type: 'value',
axisLine: {
show: true, // 是否显示坐标轴轴线
lineStyle: {
color: '#333', // 坐标轴线线的颜色
type: 'solid', // 坐标轴线线的类型(solid实线类型;dashed虚线类型;dotted点状类型)
},
},
},
tooltip: {
trigger: 'axis',
},
series: [
{
name: '月活用户',
type: 'line',
data: MyViewVar.usersDataByMonthly.user_active_count_list,
itemStyle: {
color: '#FFC858',
},
markPoint: {
data: [
{type: 'max', name: '最大值'},
{type: 'min', name: '最小值'}
]
},
lineStyle: {
color: '#FFC858', //线颜色
},
},
{
name: '月增用户',
data: MyViewVar.usersDataByMonthly.user_increase_count_list,
type: 'line',
itemStyle: {
color: '#91CC75',
},
label: {
show: true,
formatter: function (params) {
return params.value;
}
},
markPoint: {
data: [
{type: 'max', name: '最大值'},
{type: 'min', name: '最小值'}
]
},
lineStyle: {
color: '#91CC75', //线颜色
},
},
]
});
var userYearIncreaseChart = echarts.init(document.getElementById('userYearIncrease'));
userYearIncreaseChart.setOption({
title: {
text: '用户年增长及跃人数\n' + '用户总人数:' + MyViewVar.userCurActiveData.totalCount,
x: 'center'
},
tooltip: {},
legend: {
orient: 'vertical',
data: ['年活跃用户', '年增长用户'],
left: 'right',
},
xAxis: {
axisLine: {
show: true, // 是否显示坐标轴轴线
lineStyle: {
color: '#333', // 坐标轴线线的颜色
type: 'solid', // 坐标轴线线的类型(solid实线类型;dashed虚线类型;dotted点状类型)
},
},
data: MyViewVar.usersDataByYears.year_list,
},
yAxis: {
name: '数量',
type: 'value',
axisLine: {
show: true, // 是否显示坐标轴轴线
lineStyle: {
color: '#333', // 坐标轴线线的颜色
type: 'solid', // 坐标轴线线的类型(solid实线类型;dashed虚线类型;dotted点状类型)
},
},
},
series: [
{
name: '年活跃用户',
type: 'bar',
data: MyViewVar.usersDataByYears.user_active_count_list,
itemStyle: {
color: '#FFC858',
},
},
{
name: '年增长用户',
type: 'bar',
data: MyViewVar.usersDataByYears.user_increase_count_list,
},
],
label: {
show: true,
position: 'top', // 在柱形顶部显示标签
formatter: '{c}', // 数值显示格式
color: '#000', // 标签颜色
fontSize: 14, // 标签字体大小
},
})
</script>
{% endblock %}
2. 后端代码
后端代码接口使用的技术栈是Django+ORM
代码仅供参考,大家可自行根据自己项目的业务进行参考使用
class DataStatisticsView(LoginRequiredJSONMixin, APIView):
def get(self, request):
permissions = get_user_permissions(request.user.id)
quarterData = get_quarter_data_statistics(CP_Register)
# 获取当前日期
now_date = datetime.date.today()
userCurActiveData = self.get_cur_user_active_data(now_date)
usersDataByDaily = self.get_increase_and_active_users_by_daily(now_date)
usersDataByMonthly = self.get_increase_and_active_users_by_monthly(now_date)
usersDataByYears = self.get_increase_and_active_users_by_years(now_date)
context = {
'permissions': permissions,
'quarterData': quarterData,
'userCurActiveData': userCurActiveData,
'usersDataByDaily': usersDataByDaily,
'usersDataByMonthly': usersDataByMonthly,
'usersDataByYears': usersDataByYears,
}
return render(request, 'teams/my_dashboard/statistics/data_statistics.html', context)
def get_increase_and_active_users_by_years(self, now_date):
"""数据库中按年增长及年活跃人数"""
# 按年增长统计用户
users_per_year = User.objects.annotate(year=ExtractYear('date_joined')).values('year').annotate(
total=Count('id'))
user_increase_count_list = []
year_list = []
for user in users_per_year:
user_increase_count_list.append(user['total'])
year_list.append(user['year'])
# 按年统计活跃人数
users_per_year = User.objects.annotate(year=ExtractYear('last_login')).values('year').annotate(
total=Count('id'))
user_active_count_list = []
for user in users_per_year:
user_active_count_list.append(int(user['total']) * ActiveCoefficient.year_active)
usersDataByYears = {
'user_increase_count_list': user_increase_count_list,
'user_active_count_list': user_active_count_list,
'year_list': year_list,
}
return usersDataByYears
def get_increase_and_active_users_by_monthly(self, now_date):
"""
近一年用户月增及月活跃数据
sqlite按当月统计一年用户的数量sql:SELECT DATE('now', 'start of month') AS end_date,
DATE('now', '-12 months', 'start of month') AS start_date;
SELECT strftime('%Y-%m', date_joined) AS month,
COUNT(id) AS count
FROM auth_user
WHERE date_joined >= DATE('now', '-12 months', 'start of month')
GROUP BY month
ORDER BY month;
"""
user_increase_count_list = []
user_active_count_list = []
month_list = []
# FIXME--bug:某月用户数量为0时无数据
"""
end_date = now_date.replace(day=30)
start_date = (end_date - datetime.timedelta(days=365)).replace(day=1)
{'user_count_list': [33, 37, 30, 35, 25, 22, 11, 35, 4, 6, 1, 7],
'month_list': ['22-07', '22-08', '22-09', '22-10', '22-11', '22-12', '23-01', '23-02', '23-03', '23-04', '23-05', '23-07']
}
users_last_year = User.objects.filter(date_joined__range=(start_date, end_date)).annotate(
month=TruncMonth('date_joined')).values('month').annotate(count=Count('id'))
for user in users_last_year:
user_count_list.append(user['count'])
month_list.append(user['month'].strftime('%y-%m'))
"""
# 计算往前12个月的日期时间,计算月增月活数据
for i in range(12):
# 当月起始时间和月末时间
month_first_day = (now_date - datetime.timedelta(days=365 * i / 12)).replace(day=1)
month_last_day = (month_first_day + datetime.timedelta(days=32)).replace(day=1) - datetime.timedelta(days=1)
month_increase_count = User.objects.filter(date_joined__range=(month_first_day, month_last_day)).count()
month_list.append(month_first_day.strftime('%y-%m'))
user_increase_count_list.append(month_increase_count)
moth_active_count = int(User.objects.filter(
last_login__range=(month_first_day, month_last_day)).count() * ActiveCoefficient.monthly_active)
user_active_count_list.append(moth_active_count)
usersDataByMonthly = {
'user_increase_count_list': user_increase_count_list[::-1],
'user_active_count_list': user_active_count_list[::-1],
'month_list': month_list[::-1],
}
return usersDataByMonthly
def get_increase_and_active_users_by_daily(self, now_date):
"""近一月用户日增日活数据"""
# 获取一个月前日期
start_date = now_date - datetime.timedelta(days=30)
date_list = []
user_increase_count_list = []
user_active_count_list = []
for i in range(1, 31):
# 循环遍历获取当天日期
cur_date = start_date + datetime.timedelta(days=i)
next_date = start_date + datetime.timedelta(days=i + 1)
day_increase_count = User.objects.filter(last_login__range=(cur_date, next_date)).count()
date_list.append(cur_date.strftime('%y-%m-%d'))
user_increase_count_list.append(day_increase_count)
day_active_count = int(
User.objects.filter(last_login__range=(cur_date, next_date)).count() * ActiveCoefficient.daily_active)
user_active_count_list.append(day_active_count)
dailyIncreaseUsers = {
'date_list': date_list,
'user_increase_count_list': user_increase_count_list,
'user_active_count_list': user_active_count_list,
}
return dailyIncreaseUsers
def get_cur_user_active_data(self, now_date):
"""当日及当月活跃数据"""
# 日活用户
dailyActiveCount = User.objects.filter(last_login__gte=now_date).count()
# 月活用户
first_day_of_month = datetime.date(now_date.year, now_date.month, 1)
last_day_of_month = datetime.date(now_date.year, now_date.month + 1, 1) - datetime.timedelta(days=1)
monthlyActiveCount = User.objects.filter(last_login__range=(first_day_of_month, last_day_of_month)).count()
# 用户总数
totalCount = User.objects.all().count()
userCurActiveData = {
'dailyActiveCount': int(dailyActiveCount * ActiveCoefficient.daily_active),
'monthlyActiveCount': int(monthlyActiveCount * ActiveCoefficient.monthly_active),
'totalCount': totalCount,
'date': now_date.strftime('%Y-%m-%d'),
}
return userCurActiveData
utils.py
class ActiveCoefficient:
daily_active = 1.5
monthly_active = 1.5
year_active = 3
def get_user_permissions(user_id):
from registration.models import UserProfile
u_pro = UserProfile.objects.filter(user_id=user_id).first()
permissions = OrderedDict()
if u_pro.is_superuser:
permissions['is_superuser'] = '超级管理员'
if u_pro.is_team_leader:
permissions['is_team_leader'] = '团队负责人'
if u_pro.is_ele_feature_extension_admin:
permissions['ele_feature_extension_admin'] = '普通管理员'
if u_pro.is_es_feature_extension_admin:
permissions['es_feature_extension_admin'] = '普通管理员'
if u_pro.role:
permissions = get_role_permission(u_pro.role.id, permissions)
return permissions
def get_quarter_data_statistics(obj):
"""季度发布数据统计"""
today = datetime.date.today()
current_quarter = (today.month - 1) // 3 + 1
# 当前年份季度
current_year_quarter = str(today.year) + 'Q{}'.format(str(current_quarter))
total = obj.objects.filter(schedule__startswith=current_year_quarter).count()
completed_cnt = obj.objects.filter(schedule__startswith=current_year_quarter).filter(
Q(decision__in=['', 'Released']) | Q(decision__isnull=True)).count()
try:
percentageComplete = int(completed_cnt / total * 100)
except Exception as e:
percentageComplete = 0
logger.info('homePage error :{}'.format(e))
QuarterData = {
'requestTotal': total,
'percentageComplete': percentageComplete,
'completed': completed_cnt,
'currentQuarter': 'Q{}'.format(current_quarter),
}
return QuarterData
以上就是Django + Bootstrap - 【echart】 统计图表进阶使用-统计用户日活日增、月活月增等数据的基本使用,希望对你有所帮助!