Бобылев Артём
Визуализация статистики гитхаб: github contributions graph
Недавно столкнулся с задачей самостоятельной визуализации статистики github-пользователя, чтобы «как на github».
В этой статье опишу своë решение.
Как получить данные
Через поиск «github contributions data», находится масса готовых решений. Например, github-contributions-api.
С помощью GET-запроса по адресу https://github-contributions-api.jogruber.de/v4/GITHUB_USERNAME можно получить статистику пользователя в следующем виде:
{
"total": {
"2016": 249,
"2017": 785
},
"contributions": [
{
"date": "2016-01-01",
"count": 1,
"level": 1
},
{
"date": "2016-01-02",
"count": 0,
"level": 0
},
...
]
}
Есть возможность выбрать отдельный год:
https://github-contributions-api.jogruber.de/v4/GITHUB_USERNAME?y=2020
Как визуализировать
Будем использовать библиотеку cal-heatmap.
В <head>
вставим:
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://unpkg.com/cal-heatmap/dist/cal-heatmap.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/cal-heatmap/dist/cal-heatmap.css">
Для отображения тепловой карты необходим элемент в <body>
, например:
<div id="cal-heatmap"></div>
Подготовим пользовательские данные:
async function fetchGithubData() {
const response = await fetch('https://github-contributions-api.jogruber.de/v4/karpathy?y=last');
const user_data = await response.json();
return user_data;
}
Для раскраски тепловой карты значения разбиваются на группы с соответствующим цветом.
Этого можно добиться, используя значения level
из ответа api, либо написав функцию разбиения:
function getClassBounds(data, nClasses) {
let minValue = Math.min(...data);
let maxValue = Math.max(...data);
let classWidth = (maxValue - minValue) / nClasses;
let classBounds = [minValue];
for (let i = 1; i < nClasses; i++) {
classBounds[i] = Math.ceil(minValue + (i * classWidth));
}
return classBounds;
}
На github используются 5 цветов ['rgb(235,237,240)', 'rgb(172,231,174)', 'rgb(105,193,110)', 'rgb(83,159,87)', 'rgb(56,108,62)']
, первый из которых соответствует нулевому числу contributions, поэтому разбивка пойдет на 4 группы:
fetchGithubData().then(user_data => {
user_data = user_data.contributions;
let values = [];
user_data.forEach( obj => obj["count"] != 0 ? values.push(obj["count"]):null);
let domain = getClassBounds(values, 4);
let first_date = user_data[0]["date"];
var cal = new CalHeatmap();
cal.paint({
itemSelector: "#cal-heatmap",
domain: {
type: 'month',
gutter: 4,
label: { text: '', textAlign: 'start', position: 'top' },
},
subDomain: { type: 'ghDay', radius: 2, width: 11, height: 11, gutter: 4 },
date: { start: new Date(first_date) },
range: 12,
data: {
source: user_data,
x: (datum) => +new Date(datum["date"]),
y: (datum) => +datum["count"]
},
scale: {
color: {
type: 'threshold',
range: ['rgb(235,237,240)', 'rgb(172,231,174)', 'rgb(105,193,110)', 'rgb(83,159,87)', 'rgb(56,108,62)'],
domain: domain,
},
},
},
);
});
Итоговый результат:
Именно в таком виде я использовал статистику github contributions для своего проекта gitcloths. При желании, можно добавить дни и месяцы.
Пример того, как это сделать можно найти на сайте cal-heatmap. Не забудьте дополнить зависимости в <head>
, иначе подписи не отобразятся:
<script src="https://unpkg.com/cal-heatmap/dist/plugins/CalendarLabel.min.js"></script>
И отобразить карту следующим образом:
var cal = new CalHeatmap();
cal.paint({
itemSelector: "#cal-heatmap",
domain: {
type: 'month',
gutter: 4,
label: { text: 'MMM', textAlign: 'start', position: 'top' },
},
subDomain: { type: 'ghDay', radius: 2, width: 11, height: 11, gutter: 4 },
date: { start: new Date(first_date) },
range: 12,
data: {
source: user_data,
x: (datum) => +new Date(datum["date"]),
y: (datum) => +datum["count"]
},
scale: {
color: {
type: 'threshold',
range: ['rgb(235,237,240)', 'rgb(172,231,174)', 'rgb(105,193,110)', 'rgb(83,159,87)', 'rgb(56,108,62)'],
domain: domain,
},
},
},
[
[
CalendarLabel,
{
width: 30,
textAlign: 'start',
text: () => dayjs.weekdaysShort().map((d, i) => (i % 2 == 0 ? '' : d)),
padding: [25, 0, 0, 0],
},
],
]
);
Итоговая карта – svg элемент. Для gitcloths мне нужно было именно это.
Тем не менее существует масса гораздо более простых решений. Например, вы можете внедрить github статистику на сайт, просто добавив img элемент с соответствующим src, используя ghchart.rshah.org.