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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
<div id="heatmap" style="
max-width: 1900px;
height: 180px;
padding: 2px;
text-align: center;
"
></div>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.3.0/dist/echarts.min.js"></script>
<script type="text/javascript">
var chartDom = document.getElementById('heatmap');
var myChart = echarts.init(chartDom);
window.onresize = function() {
myChart.resize();
};
var option;
// echart heatmap data seems to only support two elements tuple
// it doesn't render when each item has 3 value
// it also only pass first 2 elements when reading event param
// so here we build a map to store additional metadata like link and title
// map format {date: [{wordcount, link, title}]}
// for more information see https://blog.douchi.space/hugo-blog-heatmap
var dataMap = new Map();
{{ range ((where .Site.RegularPages "Type" "post")) }}
var key = {{ .Date.Format "2006-01-02" }};
var value = dataMap.get(key);
var wordCount = {{ .WordCount }};
var link = {{ .RelPermalink}};
var title = {{ .Title }};
// multiple posts in same day
if (value == null) {
dataMap.set(key, [{wordCount, link, title}]);
} else {
value.push({wordCount, link, title});
}
{{- end -}}
var data = [];
// sum up the word count
for (const [key, value] of dataMap.entries()) {
var sum = 0;
for (const v of value) {
sum += v.wordCount;
}
data.push([key, (sum / 1000).toFixed(1)]);
}
var startDate = new Date();
var year_Mill = startDate.setFullYear((startDate.getFullYear() - 1));
var startDate = +new Date(year_Mill);
var endDate = +new Date();
var dayTime = 3600 * 24 * 1000;
startDate = echarts.format.formatTime('yyyy-MM-dd', startDate);
endDate = echarts.format.formatTime('yyyy-MM-dd', endDate);
// change date range according to months we want to render
function heatmap_width(months){
var startDate = new Date();
var mill = startDate.setMonth((startDate.getMonth() - months));
var endDate = +new Date();
startDate = +new Date(mill);
endDate = echarts.format.formatTime('yyyy-MM-dd', endDate);
startDate = echarts.format.formatTime('yyyy-MM-dd', startDate);
var showmonth = [];
showmonth.push([
startDate,
endDate
]);
return showmonth
};
function getRangeArr() {
const windowWidth = window.innerWidth;
if (windowWidth >= 600) {
return heatmap_width(12);
} else if (windowWidth >= 400) {
return heatmap_width(9);
} else {
return heatmap_width(6);
}
}
option = {
title: {
top: 0,
left: 'center',
text: '热力图'
},
tooltip: {
hideDelay: 1000,
enterable: true,
formatter: function (p) {
const date = p.data[0];
const posts = dataMap.get(date);
var content = `${date}`;
for (const [i, post] of posts.entries()) {
content += "<br>";
var link = post.link;
var title = post.title;
var wordCount = (post.wordCount / 1000).toFixed(1);
content += `<a href="${link}" target="_blank">${title} | ${wordCount} k</a>`
}
return content;
}
},
visualMap: {
min: 0,
max: 10,
type: 'piecewise',
orient: 'horizontal',
left: 'center',
top: 30,
inRange: {
// [floor color, ceiling color]
color: ['#7aa8744c', '#7AA874' ]
},
splitNumber: 4,
text: ['千字', ''],
showLabel: true,
itemGap: 20,
},
calendar: {
top: 80,
left: 20,
right: 4,
cellSize: ['auto', 13],
range: getRangeArr(),
itemStyle: {
color: '#F1F1F1',
borderWidth: 1.5,
borderColor: '#fff',
},
yearLabel: { show: false },
// the splitline between months. set to transparent for now.
splitLine: {
lineStyle: {
color: 'rgba(0, 0, 0, 0.0)',
// shadowColor: 'rgba(0, 0, 0, 0.5)',
// shadowBlur: 5,
// width: 0.5,
// type: 'dashed',
}
}
},
series: {
type: 'heatmap',
coordinateSystem: 'calendar',
data: data,
}
};
myChart.setOption(option);
myChart.on('click', function(params) {
if (params.componentType === 'series') {
// open the first post on the day
const post = dataMap.get(params.data[0])[0];
const link = window.location.origin + post.link;
window.open(link, '_blank').focus();
}
});
</script>
|