반응형
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 설정이 필요하다.
'JavaScript' 카테고리의 다른 글
[JavaScript] 이벤트 루프란? (Event Loop, JS Engine, Web API, Callback Queue, Single Thread, ...) (1) | 2025.02.04 |
---|