[Javascript] Full calendar(스케줄 달력)의 사용법


안녕하세요. 명월입니다.


이 글은 웹에서의 full calendar(스케줄 달력)의 사용법에 대한 글입니다.


우리가 웹 프로그램을 작성하게 되면 보통 네이버 같은 포털 사이트보다 회사나 여러가지 그룹등에서 사용하는 커뮤니티 사이트나 일정 관리 사이트가 많이 개발할 듯 싶습니다.

그 프로젝트에서 가장 많이 쓰이는 프레임워크 라이브러리가 WYSIWYG 에디트로 웹 환경에서 메모장 같이 사용되는 에디트 기능이라고 생각합니다만, 그 외에는 아마 스케줄을 설정하는 달력 프레임워크 라이브러리가 아닐까 생각합니다.


달력 프레임워크에 관해서도 여러가지 프레임워크가 존재합니다만, 개인적으로 full-calendar라는 라이브러리가 가장 편하지 않을까 싶어 소개하고자 합니다.

링크 - https://fullcalendar.io/

일단 fullcalendar를 사용하기 위해서 해당 자바스크립트(js)과 스타일시트(css)를 다운받아서 사용해도 좋습니다만, 웹 환경의 성능을 위해서 CDN 링크를 사용하는 것을 추천합니다.

다운로드 링크 - https://fullcalendar.io/docs/initialize-globals

CDN 링크 - https://www.jsdelivr.com/package/npm/fullcalendar

<!DOCTYPE html>
<html>
<head>
  <meta charset='utf-8' />
  <!-- 화면 해상도에 따라 글자 크기 대응(모바일 대응) -->
  <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <!-- jquery CDN -->
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <!-- fullcalendar CDN -->
  <link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.8.0/main.min.css' rel='stylesheet' />
  <script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.8.0/main.min.js'></script>
  <!-- fullcalendar 언어 CDN -->
  <script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.8.0/locales-all.min.js'></script>
<style>
  /* body 스타일 */
  html, body {
    overflow: hidden;
    font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
    font-size: 14px;
  }
  /* 캘린더 위의 해더 스타일(날짜가 있는 부분) */
  .fc-header-toolbar {
    padding-top: 1em;
    padding-left: 1em;
    padding-right: 1em;
  }
</style>
</head>
<body style="padding:30px;">
  <!-- calendar 태그 -->
  <div id='calendar-container'>
    <div id='calendar'></div>
  </div>
  <script>
  (function(){
    $(function(){
      // calendar element 취득
      var calendarEl = $('#calendar')[0];
      // full-calendar 생성하기
      var calendar = new FullCalendar.Calendar(calendarEl, {
        height: '700px', // calendar 높이 설정
        expandRows: true, // 화면에 맞게 높이 재설정
        slotMinTime: '08:00', // Day 캘린더에서 시작 시간
        slotMaxTime: '20:00', // Day 캘린더에서 종료 시간
        // 해더에 표시할 툴바
        headerToolbar: {
          left: 'prev,next today',
          center: 'title',
          right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
        },
        initialView: 'dayGridMonth', // 초기 로드 될때 보이는 캘린더 화면(기본 설정: 달)
        initialDate: '2021-07-15', // 초기 날짜 설정 (설정하지 않으면 오늘 날짜가 보인다.)
        navLinks: true, // 날짜를 선택하면 Day 캘린더나 Week 캘린더로 링크
        editable: true, // 수정 가능?
        selectable: true, // 달력 일자 드래그 설정가능
        nowIndicator: true, // 현재 시간 마크
        dayMaxEvents: true, // 이벤트가 오버되면 높이 제한 (+ 몇 개식으로 표현)
        locale: 'ko', // 한국어 설정
        eventAdd: function(obj) { // 이벤트가 추가되면 발생하는 이벤트
          console.log(obj);
        },
        eventChange: function(obj) { // 이벤트가 수정되면 발생하는 이벤트
          console.log(obj);
        },
        eventRemove: function(obj){ // 이벤트가 삭제되면 발생하는 이벤트
          console.log(obj);
        },
        select: function(arg) { // 캘린더에서 드래그로 이벤트를 생성할 수 있다.
          var title = prompt('Event Title:');
          if (title) {
            calendar.addEvent({
              title: title,
              start: arg.start,
              end: arg.end,
              allDay: arg.allDay
            })
          }
          calendar.unselect()
        }
        // 이벤트 
        events: [
          {
            title: 'All Day Event',
            start: '2021-07-01',
          },
          {
            title: 'Long Event',
            start: '2021-07-07',
            end: '2021-07-10'
          },
          {
            groupId: 999,
            title: 'Repeating Event',
            start: '2021-07-09T16:00:00'
          },
          {
            groupId: 999,
            title: 'Repeating Event',
            start: '2021-07-16T16:00:00'
          },
          {
            title: 'Conference',
            start: '2021-07-11',
            end: '2021-07-13'
          },
          {
            title: 'Meeting',
            start: '2021-07-12T10:30:00',
            end: '2021-07-12T12:30:00'
          },
          {
            title: 'Lunch',
            start: '2021-07-12T12:00:00'
          },
          {
            title: 'Meeting',
            start: '2021-07-12T14:30:00'
          },
          {
            title: 'Happy Hour',
            start: '2021-07-12T17:30:00'
          },
          {
            title: 'Dinner',
            start: '2021-07-12T20:00:00'
          },
          {
            title: 'Birthday Party',
            start: '2021-07-13T07:00:00'
          },
          {
            title: 'Click for Google',
            url: 'http://google.com/', // 클릭시 해당 url로 이동
            start: '2021-07-28'
          }
        ]
      });
      // 캘린더 랜더링
      calendar.render();
    });
  })();
</script>
</body>
</html>

위 예제에서 calendar에 마우스로 드래그해서 이벤트를 추가할 수 있고, 링크를 통해 페이지 이동, 일의 숫자를 눌러서 캘린더가 이동하는 것 등등을 테스트 해 볼 수 있습니다.


저는 위 예제에서 이벤트를 배열식으로 고정으로 설정하였습니다만, ajax로 동적으로 데이터를 취득할 수도 있습니다.

링크 - https://fullcalendar.io/docs/events-json-feed


그 외에 드래그 형식의 아이템 박스를 만들어서 아이템을 드래그 엔 드롭하는 캘린더도 만들수도 있습니다.

<!DOCTYPE html>
<html>
<head>
  <meta charset='utf-8' />
  <!-- 화면 해상도에 따라 글자 크기 대응(모바일 대응) -->
  <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <!-- jquery CDN -->
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <!-- fullcalendar CDN -->
  <link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.8.0/main.min.css' rel='stylesheet' />
  <script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.8.0/main.min.js'></script>
  <!-- fullcalendar 언어 CDN -->
  <script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.8.0/locales-all.min.js'></script>
<style>
  /* body 스타일 */
  body {
    margin-top: 40px;
    font-size: 14px;
    font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
  }
  /* 드래그 박스의 스타일 */
  #external-events {
    position: fixed;
    left: 20px;
    top: 20px;
    width: 100px;
    padding: 0 10px;
    border: 1px solid #ccc;
    background: #eee;
    text-align: left;
  }
  #external-events h4 {
    font-size: 16px;
    margin-top: 0;
    padding-top: 1em;
  }
  #external-events .fc-event {
    margin: 3px 0;
    cursor: move;
  }

  #external-events p {
    margin: 1.5em 0;
    font-size: 11px;
    color: #666;
  }

  #external-events p input {
    margin: 0;
    vertical-align: middle;
  }

  #calendar-wrap {
    margin-left: 200px;
  }

  #calendar1 {
    max-width: 1100px;
    margin: 0 auto;
  }
</style>
</head>
<body>
  <div id='wrap'>
    <!-- 드래그 박스 -->
    <div id='external-events'>
      <h4>Draggable Events</h4>
      <div id='external-events-list'></div>
    </div>
    <!-- calendar 태그 -->
    <div id='calendar-wrap'>
      <div id='calendar1'></div>
    </div>
  </div>
  <script>
  (function(){
    $(function(){
      // 드래그 박스 취득
      var containerEl = $('#external-events-list')[0];
      // 설정하기
      new FullCalendar.Draggable(containerEl, {
        itemSelector: '.fc-event',
        eventData: function(eventEl) {
          return {
            title: eventEl.innerText.trim()
          }
        }
      });
      // 드래그 아이템 추가하기
      for(var i=1; i<=5;i++) {
        var $div = $("<div class='fc-event fc-h-event fc-daygrid-event fc-daygrid-block-event'></div>");
        $event = $("<div class='fc-event-main'></div>").text("Event "+i);
        $('#external-events-list').append($div.append($event));
      }
      // calendar element 취득
      var calendarEl = $('#calendar1')[0];
      // full-calendar 생성하기
      var calendar = new FullCalendar.Calendar(calendarEl, {
        // 해더에 표시할 툴바
        headerToolbar: {
          left: 'prev,next today',
          center: 'title',
          right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
        },
        initialDate: '2021-07-15', // 초기 날짜 설정 (설정하지 않으면 오늘 날짜가 보인다.)
        locale: 'ko', // 한국어 설정
        editable: true, // 수정 가능
        droppable: true,  // 드래그 가능
        drop: function(arg) { // 드래그 엔 드롭 성공시
          // 드래그 박스에서 아이템을 삭제한다.
          arg.draggedEl.parentNode.removeChild(arg.draggedEl);
        }
      });
      // 캘린더 랜더링
      calendar.render();
    });
  })();
</script>
</body>
</html>

Draggable Events

위 예제에서 왼쪽 드래그 박스에서 캘린더로 드래그 엔 드롭이 가능합니다.(모바일의 경우는 이벤트를 누른 후 1초 이상 유지하면 드래그 엔 드롭이 가능합니다.)

드래그 엔 드롭은 따로 ajax로 추가하는 함수가 없기 때문에 동적으로 생성하는 코드를 작성해야 합니다. 저의 경우도 for문으로 5개 생성했네요.

링크 - https://fullcalendar.io/docs/external-dragging


그리고 fullcalendar에는 유료 버전인 timeline 캘린더도 있습니다.

<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
  <style>
    /* body 스타일 */
    html, body {
      margin: 0;
      padding: 0;
      font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
      font-size: 14px;
    }
    #calendar2 {
      max-width: 1100px;
      margin: 40px auto;
    }
  </style>
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.8.0/main.min.css' rel='stylesheet' />
  <script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.8.0/main.min.js'></script>
  <script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.8.0/locales-all.min.js'></script>
</head>
<body>
  <div id='calendar2'></div>
  <script>
  (function(){
    $(function(){
      // calendar element 취득
      var calendarEl = $('#calendar2')[0];
      // full-calendar 생성하기
      var calendar = new FullCalendar.Calendar(calendarEl, {
        timeZone: 'UTC', // 타임존 설정
        initialView: 'resourceTimelineDay', // 초기 로드 될때 보이는 캘린더 화면(기본 설정: 일)
        aspectRatio: 1.5, // 너비를 채우는 블록 요소
        // 해더에 표시할 툴바
        headerToolbar: {
          left: 'prev,next',
          center: 'title',
          right: 'resourceTimelineDay,resourceTimelineWeek,resourceTimelineMonth'
        },
        editable: true, // 수정 가능
        resourceAreaHeaderContent: 'Rooms',
        initialDate: '2021-07-15', // 초기 날짜 설정 (설정하지 않으면 오늘 날짜가 보인다.)
        height: '320px', // 높이 설정
        locale: 'ko', // 한국어 설정
        // 타임 라인에서 왼쪽의 리소스 설정(이 부분도 물론 ajax로 설정이 가능하다.)
        resources: [
          {"id":"a","title":"Auditorium A"},
          {"id":"b","title":"Auditorium B","eventColor":"green"},
          {"id":"c","title":"Auditorium C","eventColor":"orange"},
          {"id":"d","title":"Auditorium D","children":[
           {"id":"d1","title":"Room D1"},
           {"id":"d2","title":"Room D2"}]
          }
        ],
        // 이벤트 
        events: [
          {"resourceId":"a","title":"event 1","start":"2021-07-14","end":"2021-07-16"},
          {"resourceId":"b","title":"event 3","start":"2021-07-15T12:00:00+00:00","end":"2021-07-16T06:00:00+00:00"},
          {"resourceId":"d1","title":"event 4","start":"2021-07-15T07:30:00+00:00","end":"2021-07-15T09:30:00+00:00"}
        ]
      });
      // 캘린더 랜더링
      calendar.render();
    });
  })();
</script>
</body>
</html>

위 소스는 일반 캘런더가 아니고 가로로 타임 라인이 있는 캘린더입니다.

시간 관련된 스케줄러 프로그램을 만들 때 유용할 듯 싶네요.

참고로 위 소스는 유료 라이센스가 필요한 모듈입니다. 필요하시면 FullCalendar에서 라이센스를 구매한 후 사용하시면 됩니다.


제가 자주 사용하는 API는 예제로 설명을 했습니다만, 그 외에 더 많은 API를 사용하시려면 API 도큐멘트를 확인하시면 될 듯 싶습니다.

링크 - https://fullcalendar.io/docs#toc

위 API 도큐멘트가 영어로 되어 있기는 합니다만, 그렇게 어려운 영어는 아니니 파파고 등을 이용하면 사용하는 데는 크게 어려움이 없을 듯 싶습니다.


여기까지 웹에서의 full calendar(스케줄 달력)의 사용법에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.