网上冲浪的时候看到Uncle_drew的文章数据分析界面,样式好看的同时功能也挺强大,琢磨着给自己也加一个。看了他的教程——花里胡哨的Hexo | 给你的hexo博客加上文章分析之后我发现可太难了🤒,原因就是大佬使用的主题用的是ejs模板,而我用的Butterfly主题使用了pug模板,教程中的代码不能直接套用。因为不是很熟悉pug的写法,本来想放弃的,但还是抱着试一试的心态做了下来🤔值得夸奖哈哈

1. 遇到的问题

如何在pug模板文件中使用JS或CSS?

也怪我看官方文档不仔细,翻了翻主题里源文件才知道,只写一个script或style标签是无法达到目的的,需要在标签后紧跟一个.,即可在后面书写JS或CSS语句了。

传送门:https://www.pugjs.cn/language/plain-text.html

如何在script内部使用Hexo的内置变量获取博客信息?

这也是我翻主题源文件学到的(这方面信息太少😥),使用#{ 变量名 }的格式获取外部的变量内容。而且这里的变量和我看的教程的也不尽相同,比如教程中的site.posts在这里要使用site.posts.data,其它的也同理。

这两个问题最开始的时候困扰了我好久,最终也是通过自己解决了,开心~

2. 实现

解决了上面两个问题之后,实现效果就变得比较容易了。基本的画图逻辑和教程中的相同,有一个旭日图我是自己判断分类关系重新修改代码画的😛。

新建页面analyticsindex.md的内容改为:

1
2
3
4
5
6
7
8
9
---
title: 文章数据统计
date: 2020-07-12 18:26:21
aside: false
comments: false
type: "analytics"
top_img:
---

进入主题目录,打开 layout - page.pug,在判断语句中添加一条判断

1
2
else if page.type === 'analytics'
include analytics.pug

核心内容就在analytics.pug中进行,新建analytics.pug文件在page.pug的同级目录下,复制下面代码就可以了

这里我获得数据的方法还是比较笨,如果有小伙伴有好的方法可以在下面评论呀🙂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
#charts
#posts-chart(style="width: 100%;height:500px;")
#categories-chart(style="width: 100%;height:500px;")
#tags-chart(style="width: 100%;height:500px;")
- var postDate = ""
each post, index in site.posts.data
if index === site.posts.length-1
- postDate = postDate + post.date.format('YYYY-MM')
else
- postDate = postDate + post.date.format('YYYY-MM') + ","
- var categoryName = ""
- var categoryLength = ""
- var categoryParent = ""
- var categoryId = ""
each category, index in site.categories.data
if index === site.categories.length-1
- categoryName = categoryName + category.name
- categoryLength = categoryLength + category.length
- categoryParent = categoryParent + category.parent
- categoryId = categoryId + category._id
else
- categoryName = categoryName + category.name + ","
- categoryLength = categoryLength + category.length + ","
- categoryParent = categoryParent + category.parent + ","
- categoryId = categoryId + category._id + ","
- var tagName = ""
- var tagLength = ""
each tag, index in site.tags.data
if index === site.tags.length-1
- tagName = tagName + tag.name
- tagLength = tagLength + tag.length
else
- tagName = tagName + tag.name + ","
- tagLength = tagLength + tag.length + ","

script(src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js")
script(src="http://cdn.staticfile.org/moment.js/2.24.0/moment.js")
script.
// 基于准备好的dom,初始化echarts实例
let postsChart = echarts.init(document.getElementById('posts-chart'));
let categoriesChart = echarts.init(document.getElementById('categories-chart'));
let tagsChart = echarts.init(document.getElementById('tags-chart'));

/* calculate postsOption data. */
var startDate = moment().subtract(1, 'years').startOf('month');
var endDate = moment().endOf('month');

var monthMap = new Map();
var dayTime = 3600 * 24 * 1000;
for (var time = startDate; time <= endDate; time += dayTime) {
var month = moment(time).format('YYYY-MM');
if (!monthMap.has(month)) {
monthMap.set(month, 0);
}
}
var postDate = '#{ postDate }';
var postDateArr = postDate.split(",");

for (let i = 0; i < postDateArr.length; i++) {
if (monthMap.has(postDateArr[i])) {
monthMap.set(postDateArr[i], monthMap.get(postDateArr[i])+1)
}
}

var monthArr = Array.from(monthMap.keys());
var monthValueArr = Array.from(monthMap.values());

let postsOption = {
title: {
text: '文章发布统计图',
top: 0,
x: 'center'
},
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: monthArr
},
yAxis: {
type: 'value',
},
series: [
{
name: 'postsNumberName',
type: 'line',
color: ['#6772e5'],
data: monthValueArr,
lineStyle: {
width: 2.5
},
markPoint: {
symbolSize: 45,
color: ['#fa755a','#3ecf8e','#82d3f4'],
data: [{
type: 'max',
itemStyle: {color: ['#3ecf8e']},
name: 'maximum'
}, {
type: 'min',
itemStyle: {color: ['#fa755a']},
name: 'minimum'
}]
},
markLine: {
itemStyle: {color: ['#ab47bc']},
data: [
{type: 'average', name: 'average'}
]
}
}
]
};

/* calculate categoriesOption data. */
var categoryArr = [];
var categoryName = '#{ categoryName }';
var categoryNameArr = categoryName.split(",");
var categoryLength = '#{ categoryLength }';
var categoryLengthArr = categoryLength.split(",");
var categoryLengthArr = categoryLengthArr.map(Number);
var categoryParent = '#{ categoryParent }';
var categoryParentArr = categoryParent.split(",");
var categoryId = '#{ categoryId }';
var categoryIdArr = categoryId.split(",");

for (let i = 0; i < categoryNameArr.length; i++) {
categoryArr.push({name: categoryNameArr[i], value: categoryLengthArr[i], id: categoryIdArr[i], parent: categoryParentArr[i]});
}

var childMap = new Map();
var parentArr = [];

/* 分开子母分类 */
for (let i = 0; i < categoryArr.length; i++) {
if (categoryArr[i]['parent'] != 'undefined') {
if (childMap.has(categoryArr[i]['parent'])) {
child = childMap.get(categoryArr[i]['parent']);
child.push({name: categoryNameArr[i], value: categoryLengthArr[i]});
} else {
childMap.set(categoryArr[i]['parent'], [{name: categoryNameArr[i], value: categoryLengthArr[i]}]);
}
} else {
parentArr.push({name: categoryNameArr[i], value: categoryLengthArr[i], id: categoryIdArr[i]});
}
}

for (let i = 0; i < parentArr.length; i++) {
if (childMap.has(parentArr[i]['id'])) {
child = childMap.get(parentArr[i]['id']);
parentArr[i]['children'] = child;
}
}

let categoriesOption = {
title: {
text: '文章分类统计图',
top: 1,
x: 'center'
},
tooltip: {
trigger: 'item',
formatter: "categories <br/>{b} : {c}"
},
series: [
{
type: 'sunburst',
radius: ['10%', '85%'],
center: ['50%', '55%'],
data: parentArr,
label: {
align: 'center'
},
itemStyle: {
opacity: 0.95
}
}
],
color: ['#37a2da', '#67e0e3', '#9fe6b8', '#ffdb5c','#ff9f7f', '#ca8622', '#9d96f5','#8378ea', '#96bfff']
};
// 计算top10标签
var tagArr = [];
var tagName = '#{ tagName }';
var tagNameArr = tagName.split(",");
var tagLength = '#{ tagLength }';
var tagLengthArr = tagLength.split(",");
var tagLengthArr = tagLengthArr.map(Number);

for (let i = 0; i < tagNameArr.length; i++) {
tagArr.push({name: tagNameArr[i], value: tagLengthArr[i]});
}
tagArr.sort((a, b) => {return b.value - a.value});

var tagXAxisArr = [];
var tagCountArr = [];
for (var i = 0, len = Math.min(tagArr.length, 10); i < len; i++) {
tagXAxisArr.push(tagArr[i].name);
tagCountArr.push(tagArr[i].value);
}

let tagsOption = {
title: {
text: 'Top10标签统计图 ',
top: 2,
x: 'center'
},
tooltip: {},
xAxis: [
{
type: 'category',
data: tagXAxisArr
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
type: 'bar',
color: ['#82d3f4'],
barWidth : 18,
data: tagCountArr,
markPoint: {
symbolSize: 45,
data: [{
type: 'max',
itemStyle: {color: ['#3ecf8e']},
name: 'maximum'
}, {
type: 'min',
itemStyle: {color: ['#fa755a']},
name: 'minimum'
}],
},
markLine: {
itemStyle: {color: ['#ab47bc']},
data: [
{type: 'average', name: 'average'}
]
}
}
]
};


// 使用刚指定的配置项和数据显示图表。
postsChart.setOption(postsOption);
categoriesChart.setOption(categoriesOption);
tagsChart.setOption(tagsOption);

效果如下:

3. 参考