ํ์บ๋ฆฐ๋(FullCalendar) ์์ฑ - 6
FullCalendar JS๋ฅผ ํ์ฉํ๋ค ๋ณด๋ฉด ๊ต์ฅํ ๋ค์ํ ์์ฑ๊ณผ ์ด๋ฒคํธ๋ฅผ ๋ณผ ์ ์๋ค. ์ฌ๋ฌ ์์ฑ๋ค์ด ์ด๋ค ํน์ง๋ค์ ๊ฐ์ง๊ณ ์๋์ง, ํ์บ๋ฆฐ๋๊ฐ ๊ฐ์ง๊ณ ์๋ ์ด๋ฒคํธ์๋ ์ด๋ค ๊ฒ๋ค์ด ์์ผ๋ฉฐ ํด๋น ์ด๋ฒคํธ๋ ์ด๋ค ๋์๋ค์ ํฌํจํ๊ณ ์๋์ง ๋ฑ๋ฑ์ ๋ํด์ ์ ๋ชจ๋ฅผ ๋๊ฐ ๋ง๋ค. FullCalendar JS ๊ณต์ ํํ์ด์ง์์ ์ ๊ณตํ๋ Documents ํ์ผ์ ๋ณด๊ธด ํ์ง๋ง Docs ๋ฌธ์๋ค์ ํ์ธํ๋ ๊ฒ ์์ง ์ต์์ง ์์ ์ฌ๋์ ๋ฌธ์ ๋ณด๋ ๋ฐฉ๋ฒ์กฐ์ฐจ ์ด๋ ค์ธ ์ ์๋ค. ๊ทธ๋์ FullCalendar JS์์ ์ฌ์ฉํ ์ ์๋ ์์ฑ๋ค์ ํ๋์ ์ดํด๋ณด๊ณ ์ ํ๋ค. ๋ฌผ๋ก 100% ๋ชจ๋ ์์ฑ๋ค์ ์ ๋ถ ๋ณด๋ฉด ์ข๊ฒ ์ง๋ง, ๊ฐ์ฅ ์ค์ํ ์์ฑ๋ค ์์ฃผ๋ก ํ์ธํด ๋ณด๊ณ ๊ทธ ์ธ์ ์์ฑ๋ค์ ์ง์ Documents๋ฅผ ํ์ธํด ๋ณด๊ธธ ๋ฐ๋๋ค.
๐ 6. ์ํธ์์ฉ (Interaction Options)
droppable
' ๋ค๋ฅธ ๋ฌ๋ ฅ์ ๋๋๊ทธ ๊ฐ๋ฅํ ์ธ๋ถ ์์๋ ์ด๋ฒคํธ๋ฅผ ๋ฌ๋ ฅ์ ๋์ ์ ์๋์ง ์ฌ๋ถ '
droppable ์์ฑ์ ์ธ๋ถ ์์๋ฅผ Drag & Drop์ผ๋ก ์บ๋ฆฐ๋์ ๋๋กญํ ์ ์๋๋ก ํ์ฑํ ํ๋ ๊ธฐ๋ฅ์ ๋๋ค. ํด๋น ์์ฑ์ ํตํด ์ธ๋ถ ์ด๋ฒคํธ๋ฅผ ์ผ์ ์ผ๋ก ์ถ๊ฐํ ์ ์๊ณ ์ธํฐ๋์ ์ ๊ฐํํ๊ฑฐ๋ jQuery UI ๋๋ Draggable ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํจ๊ป ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค. ๊ธฐ๋ณธ๊ฐ์ false์ ๋๋ค.
<div id="external-events">
<p><strong>์ธ๋ถ ์ผ์ ๋ชฉ๋ก</strong></p>
<div class="fc-event" data-title="์ผ์ 1">์ผ์ 1</div>
<div class="fc-event" data-title="์ผ์ 2">์ผ์ 2</div>
</div>
<div id="calendar"></div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// ์ธ๋ถ ์์๋ฅผ ๋๋๊ทธ ๊ฐ๋ฅํ๊ฒ ์ค์
new FullCalendar.Draggable(document.getElementById('external-events'), {
itemSelector: '.fc-event', // ๋๋๊ทธ ๊ฐ๋ฅํ ์์
eventData: function(eventEl) {
return {
title: eventEl.dataset.title // ๋๋กญ๋ ๋ ์ฌ์ฉํ ์ ๋ชฉ
};
}
});
// ์บ๋ฆฐ๋ ์ค์
var calendar = new FullCalendar.Calendar(document.getElementById('calendar'), {
initialView: 'dayGridMonth',
droppable: true, // ๋๋กญ ํ์ฑํ
editable: true // ์ผ์ ์์ ๊ฐ๋ฅ
});
calendar.render();
});
</script>
Draggable ํด๋์ค๋ FullCalendar์ ๋ด์ฅ ๊ธฐ๋ฅ์ด๋ฏ๋ก jQuery UI๊ฐ ๋ณ๋๋ก ํ์๊ฐ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋๋๊ทธ ๊ฐ๋ฅํ ์์์ CSS๋ก ์คํ์ผ์ ์ถ๊ฐํ๋ฉด UI๋ฅผ ๊ฐ์ ํ ์ ์์ต๋๋ค.
eventClick
' ์ฌ์ฉ์๊ฐ ์ด๋ฒคํธ๋ฅผ ํด๋ฆญํ๋ฉด ๋ฐ์ '
eventClick ์์ฑ์ ์ฌ์ฉ์๊ฐ ์บ๋ฆฐ๋์ ์ผ์ (event)์ ํด๋ฆญํ ๋ ํธ์ถ๋๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๋๋ค. ์ผ์ ์ ํด๋ฆญ ์ ํ์ ํ์, ์์ธ ์ ๋ณด ๋ณด๊ธฐ, ์์ , ์ญ์ ๋ฑ์ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์๊ณ event ๊ฐ์ฒด์ jsEvent, view ์ ๋ณด๋ฅผ ์ ๊ณตํฉ๋๋ค.
var calendar = new FullCalendar.Calendar(document.getElementById('calendar'), {
initialView: 'dayGridMonth',
events: [
{ title: '์ผ์ 1', start: '2025-02-15', description: 'ํ๋ก์ ํธ ์งํ ์ํฉ ๋
ผ์' },
{ title: '์ผ์ 2', start: '2025-02-18' }
],
eventClick: function(info) {
alert('์ผ์ ์ ๋ชฉ: ' + info.event.title); // ์ผ์ ์ ๋ชฉ ํ์
}
});
calendar.render();
eventDrop
' ๋๋๊ทธ๊ฐ ์ค์ง๋๊ณ ์ด๋ฒคํธ๊ฐ ๋ค๋ฅธ ์์ผ/์๊ฐ์ผ๋ก ์ด๋ํ ๋ ๋ฐ์ '
eventDrop ์์ฑ์ ์ผ์ ์ ๋๋๊ทธํ์ฌ ๋ ์ง๋ ์๊ฐ์ ๋ณ๊ฒฝํ ๋ ํธ์ถ๋๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๋๋ค. ์ผ์ ์ ์๋ก์ด ๋ ์ง ๋๋ ์๊ฐ์ผ๋ก ์ด๋ํ ์ ์๊ณ ์ด๋ ํ ์๋ฒ์ DB ์ ๋ฐ์ดํธ ์์ฒญ๊ณผ ๊ฐ์ ๊ธฐ๋ฅ ๊ตฌํ์ด ๊ฐ๋ฅํฉ๋๋ค.
var calendar = new FullCalendar.Calendar(document.getElementById('calendar'), {
initialView: 'dayGridMonth',
editable: true, // ์ผ์ ๋๋๊ทธ/์์ ๊ฐ๋ฅ
events: [
{ title: '์ผ์ 1', start: '2025-02-15' },
{ title: '์ผ์ 2', start: '2025-02-18' }
],
eventDrop: function(info) {
alert('์๋ก์ด ๋ ์ง: ' + info.event.start.toISOString()); // ๋ณ๊ฒฝ๋ ๋ ์ง ํ์
}
});
calendar.render();
๋งค๊ฐ๋ณ์ | ์ค๋ช |
info.event | ๋๋๊ทธ ํ ๋ณ๊ฒฝ๋ ์ผ์ ๊ฐ์ฒด (title, start, end ๋ฑ) |
info.delta | ์ผ์ ์ด ์ด๋ํ ์๊ฐ ์ฐจ์ด (์: 1์ผ, 2์๊ฐ ๋ฑ) |
info.revert() | ์ผ์ ์ด๋์ ์ทจ์ํ๊ณ ์๋ ์์น๋ก ๋๋๋ฆผ |
info.jsEvent | JavaScript ์ด๋ฒคํธ ๊ฐ์ฒด (๋ง์ฐ์ค ์ด๋ฒคํธ ๋ฑ) |
eventResize
' ์ผ์ ์ ์๊ฐ ๋ฒ์๋ฅผ ํ์ฅํ๊ฑฐ๋ ์ถ์ํ ๋ ๋ฐ์ '
eventResize ์์ฑ์ ์ฌ์ฉ์๊ฐ ์ผ์ (event)์ ์๊ฐ ๋ฒ์๋ฅผ ํ์ฅํ๊ฑฐ๋ ์ถ์ํ ๋ ํธ์ถ๋๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๋๋ค. Drag๋ก ์ผ์ ์ ์ข ๋ฃ ์๊ฐ์ ๋ณ๊ฒฝ ํ ์ ์๊ณ ์ผ์ ๋ณ๊ฒฝ ํ DB ์ ๋ฐ์ดํธ ์์ฒญ์ ํ ์ ์์ต๋๋ค.
var calendar = new FullCalendar.Calendar(document.getElementById('calendar'), {
initialView: 'timeGridWeek', // ์ฃผ๊ฐ ๋ทฐ์์ ๋ ์ง๊ด์ ์ผ๋ก ํ์ธ ๊ฐ๋ฅ
editable: true, // ์ผ์ ๋๋๊ทธ ๋ฐ ๋ฆฌ์ฌ์ด์ฆ ๊ฐ๋ฅ
events: [
{ title: '์ผ์ 1', start: '2025-02-15T10:00:00', end: '2025-02-15T11:00:00' }
],
eventResize: function(info) {
alert('์๋ก์ด ์ข
๋ฃ ์๊ฐ: ' + info.event.end.toISOString()); // ๋ณ๊ฒฝ๋ ์ข
๋ฃ ์๊ฐ ํ์
}
});
calendar.render();
๋งค๊ฐ๋ณ์ | ์ค๋ช |
info.event | ๋ฆฌ์ฌ์ด์ฆ ํ ๋ณ๊ฒฝ๋ ์ผ์ ๊ฐ์ฒด (title, start, end ๋ฑ) |
info.delta | ์ผ์ ์ด ํ์ฅ/์ถ์๋ ์๊ฐ ์ฐจ์ด (Duration ๊ฐ์ฒด) |
info.revert() | ์ผ์ ๋ณ๊ฒฝ ์ทจ์ ๋ฐ ์๋ ์ํ๋ก ๋ณต๊ตฌ |
info.jsEvent | JavaScript ์ด๋ฒคํธ ๊ฐ์ฒด (๋ง์ฐ์ค ์ด๋ฒคํธ ๋ฑ) |
dateClick
' ์ฌ์ฉ์๊ฐ ๋ ์ง๋ ์๊ฐ์ ํด๋ฆญํ๋ฉด ๋ฐ์ '
dateClick ์์ฑ์ ์บ๋ฆฐ๋์ ํน์ ๋ ์ง๋ ์๊ฐ์ ํด๋ฆญํ์ ๋ ํธ์ถ๋๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๋๋ค. ๋ ์ง ๋๋ ์๊ฐ์ ํด๋ฆญํ์ ๋ ์ฆ๊ฐ์ ์ธ ์ก์ ์ ์ํํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ํด๋น ์ด๋ฒคํธ๋ฅผ ์ด์ฉํ๋ฉด ์๋ก์ด ์ผ์ ์ถ๊ฐ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.
var calendar = new FullCalendar.Calendar(document.getElementById('calendar'), {
initialView: 'dayGridMonth',
dateClick: function(info) {
alert('ํด๋ฆญํ ๋ ์ง: ' + info.dateStr); // ํด๋ฆญํ ๋ ์ง ํ์
}
});
calendar.render();
// ํด๋ฆญํ ๋ ์์ ์๋ก์ด ์ผ์ ์ถ๊ฐํ๊ธฐ
var calendar = new FullCalendar.Calendar(document.getElementById('calendar'), {
initialView: 'dayGridMonth',
events: [], // ์ด๊ธฐ์๋ ์ผ์ ์์
dateClick: function(info) {
calendar.addEvent({
title: '์๋ก์ด ์ผ์ ',
start: info.dateStr,
allDay: true
});
}
});
calendar.render();
๋งค๊ฐ๋ณ์ | ์ค๋ช |
info.date | ํด๋ฆญํ ๋ ์ง์ Date ๊ฐ์ฒด |
info.dateStr | YYYY-MM-DD ํ์์ ๋ฌธ์์ด ๋ ์ง |
info.allDay | ํด๋ฆญํ ๊ณณ์ด ์ข ์ผ(all-day) ์์ญ์ธ์ง ์ฌ๋ถ |
info.jsEvent | JavaScript์ ๋ง์ฐ์ค ์ด๋ฒคํธ ๊ฐ์ฒด (ํด๋ฆญ ์์น ๋ฑ) |
info.view | ํ์ฌ ์บ๋ฆฐ๋์ ๋ทฐ ์ ๋ณด (์: dayGridMonth, timeGridWeek) |
@Junesker
๋๊ธ