FullCalendar v5.0.0を使いこなす(カスタマイズ編)

UI開発者 橋本

この記事はミツエーリンクス Advent Calendar 2020 - Adventarの8日目の記事です。

前回のFullCalendar記事に引き続き、今回はFullCalendar v5のカレンダーの生成と各オプションの説明、応用の仕方について紹介します。

カレンダーの生成とオプションの説明

まず初めにカレンダーの生成方法から説明します。

<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<link href='css/fullcalendar/main.css' rel='stylesheet'>
<script src='js/fullcalendar/main.js'></script>
<script>
(function() {
    'use strict';

    const calendarEl = document.querySelector('.calendar');
    const calendar = new FullCalendar.Calendar(calendarEl);

    calendar.render();
}());
</script>
</head>
<body>
<div class="calendar"></div>
</body>
</html>

カレンダー自体は上記の通り21行で表示できます。
FullCalendarのJSとCSSは公式ドキュメントからダウンロードしたファイルを使用しています。
ただこれではあまりに簡素すぎるので公式ドキュメントのデモレベルまでカスタマイズすると以下のようになります。

カレンダーのオプション

CodePenで記述している各オプションについて説明します。

オプション名 説明
headerToolbar object left/center/right or start/center/end カレンダー上のツールバーのボタン配置(詳細
initialDate string Date Object 初回読み込み時に表示したい最初の日付(指定しなければ現在の日付)
navLinks boolean true/false カレンダー内の日付クリックで日表示に遷移するかどう
businessHours boolean true/false 休日を表示するかどうか
editable boolean true/false イベントを編集できるかどうか
locale string ja カレンダーに表示する文字の言語選択
events array of objects [Event Object] カレンダー上の予定(以下「イベント」)の表示に使用します

localeオプションに関しては単体だけでは使えないので、locales/ja.jsの読み込みも必要になります。
またeventsオプションは配列の他にも関数として指定したり、外部のJSONファイルをURLで指定して読み込むこともできます。

カレンダーの種類

FullCalendarのカレンダーは以下の通り16種類あります。

  • dayGridMonth
  • dayGridWeek
  • dayGridDay
  • timeGridWeek
  • timeGridDay
  • listYear
  • listMonth
  • listWeek
  • listDay
  • custom(後ほど説明)
  • 有料プラン
    • resourceTimelineYear
    • resourceTimelineMonth
    • resourceTimelineWeek
    • resourceTimelineDay
    • resourceTimeGridWeek
    • resourceTimeGridDay

「~Month」「~Week」「~Day」は以後、月表示、週表示、日表示と表記します。

カレンダーのカスタマイズ方法

公式ドキュメントに載っているオプションで、自分が便利だと感じたカスタマイズの一部を紹介します。

タイトルなどの日付フォーマットを変更したい

CodePenでカレンダーの真上に表示されている日付の文言を変更したいときのカスタマイズ方法について説明します。
たとえば週表示で現在初期表示される「2020年11月29日 - 12月5日」を「11月~12月」のように文言を月のみの表示にしたいとか、カレンダー内の見出しにある「12/1(火)」から「1(火)」と月の文言を取りたいなどのカスタマイズをしたいときには、titleFormatdayHeaderFormatというプロパティを使います。

具体的なコードは以下になります。

views: {
  timeGridWeek: {
    titleFormat: function (date) {
      const startMonth = date.start.month + 1;
      const endMonth = date.end.month + 1;

      // 1週間のうちに月をまたぐかどうかの分岐処理
      if (startMonth === endMonth) {
         return startMonth + '月';
      } else {
         return startMonth + '月~' + endMonth + '月'; 
      }
    },
    dayHeaderFormat: function (date) {
      const day = date.date.day;
      const weekNum = date.date.marker.getDay();
      const week = ['(日)', '(月)', '(火)', '(水)', '(木)', '(金)', '(土)'][weekNum];

      return day + ' ' + week;
    }
  }
}

viewsオプションにカスタマイズしたいカレンダーを指定し、その中にtitleFormatdayHeaderFormatプロパティを記述します。
dateという引数には、現在表示している1週間の範囲の日付情報が入っています。そこから月情報や日情報を定義してreturnで表示したい値を返すようにしています。

イベントをすべて四角枠で表示したい

FullCalendarのv5から、終日イベントなどの時間指定をしていないイベントは四角枠、時間指定をしてあるイベントはイベント文言の前にドットが付く形で表示されます。時間指定をしてあるイベントも四角枠で表示させたいのであればeventDisplayオプションで'block'を指定するとすべてのイベントが四角枠で表示できます('list-item'を指定するとすべてのイベントをドットが付く形で表示できます)。

時間区切りの間隔を変更したい

週表示や日表示でカレンダーの時間区切りをslotDurationオプション、slotLabelIntervalオプションで変更できます。

具体的なコードは以下になります。

slotDuration: '00:15:00',
slotLabelInterval: '01:00'

slotDurationプロパティは時間枠の区切りを何時間、何分、何秒の間隔で表示するかを指定できて、slotLabelIntervalプロパティは何時間、何分ごとに時間テキストを表示するかを指定できます。
上記の例では、1時間ごとのテキストの間に15分間隔、つまり4区切りの時間枠が表示されます。
デフォルトだとslotDuration: '00:30:00'slotLabelInterval: '01:00'が設定されています。

カレンダーに表示する時間範囲を絞りたい

上記のCodePenだと、週表示や日表示で、0時~24時の表示になっていますが、ある時間の範囲のみ表示したいとなったときにslotMinTimeslotMaxTimeというプロパティを使って表現できます。

具体的なコードは以下になります。

views: {
  timeGridWeek: {
    slotMinTime: '09:00:00',
    slotMaxTime: '18:00:00'
  },
  timeGridDay: {
    slotMinTime: '09:00:00',
    slotMaxTime: '18:00:00'
  }
}

上記の例では9時~18時の範囲のみの予定が表示され、19時~8時の時間軸が表示されなくなります。

カレンダーをスクロールなしの全量表示したい

カレンダーはデフォルトで一定の高さでサイズがキープされ、中身がそれを越えるとスクロールが出るようになっています。contentHeightオプションに'auto'を指定すると全量表示ができ、スクロールバーが消えます。

祝日を反映させたい

FullCalendarの機能としてはないのですが、GoogleカレンダーのAPIを用いることで反映が可能です(APIの取得方法はこちら)。

具体的なコードは以下になります。

eventSources: [
  {
    googleCalendarApiKey: 'ここにAPIキーが入ります',
    googleCalendarId: 'japanese__ja@holiday.calendar.google.com',
    display: 'background',
  }
]

eventSourcesオプションに配列としてGoogleカレンダーのAPIキーとjapanese__ja@holiday.calendar.google.comというGoogleが提供している日本の祝日データの入ったアドレスを指定します。
googleCalendarIdプロパティには自分のGoogleカレンダーIDを記述するとGoogleカレンダーの自分の予定がFullCalendarに反映されます。
displayプロパティはとくに指定しなければ、祝日名がカレンダーに表示されますが、'background'を指定することで休日と同じ背景色が変わるだけの効果にできます。

現在時刻を視覚的にしたい

nowIndicatorオプションをtrueにすることで、週表示、日表示に赤線で現在時刻のボーダーが表示されます(ボーダーの色はCSSで変更できます)。

日付1枠に表示するイベントを制限したい

デフォルトのカレンダーだと1日の予定が増えていったときにカレンダーの日付枠がどんどん縦に伸びていきます。
それを制限したいときはdayMaxEventsオプションをtrueにすることで、枠の高さを超えるイベントは表示されずその代わりに「+ 2more」のようなテキストリンクが表示され、クリックすることでその日の全体のイベントをポップアップ表示できます。

日付枠内の日付を数字のみにしたい

カレンダーを日本語にすると、月表示で日付枠内の日付が「○日」と表示されるなど余分なテキストが付いてしまいます。
余分なテキストを取り除きたい場合は、dayCellContentオプションを使うことでセル内のテキストを編集できます。

具体的なコードは以下になります。

dayCellContent: function (e) {
  e.dayNumberText = e.dayNumberText.replace('日', '');
}

dayNumberTextが日付枠の日付部分に当たるので、そこに付いた「日」という不要な文言をreplaceで取り除く処理を記述するだけです。

オリジナルレイアウトのカレンダーを作成したい

前述したカレンダー種類の中にcustomというものがあったと思います。
こちらで自由なレイアウト、情報の出し分けができるカレンダーを作成できます。

手順と具体的なコードは以下になります。

中身の要素、レイアウトを作る

const CustomViewConfig = {
  classNames: ['custom-view'],
  buttonText: '予約リスト2',
  duration: {days: 31},
  titleFormat: function (date) {
    const startYear = date.start.year;
    const endYear = date.end.year;
    const startMonth = date.start.month + 1;
    const endMonth = date.end.month + 1;
    const startDay = date.start.day;
    const endDay = date.end.day;

    if (startYear === endYear) {
        return startYear + '年' + startMonth + '月' + startDay + '日 ~ ' + endMonth + '月' + endDay + '日';
    } else {
        return startYear + '年' + startMonth + '月' + startDay + '日 ~ ' + endYear + '年' + endMonth + '月' + endDay + '日';
    }
  },
  content: function (props) {
    const segs = FullCalendar.sliceEvents(props, true);
    let getData = '';
    function addZero (num) {
      let result = '';
      if (num < 10) {
        result = '0' + num;
      } else {
        result = String(num);
      }

      return result;
    };
    function getSegs() {
      for (let i = 0, len = segs.length; i < len; i++) {
        const data = segs[i];
        const start = data.instance.range.start;
        const end = data.instance.range.end;
        const month = start.getMonth() + 1;
        const day = start.getDate();
        const weekNum = start.getDay();
        const week = ['(日)', '(月)', '(火)', '(水)', '(木)', '(金)', '(土)'][weekNum];
        const getDate = month + '月' + day + '日' + week;

        const startHours = start.getUTCHours();
        const endHours = end.getUTCHours();
        const startMinutes = start.getUTCMinutes();
        const endMinutes = end.getUTCMinutes();
        let getTime;
        if (startHours + startMinutes + endHours + endMinutes === 0) {
          getTime = '終日';
        } else {
          getTime = addZero(startHours) + ':' + addZero(startMinutes) + '-' + addZero(endHours) + ':' + addZero(endMinutes);
        }

        const getEvent = data.def.title;

        getData += '<tr><th>' + getDate + '</th><td>' + getTime + '</td><td>' + getEvent + '</td></tr>';
      }
      return getData;
    }
    getSegs();

    let html;
    if (getData === '') {
      html = '<div class="not-data">表示する予定はありません</div>';
    } else {
      html = '<table><thead><tr><th>日付</th><th>時間</th><th>予定</th></tr></thead>' +
      '<tbody>' + getData + '</tbody>' +
      '</table>';
    }

    return {html: html};
  }
};

上記記述の中から新しく出てきたオプションについて説明します。

オプション名 説明
classNames array ['クラス名'] カスタマイズしたカレンダーにクラスを付与できます
buttonText string 'ボタン名' カレンダー上部のツールにある、このカレンダーにリンクするボタンの名前を変更できます
duration object {days: 31} 表示する時間範囲です。31を設定することで現在の日付から1か月分の範囲を指定できます

viewsオプション、headerToolbarオプションにカスタマイズしたカレンダーを追加する

views: {
  custom: CustomViewConfig
},
headerToolbar: {
  left: 'prev,next today',
  center: 'title',
  right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth,custom'
}

このように自作レイアウトで作ったものを簡単にカレンダーの一部として扱うことができますが、少々カスタマイズ難易度が高いものになると思います。

まとめ

今までの変更をすべて含めたカレンダーを以下に反映してみました(祝日表示はAPIキーを使うことになるので、反映していません)。
自作レイアウトのカレンダーは「予定リスト2」として反映されています。

ミツエーリンクスのアドベントカレンダーの予定を入れてみましたので、気になった記事があったらぜひ見てみてください!

最後に、ここまでの内容を通してカスタマイズの自由さを理解していただけたでしょうか。
今回紹介したカスタマイズはまだほんの一部であり、公式ドキュメントには他にもさまざまなオプションがありますので、是非熟読してみてください!