GitHubにあるような芝(カレンダー)をサイトに設置する方法


[cal-heatmap](https://github.com/wa0x6e/cal-heatmap)は、GitLabにも使われています。ここでは、GitLabユーザーのカレンダー情報をJSONで取得し、サイトに設定する方法を紹介します。

![](https://raw.githubusercontent.com/mba-hack/images/master/cal-heatmap-sample.png)

```bash:
$ bower install cal-heatmap
```

```html:index.html
<script src="/bower_components/d3/d3.min.js" charset="utf-8"></script>
<script src="/bower_components/cal-heatmap/cal-heatmap.min.js"></script>
<link rel="stylesheet" href="/bower_components/cal-heatmap/cal-heatmap.css" />

<h3>GitLab Calendar Activities</h3>
<div id="cal-heatmap"></div>
<div id="example-heatmap"></div>
<script type="text/javascript">
var cal = new CalHeatMap();
cal.init({
	itemSelector: "#example-heatmap",
	domain: "month",
	data: "/json/datas.json",
	start: new Date(2016, 0),
	cellSize: 11,
	range: 9,
	previousSelector: "#example-b-PreviousDomain-selector",
	nextSelector: "#example-b-NextDomain-selector",

	legend: [1, 3, 5, 7],
	legendColors: {
		min: "#efefef",
		max: "steelblue",
		empty: "#efefef"
	},
	tooltip: true
});
</script>
```


ここで重要なのは`itemSelector, data`です。

表示する場所は`itemSelector:`でHTML要素を指定します。`data`ではユーザーのカレンダー情報ですね。

その他、例えば、`legend`で最小、最大のコミット数を指定します。次に、`legendColors`はコミット数と関連したカラーの設定ですね。

GitLabのカレンダー情報をJSONで取得します。

```bash:
$ curl -sL gitlab.com/u/$USER/calendar

# jq
$ export x=`curl -sL gitlab.com/u/$USER/calendar|grep '{"'`
$ echo ${x%,}|jq .
$ echo ${x%,}|jq . >> json/datas.json

# example
$ curl -sLO http://cal-heatmap.com/datas-years.json
$ cat !$:t | jq .

# preview
$ jekyll server
```

例えば、これをjQuery, Ajaxで書いてみます。GitLabから情報を取るために[jquery.xdomainajax.js](https://github.com/padolsey-archive/jquery.fn/blob/master/cross-domain-ajax/jquery.xdomainajax.js)を使います。

しかし、GitLabが提供する出力はHTMLですので、これを加工する必要があります。

必要なJSONは`<script>`内にあります。ここで、`xdomainajax.js`は`<script>`が空にされるため、一部コードを[書き換えて](https://github.com/padolsey-archive/jquery.fn/blob/master/cross-domain-ajax/jquery.xdomainajax.js#L62)使います。

```js:js/jquery.xdomainajax.js
// https://github.com/padolsey-archive/jquery.fn/blob/master/cross-domain-ajax/jquery.xdomainajax.js#L62
- .replace(/<script[^>]+?\/>|<script(.|\s)*?\/script>/gi, '')
+ //.replace(/<script[^>]+?\/>|<script(.|\s)*?\/script>/gi, '')
```

ちなみに、このjsファイルは手元において読み込んでください。http経由で読み込まないように。

```html:t/foo.html
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="../static/js/jquery.xdomainajax.js"></script> 
<script src="../static/bower_components/d3/d3.min.js" charset="utf-8"></script>
<script src="../static/bower_components/cal-heatmap/cal-heatmap.min.js"></script>
<link rel="stylesheet" href="../static/bower_components/cal-heatmap/cal-heatmap.css" />
<!--<script src="https://raw.githubusercontent.com/syui/jquery.fn/master/cross-domain-ajax/jquery.xdomainajax.js"></script>-->
<!--diff : https://github.com/padolsey-archive/jquery.fn/blob/master/cross-domain-ajax/jquery.xdomainajax.js#L62 -->
<h3>Calendar Activities</h3>
<div id="cal-heatmap"></div>
<div id="example-heatmap"></div>

<script>
jQuery(function ($) {
	var json;
    	$.ajax({
        type: 'GET',
        url: 'https://gitlab.com/u/syui/calendar',
        dataType: 'html',
    	async: false,
    	cache: false,
    	success: function(data) {
		var content = $(data.responseText).find('script').html();
		var tmp = content.replace("<![CDATA[", "").replace("]]>", "");
		var s = tmp.indexOf( "{" );
		var e = tmp.indexOf( "}" );
		json = tmp.substring( s, e+1 );
		$('#gitlab-calendar-activities').text(json);
    	}
	});
	setTimeout( $('#example-heatmap').each(function () {
	//setTimeout( function() {
	    if( json != null ){
		var obj = $.parseJSON(json);
  		var now = new Date();
  		new CalHeatMap().init({
  		  data: obj,
  		  domain: 'month',
  		  domainLabelFormat: '%Y-%m',
  		  itemSelector: '#example-heatmap',
  		  legend: [1, 3, 5, 7],
  		  legendColors: {
  		  	min: "#efefef",
  		  	max: "steelblue",
  		  	empty: "#efefef"
  		  },
        	  tooltip: true,
  		  start: new Date(now.getFullYear(), now.getMonth() - 9)
  		});
	    } else {
	        setTimeout( arguments.callee, 100 );
	    }
	}));
});
</script>

<div id="gitlab-calendar-activities" style="display:none;"></div>
```

```bash:
# 一応、Hugoのディレクトリ構造を想定
$ tree -L 2 -d .
	- t/foo.html
	- static/
		- bower_compotnent/{d3,cal-heatmap}
		- js/jquery.xdomainajax.js
$ open t/foo.html
```

これをブラウザで開き、Consoleからログを確認しながら修正していくとよいでしょう。`console.log(json)`

うまくいくと最終的に取れるJSONが`#gitlab-calendar-activities`に表示されるはずです。ただし、`display:none`しているので、表示したい場合は消してください。別にこれを使っても使わなくてもどっちでも良いです。使わない場合は当該箇所をコードから削除して問題ありません。ここではグローバル変数を使ってますのでカレンダーへの影響はないです。

JSONはこのような感じで取得し、カレンダーに表示してもよいですが、サイトのレスポンス(遅延)が気になります。

したがって、おすすめは`data: "/json/datas.json"`として、1日1回サイト上においたファイルをサーバーやボットなどを使って自動更新することですかね。