当博客有了一定流量或者有一定文章篇数的时候,我们就可以考虑使用 Echarts 图表统计,为我们的博客提供更好的用户体验,而且能更直观地看到数据交互。

引进 Echarts

这里有两种方式可以选择:

  1. 引进 Echarts
  2. npm 安装 hexo-butterfly-charts

这里我们选择第一种方式,可以自定义 Echarts 配置项。

  1. [Blogroot]\_config.butterfly.yml\ 配置项引进 Echarts:
    1
    2
    3
    inject:
    head:
    - <script data-pjax src="https://cyan-blog.oss-cn-shenzhen.aliyuncs.com/cdn/js/echarts.min.js"></script>

    这里要注意 Echarts 的版本,这里我使用的是 V5.3.2 的,如果版本不一致,可能出现图表渲染失败。

  1. [Blogroot]\ 根目录下执行命令 npm i hexo-butterfly-charts --save:

    1
    npm i hexo-butterfly-charts --save
  2. 具体使用方法可以参考 hexo-butterfly-charts

标签统计柱状图

  1. 新建 [Blogroot]\themes\butterfly\scripts\helpers\hexo_echarts 工具类函数(文件名称可以自定义), 添加 tag_ranking_bar 函数:

    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
    // 标签统计柱状图
    hexo.extend.helper.register('tag_ranking_bar', function (options) {
    const { type, id, topNum, title, color, yAxisName, seriesName } = options
    // id 和 type 必须指定
    if (!id || !type) return
    // 获取 tags 标签页信息
    const tagArr = []
    hexo.locals.get('tags').map(function (tag) {
    tagArr.push([tag.name, tag.length])
    })
    // 对数组进行排序,然后取 top 10
    tagArr.sort((x, y) => { return y[0] - x[0] })
    const echarts_obj = {
    tag: tagArr.slice(0, topNum)
    }
    return `
    <script type="text/javascript" id="${id}">
    var themeMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
    var tagsChart = echarts.init(document.getElementById("${id}"),themeMode);

    // 指定图表的配置项和数据
    var tagsOption = {
    color: "${color}",
    backgroundColor: '',
    title: {
    text: "${title}",
    x: 'center'
    },
    dataset: [
    {
    dimensions: ['name', 'count'],
    source: ${JSON.stringify(echarts_obj[type])}
    },
    {
    transform: {
    type: 'sort',
    config: { dimension: 'count', order: 'desc' }
    }
    }
    ],
    tooltip: {},
    xAxis: {
    type: 'category'
    },
    yAxis: {
    name: "${yAxisName}",
    type: 'value',
    splitLine: {
    show: false
    },
    axisTick: {
    show: false
    },
    axisLine: {
    show: true
    }
    },
    series: {
    name: "${seriesName}",
    type: 'bar',
    encode: { x: 'name', y: 'count' },
    datasetIndex: 1,
    itemStyle: {
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
    { offset: 0, color: '#83bff6' },
    { offset: 0.5, color: '#188df0' },
    { offset: 1, color: '#188df0' }
    ])
    },
    emphasis: {
    itemStyle: {
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
    { offset: 0, color: '#2378f7' },
    { offset: 0.7, color: '#2378f7' },
    { offset: 1, color: '#83bff6' }
    ])
    }
    },
    markPoint: {
    symbolSize: 45,
    data: [
    {
    type: 'max',
    itemStyle: { color: '#425aef' },
    name: '最大值'
    },
    {
    type: 'min',
    itemStyle: { color: '#425aef' },
    name: '最小值'
    }
    ]
    },
    markLine: {
    itemStyle: { color: '#425aef' },
    data: [{ type: 'average', name: '平均值' }]
    }
    }
    };
    // 使用刚指定的配置项和数据显示图表。
    tagsChart.setOption(tagsOption);
    window.addEventListener("resize", () => {
    tagsChart.resize();
    });
    </script>`
    })
  2. 更改 [Blogroot]\themes\butterfly\layout\includes\page\tags.pug :

    1
    2
    #tag-echarts(style="height:320px")
    !=tag_ranking_bar({type:'tag',id:'tag-echarts',topNum:10,title:'Top 10 标签统计图',color:theme.theme_color.main,yAxisName:'文章篇数',seriesName:'标签统计'})

分类统计南丁格尔玫瑰图

  1. [Blogroot]\themes\butterfly\scripts\helpers\hexo_echarts 添加 categories_pic 工具类函数:

    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
    hexo.extend.helper.register('categories_pic', function (options) {
    const { id, title, seriesName } = options
    // id 必须指定
    if (!id) return
    const categoryArr = []
    hexo.locals.get('categories').map(function (category) {
    categoryArr.push({ name: category.name, value: category.length })
    })
    return `
    <script type="text/javascript" id="${id}">
    var themeMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
    var categoriesChart = echarts.init(document.getElementById("${id}"),themeMode);
    // 指定图表的配置项和数据
    var categoriesOption = {
    backgroundColor:'',
    title:{
    text:'${title}',
    x:'center'
    },
    tooltip:{
    formatter: "{a} <br/>{b} : {c} ({d}%)"
    },
    legend: {
    icon: "circle",
    top: 'bottom'
    },
    series: [
    {
    name: '${seriesName}',
    type: 'pie',
    radius: [40, 150],
    center: ['50%', '48%'],
    roseType: 'area',
    itemStyle: {
    borderRadius: 8
    },
    label: {
    formatter: "{b} : {c} ({d}%)"
    },
    data: ${JSON.stringify(categoryArr)}
    }
    ]
    };
    // 使用刚指定的配置项和数据显示图表。
    categoriesChart.setOption(categoriesOption);
    window.addEventListener("resize", () => {
    categoriesChart.resize();
    });
    </script>`
    })
  2. 更改 [Blogroot]\themes\butterfly\layout\includes\page\categories.pug :

    1
    2
    #categories-echarts(style="height:400px")
    !=categories_pic({id:'categories-echarts',title:'文章分类统计图',seriesName:'分类统计'})

文章发布统计面积图

  1. [Blogroot]\themes\butterfly\scripts\helpers\hexo_echarts 添加 posts_echarts 工具类函数:
    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
    hexo.extend.helper.register('posts_echarts', function (options) {
    let { title, id, seriesName } = options
    var moment = require('moment');
    const startDate = moment().subtract(1, 'years').startOf('month')
    const endDate = moment().endOf('month')

    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)
    }
    })
    let postsArr = [...monthMap.entries()]
    return `
    <script type="text/javascript" id="${id}">
    var themeMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
    var postsChart = echarts.init(document.getElementById("${id}"),themeMode);
    let postsOption = {
    color: ['#425aef'],
    title:{
    text:'${title}',
    x:'center'
    },
    tooltip:{
    trigger: 'axis',
    axisPointer: {
    type: 'shadow',
    shadowStyle:{
    color:'rgba(66,90,239,0.3)'
    }
    },
    },
    xAxis: {
    type: 'category',
    boundaryGap: false
    },
    yAxis: {
    name:'${seriesName}',
    axisLine: {
    show: true
    }
    },
    series: [
    {
    name:'${seriesName}',
    type: 'line',
    smooth:true,
    symbol: 'none',
    lineStyle: {
    color: '#425aef',
    width: 1
    },
    areaStyle: {
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
    offset: 0,
    color: '#425aef',
    }, {
    offset: 1,
    color: '#FFFFFF'
    }])
    },
    data: ${JSON.stringify(postsArr)}
    }
    ]
    };
    postsChart.setOption(postsOption);
    window.addEventListener("resize", () => {
    postsChart.resize();
    });
    </script>`
    })

添加博客统计菜单

  1. 执行 hexo new page echarts,新增菜单

    1
    hexo new page echarts
  2. [Blogroot]\_config.butterfly.yml\ 更改配置项:

    1
    2
    3
    menu:
    网站|| cyan-shouji:
    博客统计: /echarts/ || cyan-hezhao
  3. [Blogroot]\source\echarts\index.md 添加 type: 'echarts':

    1
    2
    3
    4
    5
    6
    ---
    title: 博客统计
    subtitle: 博客统计
    date: 2022-06-08 16:10:45
    type: 'echarts'
    ---
  4. [Blogroot]\themes\butterfly\layout\page.pug 大约 15 行处添加:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    case page.type
    when 'tags'
    include includes/page/tags.pug
    when 'link'
    include includes/page/flink.pug
    when 'categories'
    + include includes/page/categories.pug
    + when 'echarts'
    include includes/page/echarts.pug
    default
    include includes/page/default-page.pug
  5. 新增文件 [Blogroot]\themes\butterfly\layout\includes\page\echarts.pug :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    h1.page-title='博客统计'

    //- 文章发布统计图
    #posts-echart(style="height:320px")
    !=posts_echarts({title:'文章发布统计',id:'posts-echart',seriesName:'文章篇数'})

    //- 标签统计图表
    #tag-echarts(style="height:320px")
    !=tag_ranking_bar({type:'tag',id:'tag-echarts',topNum:10,title:'Top 10 标签统计图',color:theme.theme_color.main,yAxisName:'文章篇数',seriesName:'标签统计'})

    //- 分类统计图表
    #categories-echarts(style="height:400px")
    !=categories_pic({id:'categories-echarts',title:'文章分类统计图',seriesName:'分类统计'})
  6. 最后执行夺命三连 hexo cl ,hexo g,hexo s 即可看到效果。