FullCalendarをカスタマイズ！

Laravelでカレンダーをモーダルとして表示させます。
その時保存済みのイベントを呼び出してカレンダーの該当する日付に表示させましょう。

では早速やっていきましょう！

[FullCalendar](https://fullcalendar.io/)というオープンソースのjavascriptライブラリを使用していきます！

まず初めに完成形を載せます
![completed](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/506d0289-045c-7c79-676f-b94165d6668b.png)


--------------

1.DBを用意して、ルーティングなど設定しておきます
![カレンダーテーブル](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/4d6fa43f-d0e7-76d8-6222-769c60abda66.png)
```
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\EventCalendarController; //使用するコントローラー

// http://127.0.0.1:8000/calendarにアクセスしたときの画面
Route::get('/calendar', function () {
              // ↓calendar.blade.phpとします
    return view('calendar');
});

// データの取得は　　　　　この↓コントローラーの　　　　　　　　　この↓メソッドから
Route::get('/events', [EventCalendarController::class, 'getEvents']);


```
----------------

2.今回はcalendar.blade.phpにjsまで全て書いてしまいます
モーダルの書き方はbootstrapそのままです（https://getbootstrap.jp/docs/5.3/components/modal/）
```php:calendar.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>カレンダーデモ</title>

    <!-- 必要なCSSをインポートします -->
    <link href="https://cdn.jsdelivr.net/npm/fullcalendar@5.10.0/main.min.css" rel="stylesheet" />

    <!-- Bootstrap（モーダル用）-->
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">

    <!-- jQueryとFullCalendarのためのJSをインポートします -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.10.0/main.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js"></script>
</head>
<body>

    <!-- カレンダー（モーダル）を開くためのボタン -->
    <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#calendarModal">
        カレンダーを表示
    </button>

    <!-- カレンダー本体 -->
    <div class="modal fade" id="calendarModal" tabindex="-1" aria-labelledby="calendarModalLabel" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="calendarModalLabel">カレンダーのタイトル</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    <!-- ↓カレンダー表示に必要なのはこれだけ！ -->
                    <div id="calendar"></div>
                </div>
            </div>
        </div>
    </div>

    <script>
        $(document).ready(function() {
        // カレンダーが表示された時にFullCalendarを初期化
        $('#calendarModal').on('shown.bs.modal', function () {
            var calendarEl = document.getElementById('calendar');
            var calendar = new FullCalendar.Calendar(calendarEl, {
                headerToolbar: {
                    left: 'prev,',
                    center: 'title',
                    right: 'next',
                },
                height: 'auto', // カレンダーの高さを自動調節してくれます
                events: function(info, successCallback, failureCallback) {
                    // バックエンドからイベントデータを取得
                    $.ajax({
                        url: '/events',  // web.phpで指定したルートの呼び出し
                        type: 'GET',
                        success: function(response) {
                            const formattedEvents = response.map(event => ({
                                title: event.events, // eventsの文字列をタイトルとして使用
                                start: event.date, // 日付を開始日として使用
                            }));
                            successCallback(formattedEvents);  // FullCalendarにイベントデータを渡す
                        },
                        error: function() {
                            failureCallback('イベントの読み込みに失敗しました');
                        }
                    });
                }
            });
                // カレンダーを描画
                calendar.render();
            });
        });
    </script>

</body>
</html>

```

----------------

3.ボタン押下→カレンダーをイベント内容とともに表示
![カレンダー表示ボタン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/ec9b0496-9fbf-629e-df89-5bf0c33dab86.png)
↓
![カレンダー内容](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/87cffbf5-cef1-5f9d-7ab3-9fa30e1c6a57.png)
テーブルに保存されている内容がカレンダーにイベントが表示されていることを確認します


-----------

ここで気になるのはもっと見やすく、使いやすくカスタマイズできるのか？でしょう

4.ということでカスタマイズしていきます   

<b>・翌月、前月のボタンのテキストは変えられますか？
buttonTextで設定ができます</b>
``
buttonText: {
                    prev: '次！',
                    next: '前！',
                },
``
![buttonTextの設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/1f42a8cb-68a6-e555-e0cb-1b91e6bbeed5.png)


<b>・表示するカレンダーの範囲を制限したいです
validRangeで設定できます(公式ドキュメントでうまくいかなかったのでいじっています)</b>
```
validRange: function(nowDate){
               var startDate = new Date(nowDate);
               startDate.setDate(1); // 開始月の1日
               var endDate = new Date(startDate);
               endDate.setMonth(endDate.getMonth() + 4); // ３ヶ月後まで
               endDate.setDate(0); // 月末に設定
               return {
                        start: startDate,
                        end: endDate,
               };
},
```
前月が選択不可、設定した月数以降選択不可
![startDate](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/137c8205-cced-40ce-5110-8003ff06642d.png)
![endDate](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/1cd0cad5-0252-2b1d-7a82-e49bf54bea82.png)


<b>・特定の文字だけ太くしたいのですが・・・
eventContentで設定ができます</b>
テーブルにtext_boldカラムを追加しました
![bold](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/f9cf1ef7-634a-6bde-1825-4f5ff30bddff.png)

console.log(reponse)でtext_boldも返ってきていることが確認できました
![console.log](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/ecf2e523-2fea-b975-272c-10d0191dfcea.png)


1なら太字にするという設定にしましょう。
一番初めに載せたコードのajax部分のformattedEventsにextendedPropsを追加します
```
const formattedEvents = response.map(event => ({
                                title: event.events, // eventsの文字列をタイトルとして使用
                                start: event.date, // 日付を開始日として使用
                                extendedProps: {
                                    action: event.text_bold, // 太字にするため
                                }
                            }));
```

```
eventContent: function(arg) {
                    const {action} = arg.event.extendedProps; // text_bold
                    const color = action === '1' ? 'black' : '';
                    const textBold = action === '1' ? 'bold' : '';

                    let styles = `<div style="color: ${color}; font-weight: ${textBold};"> ${arg.event.title} </div>`
                    return {
                        html: styles
                    };
                }
```
![text_bold](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/96067b6d-a2a5-7017-168a-704db69512ce.png)


・カレンダーの表示週を自動で調節してもらいたい
``
fixedWeekCount: false
``
これを入れるだけです。５週６週など調節してくれます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/a3e89552-a8a7-c705-177a-16d7993e986c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/4c9fdf68-e99e-c6ae-536b-c72d7878473b.png)

<b>・土日の文字の色を変えたい
cssで設定可能です</b>
```
        th.fc-day-sat .fc-col-header-cell-cushion {
            color: blue;
        }
        td.fc-day-sat .fc-daygrid-day-number {
            color: blue;
        }
        th.fc-day-sun .fc-col-header-cell-cushion {
            color: red;
        }
        td.fc-day-sun .fc-daygrid-day-number {
            color: red;
        }
```
![text_color](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192195/e2e0a8e9-81aa-ab22-39d7-9873d1476e85.png)



---
最後に
公式HPには300以上の設定ができると書いてありますね・・・！
それにカスタマイズ例を調べていると高確率で必要そうなものは複数の方が書いてくださっている印象があります。

調べていて日本語の情報がなかなか無いこと、ドキュメント通りに行かなかったことが実感としてありました。
少しでも役に立てたら嬉しいです。