|
| 1 | +'use strict'; |
| 2 | + |
| 3 | +/** |
| 4 | + * サイトの全投稿を集計し、時間軸ごとのカテゴリ別投稿データを生成する |
| 5 | + * - 2018年以前は年ごと、2019年以降は四半期ごと |
| 6 | + * @returns {object} { quarters: string[], series: object[], categories: string[] } |
| 7 | + */ |
| 8 | +function getQuarterlyCategoryData() { |
| 9 | + const posts = this.site.posts.sort('date', 1); // 日付順にソート |
| 10 | + if (!posts.length) { |
| 11 | + return { quarters: [], series: [], categories: [] }; |
| 12 | + } |
| 13 | + |
| 14 | + const dataByTimeBucket = new Map(); |
| 15 | + |
| 16 | + // 1. 全投稿をループして、時間軸ごとにカテゴリ別投稿数を集計 |
| 17 | + posts.forEach(post => { |
| 18 | + const year = post.date.year(); |
| 19 | + let timeKey; |
| 20 | + |
| 21 | + if (year >= 2019) { |
| 22 | + // 2019年以降は四半期ごと |
| 23 | + const quarter = Math.floor(post.date.month() / 3) + 1; |
| 24 | + timeKey = `${year}-Q${quarter}`; |
| 25 | + } else { |
| 26 | + // 2018年以前は年ごと |
| 27 | + timeKey = year.toString(); |
| 28 | + } |
| 29 | + |
| 30 | + if (!dataByTimeBucket.has(timeKey)) { |
| 31 | + dataByTimeBucket.set(timeKey, new Map()); |
| 32 | + } |
| 33 | + |
| 34 | + const bucketData = dataByTimeBucket.get(timeKey); |
| 35 | + const postCategories = post.categories.map(cat => cat.name); |
| 36 | + if (!postCategories.length) return; |
| 37 | + |
| 38 | + postCategories.forEach(catName => { |
| 39 | + const currentCount = bucketData.get(catName) || 0; |
| 40 | + bucketData.set(catName, currentCount + 1); |
| 41 | + }); |
| 42 | + }); |
| 43 | + |
| 44 | + // 2. サイトの全カテゴリを取得し、「合計記事数」で降順にソートする |
| 45 | + const sortedCategoryObjects = this.site.categories.toArray().sort((a, b) => b.length - a.length); |
| 46 | + const sortedCategoryNames = sortedCategoryObjects.map(cat => cat.name); |
| 47 | + |
| 48 | + // 3. X軸のラベル(時間軸)を生成し、ソートする |
| 49 | + const sortedTimeKeys = Array.from(dataByTimeBucket.keys()).sort(); |
| 50 | + |
| 51 | + // 4. EChartsのseries形式にデータを整形 |
| 52 | + const series = sortedCategoryObjects.map(category => { |
| 53 | + const catName = category.name; |
| 54 | + const data = sortedTimeKeys.map(timeKey => { |
| 55 | + const bucketData = dataByTimeBucket.get(timeKey); |
| 56 | + return bucketData.get(catName) || 0; // その期間に投稿がなければ0 |
| 57 | + }); |
| 58 | + |
| 59 | + return { |
| 60 | + name: catName, |
| 61 | + type: 'line', |
| 62 | + stack: 'Total', |
| 63 | + areaStyle: {}, |
| 64 | + emphasis: { |
| 65 | + focus: 'series' |
| 66 | + }, |
| 67 | + data: data |
| 68 | + }; |
| 69 | + }); |
| 70 | + |
| 71 | + return { |
| 72 | + quarters: sortedTimeKeys, // キー名はEJS側と合わせるため'quarters'のまま |
| 73 | + series: series, |
| 74 | + categories: sortedCategoryNames |
| 75 | + }; |
| 76 | +} |
| 77 | + |
| 78 | +// ヘルパーとして登録 |
| 79 | +hexo.extend.helper.register('get_quarterly_category_data', getQuarterlyCategoryData); |
0 commit comments