diff --git a/themes/butterfly/layout/archive.pug b/themes/butterfly/layout/archive.pug
index 913dedc..50bda33 100644
--- a/themes/butterfly/layout/archive.pug
+++ b/themes/butterfly/layout/archive.pug
@@ -3,6 +3,7 @@ extends includes/layout.pug
block content
include ./includes/mixins/article-sort.pug
#archive
+ #posts-chart(data-start="2021-01" style="height: 300px; padding: 10px;")
.article-sort-title= `${_p('page.articles')} - ${getArchiveLength()}`
+articleSort(page.posts)
include includes/pagination.pug
\ No newline at end of file
diff --git a/themes/butterfly/layout/includes/page/categories.pug b/themes/butterfly/layout/includes/page/categories.pug
index 79153c8..fe02784 100644
--- a/themes/butterfly/layout/includes/page/categories.pug
+++ b/themes/butterfly/layout/includes/page/categories.pug
@@ -1 +1,3 @@
-.category-lists!= list_categories()
\ No newline at end of file
+
+.category-lists!= list_categories()
+#categories-chart(data-parent="true" style="height: 300px; padding: 10px;")
\ No newline at end of file
diff --git a/themes/butterfly/layout/includes/page/tags.pug b/themes/butterfly/layout/includes/page/tags.pug
index b5b62cd..ef56d4f 100644
--- a/themes/butterfly/layout/includes/page/tags.pug
+++ b/themes/butterfly/layout/includes/page/tags.pug
@@ -1,2 +1,4 @@
+
.tag-cloud-list.text-center
- !=cloudTags({source: site.tags, orderby: page.orderby || 'random', order: page.order || 1, minfontsize: 1.2, maxfontsize: 1.5, limit: 0, unit: 'em'})
\ No newline at end of file
+ !=cloudTags({source: site.tags, orderby: page.orderby || 'random', order: page.order || 1, minfontsize: 1.2, maxfontsize: 1.5, limit: 0, unit: 'em'})
+#tags-chart(data-length="10" style="height: 300px; padding: 10px;")
\ No newline at end of file
diff --git a/themes/butterfly/scripts/helpers/chart.js b/themes/butterfly/scripts/helpers/chart.js
new file mode 100644
index 0000000..516e608
--- /dev/null
+++ b/themes/butterfly/scripts/helpers/chart.js
@@ -0,0 +1,445 @@
+const cheerio = require('cheerio')
+const moment = require('moment')
+
+hexo.extend.filter.register('after_render:html', function (locals) {
+ const $ = cheerio.load(locals)
+ const post = $('#posts-chart')
+ const tag = $('#tags-chart')
+ const category = $('#categories-chart')
+ const htmlEncode = false
+
+ if (post.length > 0 || tag.length > 0 || category.length > 0) {
+ if (post.length > 0 && $('#postsChart').length === 0) {
+ if (post.attr('data-encode') === 'true') htmlEncode = true
+ post.after(postsChart(post.attr('data-start')))
+ }
+ if (tag.length > 0 && $('#tagsChart').length === 0) {
+ if (tag.attr('data-encode') === 'true') htmlEncode = true
+ tag.after(tagsChart(tag.attr('data-length')))
+ }
+ if (category.length > 0 && $('#categoriesChart').length === 0) {
+ if (category.attr('data-encode') === 'true') htmlEncode = true
+ category.after(categoriesChart(category.attr('data-parent')))
+ }
+
+ if (htmlEncode) {
+ return $.root().html().replace(/&#/g, '')
+ } else {
+ return $.root().html()
+ }
+ } else {
+ return locals
+ }
+}, 15)
+function switchPostChart () {
+ // 这里为了统一颜色选取的是“明暗模式”下的两种字体颜色,也可以自己定义
+ let color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4C4948' : 'rgba(255,255,255,0.7)'
+ if (document.getElementById('posts-chart') && postsOption) {
+ try {
+ let postsOptionNew = postsOption
+ postsOptionNew.title.textStyle.color = color
+ postsOptionNew.xAxis.nameTextStyle.color = color
+ postsOptionNew.yAxis.nameTextStyle.color = color
+ postsOptionNew.xAxis.axisLabel.color = color
+ postsOptionNew.yAxis.axisLabel.color = color
+ postsOptionNew.xAxis.axisLine.lineStyle.color = color
+ postsOptionNew.yAxis.axisLine.lineStyle.color = color
+ postsOptionNew.series[0].markLine.data[0].label.color = color
+ postsChart.setOption(postsOptionNew)
+ } catch (error) {
+ console.log(error)
+ }
+ }
+ if (document.getElementById('tags-chart') && tagsOption) {
+ try {
+ let tagsOptionNew = tagsOption
+ tagsOptionNew.title.textStyle.color = color
+ tagsOptionNew.xAxis.nameTextStyle.color = color
+ tagsOptionNew.yAxis.nameTextStyle.color = color
+ tagsOptionNew.xAxis.axisLabel.color = color
+ tagsOptionNew.yAxis.axisLabel.color = color
+ tagsOptionNew.xAxis.axisLine.lineStyle.color = color
+ tagsOptionNew.yAxis.axisLine.lineStyle.color = color
+ tagsOptionNew.series[0].markLine.data[0].label.color = color
+ tagsChart.setOption(tagsOptionNew)
+ } catch (error) {
+ console.log(error)
+ }
+ }
+ if (document.getElementById('categories-chart') && categoriesOption) {
+ try {
+ let categoriesOptionNew = categoriesOption
+ categoriesOptionNew.title.textStyle.color = color
+ categoriesOptionNew.legend.textStyle.color = color
+ if (!categoryParentFlag) { categoriesOptionNew.series[0].label.color = color }
+ categoriesChart.setOption(categoriesOptionNew)
+ } catch (error) {
+ console.log(error)
+ }
+ }
+}
+document.getElementById("mode-button").addEventListener("click", function () { setTimeout(switchPostChart, 100) })
+
+function postsChart (startMonth) {
+ const startDate = moment(startMonth || '2020-01')
+ const endDate = moment()
+
+ const monthMap = new Map()
+ const dayTime = 3600 * 24 * 1000
+ for (let time = startDate; time <= endDate; time += dayTime) {
+ const month = moment(time).format('YYYY-MM')
+ if (!monthMap.has(month)) {
+ monthMap.set(month, 0)
+ }
+ }
+ hexo.locals.get('posts').forEach(function (post) {
+ const month = post.date.format('YYYY-MM')
+ if (monthMap.has(month)) {
+ monthMap.set(month, monthMap.get(month) + 1)
+ }
+ })
+ const monthArr = JSON.stringify([...monthMap.keys()])
+ const monthValueArr = JSON.stringify([...monthMap.values()])
+
+ return `
+ `
+}
+
+function tagsChart (len) {
+ const tagArr = []
+ hexo.locals.get('tags').map(function (tag) {
+ tagArr.push({ name: tag.name, value: tag.length, path: tag.path })
+ })
+ tagArr.sort((a, b) => { return b.value - a.value })
+
+ const dataLength = Math.min(tagArr.length, len) || tagArr.length
+ const tagNameArr = []
+ for (let i = 0; i < dataLength; i++) {
+ tagNameArr.push(tagArr[i].name)
+ }
+ const tagNameArrJson = JSON.stringify(tagNameArr)
+ const tagArrJson = JSON.stringify(tagArr)
+
+ return `
+ `
+}
+
+function categoriesChart (dataParent) {
+ const categoryArr = []
+ let categoryParentFlag = false
+ hexo.locals.get('categories').map(function (category) {
+ if (category.parent) categoryParentFlag = true
+ categoryArr.push({
+ name: category.name,
+ value: category.length,
+ path: category.path,
+ id: category._id,
+ parentId: category.parent || '0'
+ })
+ })
+ categoryParentFlag = categoryParentFlag && dataParent === 'true'
+ categoryArr.sort((a, b) => { return b.value - a.value })
+ function translateListToTree (data, parent) {
+ let tree = []
+ let temp
+ data.forEach((item, index) => {
+ if (data[index].parentId == parent) {
+ let obj = data[index];
+ temp = translateListToTree(data, data[index].id);
+ if (temp.length > 0) {
+ obj.children = temp
+ }
+ if (tree.indexOf())
+ tree.push(obj)
+ }
+ })
+ return tree
+ }
+ const categoryNameJson = JSON.stringify(categoryArr.map(function (category) { return category.name }))
+ const categoryArrJson = JSON.stringify(categoryArr)
+ const categoryArrParentJson = JSON.stringify(translateListToTree(categoryArr, '0'))
+
+ return `
+ `
+}