Fullcalendarのかゆいところに手が届くオプションの設定方法

#概要
fullcalendarのオプションの動的、トリッキーな設定方法。
日本語の情報が無さすぎて書きたくなった。
$(document).readyなどは省略している

#使用環境
Rails v4.1.0
fullcalendar v2.3.0
jquery-rails v3.1.2

##今日の日付からカレンダーを表示する
```js:calednar.js
firstDay:"today"
```
月曜日、日曜日などを０、１などの数字で設定すればその曜日から表示されるが
文字列の"today"を入れると常に"今日の日付"から表示される。あらビックリ
もちろんユーザーの設定などで動的に変更も可能。
その場合は事前に変数に入れてfirstDayに変数を設定すれば大丈夫。

##ページ読み込み時に現在時刻を真ん中に表示する
scrollTimeで時間を"09:00"などで指定すればその時間をtopにして表示できるが
９時より前や夜の時間帯は予定を確認するのに毎回スクロールが必要。
この動作はストレスにしかならないので省く。

```js:calednar.js
    var current_day = new Date();
    var current_hours = current_day.getHours() - 5;
    var current_minutes = current_day.getMinutes();
    var first_scroll_time = current_hours + ":" + current_minutes + ":00"
    var calendar =  $('#calendar').fullCalendar({
                        scrollTime: first_scroll_time
                    });
```

##３０分〜３０分を1時間(または以降)単位でselectしたい

```js
slotDuration: '00:30:00', //表示する時間軸の細かさ
snapDuration: '01:00:00', // 選択する時間間隔
```
通常予定は３０分単位になってて、選択できるのは１時間がデフォルトがほとんど。
しかし上記の設定だと12:00〜13:00な選択できるが12:30:13:30などの中途半端な
時間帯が選択できない。
これってカレンダーとして致命傷。
こんなのオプションでなんとかなりそうに感じるが**「ならない」**
じゃあsnapDurationをslotと同じ30分にして「30分足したイベントをrenderする」
方法はどうか？
これは上手くいくが**「selectHelper」**とうまく噛み合わないので一瞬フリーズする。
他のselectConstraintなどオプションでも30分ずれるからダメ。
これはfullcalendar.jsの大元のファイルをいじるしかない。
確かこれはRailsでGemのfullcalendar−railsなどを使っている場合は不可なはず。
僕は最新のfullcalendar.jsのzipファイルをダウンロードしてvendor/assets以下に
置きました。
そのfullcalendar.jsのここの二カ所をいじるだけでOK！！！

```js:fullcaelendar.js
//5860行目くらい？
computeRowCoords: function() {
		var originTop = this.el.offset().top;
		var items = [];
		var i;
		var item;
                  //ここ↓
		for (i = 0; i < 48; i++) {//デフォルトのslotDurationが30分なのでcolを48個に固定すれば常に30分単位で選択できるようにはなる。ここが１時間だと23個になって30分〜30分が選択できなくなる
			item = {
				top: originTop + this.computeTimeTop(this.computeSnapTime(i))//ここがsnapDurattionの時間を足して計算している部分。１時間だと一つのRowの幅が30分の倍になり結局30分〜30分が選べないので下記で修正する
			};
			if (i > 0) {
				items[i - 1].bottom = item.top;
			}
			items.push(item);
		}
		item.bottom = item.top + this.computeTimeTop(this.computeSnapTime(i));
		return items;
	},
```

```js:fullcalendar.js
//5830行目くらい？
computeSnapTime: function(row) {
	return moment.duration(this.minTime + this.snapDuration * row);
	//ここで一つあたりの予定のtop,bottomの幅を作っているので全て30分単位に合わせる
	var select_harf_minutes = this.snapDuration / 1800000;
//slotが３０分単位なのでミリ秒の1800000で割って30分単位に変換してる。15分単位なら900000で割ればOKかと。
		return moment.duration(this.minTime + this.snapDuration / select_harf_minutes * row);
 	},
```
下のは編集はしないが動きを理解するのに役立った関数

```js:fullcalendar.js
getCell: function(x, y) {
		var rowCoords = this.rowCoords;//全てのrowのtop値、bottom値を取得している
		var rowCnt = rowCoords.length;//rowの数を取得している。通常は３０分選択で48個
		var colCoords = this.colCoords;
		var colCnt = colCoords.length;
		var hitRow = null;
		var hitCol = null;
		var i, coords;
		var cell;
		if (this.inBounds(x, y)) {
			//ここでy座標がtop,bottomの範囲内に収まっている要素をhitRowに代入している。上記二カ所を変更しないとrowCntが23個になってダメになり、coords.top,coords.bottomがそれぞれ30分単位の倍のピクセル数になりダメ
			for (i = 0; i < rowCnt; i++) {
				coords = rowCoords[i];
				if (y >= coords.top && y < coords.bottom) {
					hitRow = i;
					break;
				}
			}
			for (i = 0; i < colCnt; i++) {
				coords = colCoords[i];
				if (x >= coords.left && x < coords.right) {
					hitCol = i;
					break;
				}
			}
			if (hitRow !== null && hitCol !== null) {

				cell = this.grid.getCell(hitRow, hitCol); // expected to return a fresh object we can modify
				cell.grid = this.grid; // for CellDragListener's isCellsEqual. dragging between grids

				// make the coordinates available on the cell object
				$.extend(cell, rowCoords[hitRow], colCoords[hitCol]);

				return cell;
			}
		}

		return null;
	},
```
これでOK！ここを無理矢理30分に合わせているが取得したx,y軸に対するrowの幅を30分単位の幅に強制しただけなので他には影響しない。
ちゃんと12:30〜13:30でselectできて、なおかつ他のオプションがちゃんと動くことが
確認できました。