반응형

0. 요청사항

  • Header : 월 이동, Toay 날짜 이동 커스텀 버튼
  • 달력에 오늘날짜에 리본 표시하기
  • 달력 이벤트 조회 후, 오늘 날짜 기준으로 가장 가까운 event에 select (select시 해당 날짜에 대한 상세 조회)
  • 날짜 클릭 시, 선택된 날짜를 알 수 있게 표시하기 (하늘색 부분)

1. html

html

<body>
  <div id='calendar'></div>
</body>

2. css

css

/* calendar : resize */
#calendar {
  flex: 1;
  height: 100%;
}
#calendar a {
  color: inherit;
}
#calendar :hover {
  cursor: pointer;
}

/* calendar : toolbar, header, title */
.fc .fc-toolbar.fc-header-toolbar {
  margin: 1em 1.5em;
}
.fc .fc-toolbar-title {
  font-size: 1.5em;
  margin: 0 1.25em 0 2em !important;
  white-space: nowrap;
}
.fc-toolbar-chunk {
  display: flex;
  align-items: center;
}
.fc-toolbar-chunk:nth-child(2) {
  flex: 1;
  justify-content: center;
}
.fc-button {
  width: 38.75px;
  height: 33.78px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.fc-today-button {
  white-space: nowrap;
  width: 43.22px;
  height: 33.78px;
}

/* today ribon */
.fc-daygrid-day.fc-day-today {
  z-index: 1;
}
.fc-daygrid-day.fc-day-today .fc-daygrid-day-top::before {
  content: "Today";
  position: absolute;
  top: 5px;
  left: 5px;
  background: linear-gradient(45deg, #ff5f5f, #ff9e9e);
  color: white;
  font-size: 12px;
  font-weight: bold;
  padding: 0 10px;
  border-radius: 3px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.fc-daygrid-day.fc-day-today .fc-daygrid-day-top {
  position: relative;
}

/* custom event */
.fc-daygrid-day-events {
  text-align:left;
  border-radius:50%;
  padding:0px 7px;
  margin-right:3px;
  font-size:1rem;
}

3. javascript

  • fullCalendar 원하는 위치에 다운로드 후 소스추가

html

<script src='/resources/fullcalendar/lib/main.js'></script>

javascript

const today = new Date(); // 'yyyy-mm-dd' 형태로 Format 필요
const colorMap = { '계약금': '#42bd04',
                   '중도금': '#0e8fcf',
                   '잔금': '#d4aa02'
                 };
var prevInfo, calendarEvent, calendar; // FullCalendar에서 사용할 변수 생성

createCalendar(); // calendar Initialize
get_Date(today); // calendar 최초 조회

function createCalendar() {
  var calendarEl = document.getElementById("calendar");
  calendar = new FullCalendar.Calendar(calendarEl, {
    initialView: "dayGridMonth",
    views: {
      dayGridMonth: {
        titleFormat: function (date) {
          return date.start.year + "년" + (date.start.month + 1) + "월";
        },
      },
    },
    headerToolbar: {
      start: "",
      center: "prevYear prev title next nextYear today",
      end: "",
    },
    customButtons: {
      today: {
        text: "오늘",
        click: function () {
          calendar.today();
        },
      },
    },
    locale: "ko",
    height: "100%",
    showNonCurrentDates: false,
    fixedWeekCount: false,
    windowResizeDelay: 300,
    eventClick: function (info) {
      let dInfo = {
        date: info.event.start,
        dayEl: $(info.el).closest(".fc-daygrid-day").get(0),
        dateStr: info.event.startStr,
      };

      calendar.trigger("dateClick", dInfo);
    },
    events: function (info, successCallback, failureCallback) {
      calendarEvent = successCallback;
    },
    eventContent: function (arg) {
      let eventTitle = arg.event.title;
      let bgC = colorMap[eventTitle.slice(0, 3).trim()] || "#ffffff";

      return {
        html:
        '<div style="background-color: ' +
        bgC +
        '; padding: 2px;"><span class="fc-custom-event"><small class="fas fa-circle mx-1"></small>' +
        eventTitle +
        "</span><div>",
      };
    },
    dateClick: function (info) {
      if (prevInfo != null && prevInfo.dateStr != info.dateStr) {
        prevInfo.dayEl.style.backgroundColor = "";
      }
      info.dayEl.style.backgroundColor = "rgba(183, 224, 255, 0.3)";
      prevInfo = info || "";

      $("#INFO_TXT2").text("선택날짜 : " + info.dateStr);

      getDate(calendar.getDate()); // 여기서 해당 날짜(info.dateStr)의 상세 조회 호출
    },
    select: function (info) {
      let dInfo = {
        date: info.start,
        dayEl: document.querySelector("[data-date='" + info.startStr + "']"),
        dateStr: info.startStr,
      };

      calendar.trigger("dateClick", dInfo);
    },
    windowResize: function (arg) {
      calendar.updateSize();
    },
  });

  calendar.render();
}

// Ajax function 예시
function getDate(param) {
  $.ajax({
    url: '/get_EventData',
    method: 'get',
    data: JSON.stringify(param),
    contentType: 'application/json',
    success: (rtnData) => {
      const evtData = rtnData.Data.map(data => ({
        title: data.TITLE,
        start: data.DATE,
        end: data.DATE
      }));

      calendarEvent(evtData);

      // 조회 후 가까운 Event에 Select
      let closestEvent = evtData.filter(event => event.start >= today)
                                  .sort((a, b) => a.start.localeCompare(b.start))[0] || evtData.sort((a, b) => a.start.localeCompare(b.start))[0];
      if (closestEvent) {
        calendar.select(closestEvent);
      }
      }
    },
    error: (err) => console.error('AJAX 요청 실패:', err)
  });
}

4. 속성

  • FullCalendar - JavaScript Event Calendar
  • initialView:
    • 캘린더가 로드될 때의 초기 모습
    • 사용 가능한 View (ex: 'dayGridWeek', 'timeGridDay', 'listWeek')
  • views
    • 특정 Calendar View에만 적용되는 옵션을 지정할 수 있다.
    • ‘dayGridMonth’ View의 Title을 Format 하기 위해 설정
  • headerToolbar
    • 달력 상단의 버튼과 제목을 정의
    • start, center, end는 기본 위치를 자체 css가 잡아주지만, 위 소스에서는 center에 몰아넣고 css로 새로 적용했다.
    • 기본적으로 ‘title’, ‘prev’, ‘next’, ‘prevYear’, ‘nextYear’, ‘today’ 들을 제공하고있고, 커스텀 가능하다.
  • customButtons
    • headerToolbar/footerToolbar에서 사용할 수 있는 사용자 정의 버튼을 정의한다.
    • 혀용되는 속성으로 text, hint, click, icon, bootstrapFontAwesome이 있다.
  • showNonCurrentDates
    • 월별 보기에서 이전 달이나 다음 달의 날짜를 렌더링할지 여부를 지정
    • false 처리하여 맨 위 사진처럼 회색으로 나타남
  • fixedWeekCount
    • 월별 보기에 표시되는 주 수를 결정
  • eventClick: function
    • 사용자가 이벤트를 클릭하면 발생
    • 위 소스에서는 event클릭 시에도 날짜 클릭(dateClick)과 같은 로직을 하기에 Element를 임의로 만들어 dateClick을 trigger 시켰다.
    • select에서 style.backgroundColor를 바꿔야 하기에 day Element가 필요함.
  • events: function
    • 사용자가 이전/다음을 클릭하거나 뷰를 전환할 때 트리거되며, 해당 영역에서 Ajax 요청을하고, success와 fail에 대한 callback함수를 정의할 수 있다.
    • 위 소스에서는 calendar 함수 밖에서 ajax요청을 보내야 하기 때문에 calendarEvent를 전역변수로 만들어 successCallback 함수를 담아 처리했다.
  • eventContent: function
    • Custom 이벤트를 다양한 위치에서 FullCalendar DOM에 주입시킨다.
    • 위 코드에선 Ajax 요청시 successCallback 함수를 가르키는 calendarEvent를 실행하여 return Data를 담아 발생시켰다.
    • evtData를 colorMap에 맞춰 이벤트 DIV를 DOM에 주입시켰다.
  • dateClick: function
    • 사용자가 날짜나 시간을 클릭하면 발생한다.
    • select한 날짜의 Element를 Full Calendar가 처리가능한 객체로 만들고, 클릭한 날짜의 배경색을 처리한 부분
  • select: function
    • 날짜/시간 선택 시 트리거
  • windowResize: function
    • 브라우저 창 크기가 조정되어 달력의 크기가 변경된 후에 발생하며 windowResize가 트리거되면 달력이 자동으로 새로운 크기에 맞게 조정
    • DOM LOAD가 느려 제대로 동작하지 않을경우 windowResizeDelay 설정이 필요하다.
반응형
반응형

+ Recent posts