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()) }
if (htmlEncode) { return $.root().html().replace(/&#/g, '&#') } else { return $.root().html() } } else { return locals } }, 15)
function postsChart (startMonth) { const startDate = moment(startMonth || '2022-04') 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 ` <script id="postsChart"> var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)' var postsChart = echarts.init(document.getElementById('posts-chart'), 'light'); var postsOption = { title: { text: '文章发布统计图', x: 'center', textStyle: { color: color } }, tooltip: { trigger: 'axis' }, xAxis: { name: '', type: 'category', boundaryGap: false, nameTextStyle: { color: color }, axisTick: { show: false }, axisLabel: { show: true, color: color, interval: 0, rotate: 0 }, axisLine: { show: true, lineStyle: { color: color } }, data: ${monthArr} }, yAxis: { name: '文章篇数', type: 'value', nameTextStyle: { color: color }, splitLine: { show: false }, axisTick: { show: false }, axisLabel: { show: true, color: color }, axisLine: { show: true, lineStyle: { color: color } } }, series: [{ name: '文章篇数', type: 'line', smooth: true, lineStyle: { width: 0 }, showSymbol: false, itemStyle: { opacity: 1, color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(128, 255, 165)' }, { offset: 1, color: 'rgba(1, 191, 236)' }]) }, areaStyle: { opacity: 1, color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(128, 255, 165)' }, { offset: 1, color: 'rgba(1, 191, 236)' }]) }, data: ${monthValueArr}, markLine: { data: [{ name: '平均值', type: 'average', label: { color: color } }] } }] }; postsChart.setOption(postsOption); setpRotate(); window.addEventListener('resize', () => { setpRotate(); postsChart.resize(); }); function setpRotate() { let postsOptionNew = postsOption if (document.body.clientWidth<=768) { postsOptionNew.xAxis.axisLabel.rotate = 40 }else{ postsOptionNew.xAxis.axisLabel.rotate = 0 } postsChart.setOption(postsOptionNew) } </script>` }
function tagsChart (len) { const tagArr = [] hexo.locals.get('tags').map(function (tag) { tagArr.push({ name: tag.name, value: tag.length }) }) tagArr.sort((a, b) => { return b.value - a.value })
const dataLength = Math.min(tagArr.length, len) || tagArr.length const tagNameArr = [] const tagCountArr = [] for (let i = 0; i < dataLength; i++) { tagNameArr.push(tagArr[i].name) tagCountArr.push(tagArr[i].value) } const tagNameArrJson = JSON.stringify(tagNameArr) const tagCountArrJson = JSON.stringify(tagCountArr)
return ` <script id="tagsChart"> var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)' var tagsChart = echarts.init(document.getElementById('tags-chart'), 'light'); var tagsOption = { title: { text: 'Top ${dataLength} 标签统计图', x: 'center', textStyle: { color: color } }, tooltip: {}, xAxis: { name: '', type: 'category', nameTextStyle: { color: color }, axisTick: { show: false }, axisLabel: { show: true, color: color, interval: 0 }, axisLine: { show: true, lineStyle: { color: color } }, data: ${tagNameArrJson} }, yAxis: { name: '文章篇数', type: 'value', splitLine: { show: false }, nameTextStyle: { color: color }, axisTick: { show: false }, axisLabel: { show: true, color: color }, axisLine: { show: true, lineStyle: { color: color } } }, series: [{ name: '文章篇数', type: 'bar', data: ${tagCountArrJson}, itemStyle: { borderRadius: [5, 5, 0, 0], color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(128, 255, 165)' }, { offset: 1, color: 'rgba(1, 191, 236)' }]) }, emphasis: { itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(128, 255, 195)' }, { offset: 1, color: 'rgba(1, 211, 255)' }]) } }, markLine: { data: [{ name: '平均值', type: 'average', label: { color: color } }] } }] }; tagsChart.setOption(tagsOption); setRotate(); window.addEventListener('resize', () => { setRotate(); tagsChart.resize(); }); function setRotate() { let tagsOptionNew = tagsOption if (document.body.clientWidth<=768) { tagsOptionNew.xAxis.axisLabel.rotate = -90 }else{ tagsOptionNew.xAxis.axisLabel.rotate = 40 } tagsChart.setOption(tagsOptionNew) }
tagsChart.on('click', 'series', (event) => { if(event.name != '平均值'){ let href = '/tags/' + event.name + '/'; window.location.href = href; } }); </script>` }
function categoriesChart () { const categoryArr = [] hexo.locals.get('categories').map(function (category) { categoryArr.push({ name: category.name, value: category.length }) }) categoryArr.sort((a, b) => { return b.value - a.value }); const categoryArrJson = JSON.stringify(categoryArr)
return ` <script id="categoriesChart"> var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)' var categoriesChart = echarts.init(document.getElementById('categories-chart'), 'light'); var categoriesOption = { title: { text: '文章分类统计图', x: 'center', textStyle: { color: color } }, legend: { top: 'bottom', type: 'scroll', textStyle: { color: color } }, tooltip: { trigger: 'item', formatter: '{a} <br/>{b} : {c} ({d}%)' }, series: [{ name: '文章篇数', type: 'pie', radius: [30, 80], center: ['50%', '50%'], roseType: 'area', label: { color: color, formatter: '{b} : {c} ({d}%)' }, data: ${categoryArrJson}, itemStyle: { emphasis: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(255, 255, 255, 0.5)' } } }] }; categoriesChart.setOption(categoriesOption); window.addEventListener('resize', () => { categoriesChart.resize(); }); categoriesChart.on('click', 'series', (event) => { let href = '/categories/' + event.name + '/'; window.location.href = href; }); </script>` }
|