Skip to content

Commit b69b5e8

Browse files
committed
Add selector for heatmap
1 parent 729f4be commit b69b5e8

File tree

3 files changed

+155
-142
lines changed

3 files changed

+155
-142
lines changed

content/en/about_me.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ lastmod = 2022-02-23T17:23:37+08:00
55
draft = false
66
+++
77

8-
{{< heatmap title_text="Article Calendar" >}}
8+
{{< heatmap title_text="Article Activity" language="EN">}}
99

1010
## About me {#about-me}
1111

content/zh/about_me_zh.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ draft = false
66
toc = true
77
+++
88

9-
{{< heatmap title_text="文章日历" >}}
9+
{{< heatmap title_text="文章日历" language="ZH" >}}
1010

1111
## <span class="section-num">0x0</span> 自我认知 {#自我认知}
1212
一个努力但平凡普通的人,希望做个有趣的人, work hard and be nice to people.

layouts/shortcodes/heatmap.html

Lines changed: 153 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,151 +1,164 @@
1-
<!-- credit for https://blog.douchi.space/hugo-blog-heatmap/ -->
2-
<div
3-
id="heatmap"
1+
<div>
2+
<div style="display: flex; justify-content: center; align-items: center">
3+
<p style="margin-right: 15px; margin-bottom: 0; color: #333; padding: 8px">
4+
{{ .Get "title_text" }}
5+
</p>
6+
<select
7+
id="yearSelector"
8+
style="
9+
padding: 8px 12px;
10+
border: 1px solid #ccc;
11+
border-radius: 5px;
12+
background-color: #fff;
13+
cursor: pointer;
14+
transition: border-color 0.3s ease, box-shadow 0.3s ease;
15+
"
16+
>
17+
<!-- Years will be dynamically added here -->
18+
</select>
19+
</div>
20+
<div
21+
id="heatmap"
422
style="
5-
display: block;
6-
height: 150px;
7-
width: 75%;
8-
padding: 2px;
9-
text-align: center;"
10-
></div>
23+
display: block;
24+
height: 150px;
25+
width: 75%;
26+
padding: 2px;
27+
margin: 0 auto;
28+
text-align: center;
29+
"
30+
></div>
31+
</div>
1132
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
1233
<script type="text/javascript">
13-
var chartDom = document.getElementById('heatmap');
14-
var myChart = echarts.init(chartDom);
15-
window.onresize = function() {
16-
myChart.resize();
17-
};
18-
var option;
34+
var chartDom = document.getElementById('heatmap');
35+
var myChart = echarts.init(chartDom);
36+
var yearSelector = document.getElementById('yearSelector');
37+
window.onresize = function() {
38+
myChart.resize();
39+
};
40+
var option;
41+
var postsByDate = new Map();
42+
var years = new Set();
1943

20-
// get date range by number of months
21-
function getDateRange(months){
22-
var startDate = new Date();
23-
var mill = startDate.setMonth((startDate.getMonth() - months));
24-
var endDate = +new Date();
25-
startDate = +new Date(mill);
44+
{{ range ((where .Site.RegularPages "Type" "post")) }}
45+
var date = {{ .Date.Format "2006-01-02" }};
46+
var year = {{ .Date.Format "2006" }};
47+
years.add(year);
48+
var postObj = new Map();
49+
postObj.set("title", {{ .Title }});
50+
postObj.set("link", {{ .RelPermalink }});
51+
var wordCount = {{ .WordCount }};
52+
var data = postsByDate.get(date);
53+
if (data === undefined) {
54+
data = new Map();
55+
data.set("posts", []);
56+
data.set("totalWordCount", 0);
57+
}
58+
var posts = data.get("posts");
59+
posts.push(postObj);
60+
var totalWordCount = data.get("totalWordCount");
61+
totalWordCount += wordCount;
62+
data.set("totalWordCount", totalWordCount);
63+
postsByDate.set(date, data);
64+
{{- end -}}
2665

27-
endDate = echarts.format.formatTime('yyyy-MM-dd', endDate);
28-
startDate = echarts.format.formatTime('yyyy-MM-dd', startDate);
66+
// Populate year selector
67+
years = Array.from(years).sort().reverse();
68+
years.forEach(year => {
69+
var option = document.createElement('option');
70+
option.value = year;
71+
option.text = year;
72+
yearSelector.appendChild(option);
73+
});
2974

30-
var dateRange = [];
31-
dateRange.push([
32-
startDate,
33-
endDate
34-
]);
35-
return dateRange
36-
};
75+
function getHeatmapData(year) {
76+
var heatmapData = [];
77+
for (const [date, data] of postsByDate.entries()) {
78+
if (date.startsWith(year)) {
79+
heatmapData.push([date, data.get("totalWordCount")]);
80+
}
81+
}
82+
return heatmapData;
83+
}
3784

38-
// get number of months by window size
39-
function getMonthCount(){
40-
const windowWidth = window.innerWidth;
41-
if (windowWidth >= 600) {
42-
return 12;
43-
}
44-
if (windowWidth >= 400) {
45-
return 9;
46-
}
47-
return 6;
48-
}
85+
function updateHeatmap(year) {
86+
option.calendar.range = year;
87+
option.series.data = getHeatmapData(year);
88+
myChart.setOption(option);
89+
}
4990

50-
var postsByDate = new Map();
51-
{{ range ((where .Site.RegularPages "Type" "post")) }}
91+
yearSelector.addEventListener('change', function() {
92+
updateHeatmap(this.value);
93+
});
5294

53-
var date = {{ .Date.Format "2006-01-02" }};
54-
var postObj = new Map();
55-
postObj.set("title", {{ .Title }});
56-
postObj.set("link", {{ .RelPermalink }});
57-
var wordCount = {{ .WordCount }};
95+
option = {
96+
title: {
97+
show: false,
98+
},
99+
legend: {
100+
show: false,
101+
},
102+
visualMap: {
103+
show: false,
104+
min: 0,
105+
max: 10000,
106+
type: 'piecewise',
107+
showLable: false,
108+
orient: 'horizontal',
109+
left: 'center',
110+
top: 0,
111+
itemGap: 10,
112+
inRange: {
113+
color: ['#c6e48b', '#7bc96f', '#239a3b', '#196127'],
114+
},
115+
},
116+
calendar: {
117+
top: 30,
118+
left: 30,
119+
right: 30,
120+
cellSize: ['auto', 'auto'],
121+
range: years[0],
122+
itemStyle: {
123+
color: '#fff',
124+
borderWidth: 0.5,
125+
borderColor: '#eee',
126+
},
127+
yearLabel: { show: false },
128+
dayLabel: {
129+
firstDay: 1,
130+
nameMap: {{ .Get "language" }}
131+
},
132+
monthLabel: {
133+
nameMap: {{ .Get "language" }}
134+
},
135+
splitLine: {
136+
show: false,
137+
},
138+
},
139+
tooltip: {
140+
hideDelay: 1000,
141+
enterable: true,
142+
formatter: function (params) {
143+
const date = params.data[0];
144+
const posts = postsByDate.get(date).get("posts");
145+
var content = `${date}`;
146+
for (const [i, post] of posts.entries()) {
147+
content += "<br>";
148+
var link = post.get("link");
149+
var title = post.get("title");
150+
content += `<a href="${link}" target="_blank">${title}</a>`
151+
}
152+
return content;
153+
}
154+
},
155+
series: {
156+
type: 'heatmap',
157+
coordinateSystem: 'calendar',
158+
calendarIndex: 0,
159+
data: getHeatmapData(years[0])
160+
}
161+
};
58162

59-
var data = postsByDate.get(date);
60-
if (data === undefined) {
61-
data = new Map();
62-
data.set("posts", []);
63-
data.set("totalWordCount", 0);
64-
}
65-
var posts = data.get("posts");
66-
posts.push(postObj);
67-
var totalWordCount = data.get("totalWordCount");
68-
totalWordCount += wordCount;
69-
data.set("totalWordCount", totalWordCount);
70-
postsByDate.set(date, data);
71-
{{- end -}}
72-
73-
var heatmapData = [];
74-
for (const [date, data] of postsByDate.entries()) {
75-
heatmapData.push([date, data.get("totalWordCount")]);
76-
}
77-
78-
option = {
79-
title: {
80-
show: true,
81-
top: 0,
82-
left: 'center',
83-
text: '{{ .Get "title_text" }}'
84-
},
85-
legend: {
86-
show: false,
87-
},
88-
visualMap: {
89-
show: false,
90-
min: 0,
91-
max: 10000,
92-
type: 'piecewise',
93-
showLable: false,
94-
orient: 'horizontal',
95-
left: 'center',
96-
top: 0,
97-
itemGap: 10,
98-
inRange: {
99-
color: ['#c6e48b', '#7bc96f', '#239a3b', '#196127'],
100-
},
101-
},
102-
calendar: {
103-
top: 50,
104-
left: 30,
105-
right: 30,
106-
cellSize: ['auto', 'auto'],
107-
range: getDateRange(getMonthCount()),
108-
itemStyle: {
109-
color: '#fff',
110-
borderWidth: 0.5,
111-
borderColor: '#eee',
112-
},
113-
yearLabel: {
114-
show: false,
115-
},
116-
dayLabel: {
117-
align: 'center',
118-
nameMap: 'ZH',
119-
},
120-
monthLabel: {
121-
nameMap: 'EN',
122-
},
123-
splitLine: {
124-
show: false,
125-
},
126-
},
127-
tooltip: {
128-
hideDelay: 1000,
129-
enterable: true,
130-
formatter: function(params) {
131-
const date = params.data[0];
132-
const posts = postsByDate.get(date).get("posts");
133-
var content = `${date}`;
134-
for (const [i, post] of posts.entries()) {
135-
content += "<br>";
136-
var link = post.get("link");
137-
var title = post.get("title");
138-
content += `<a href="${link}" target="_blank">${title}</a>`
139-
}
140-
return content;
141-
}
142-
143-
},
144-
series: {
145-
type: 'heatmap',
146-
coordinateSystem: 'calendar',
147-
data: heatmapData
148-
}
149-
};
150-
option && myChart.setOption(option);
163+
option && myChart.setOption(option);
151164
</script>

0 commit comments

Comments
 (0)