공휴일 표시 및 툴팁 표시
달력에 공휴일(국가에서 정한 휴일)을 표시하기 위해서 공휴일 정보가 있는 배열을 객체에 추가합니다.
공휴일 정보는 날짜(date)와 공휴일 명(title)으로 구성합니다.
var options = {
showToday : true,
arHoliday : [{"date" : "3-1", "title" : "삼일절"}]
};
3월의 공휴일은 삼일절(3월 1일)입니다.
<style>에 공휴일(holiday)의 폰트 컬러를 추가합니다.
.calendar table > tbody > tr > td > span.holiday { color: red; }
스크립트의 배열(Array) 객체는 typeof로는 object로 나옵니다. 그래서 instanceof를 사용하여 생성 타입을 확인하거나 Array.isArray() 메서드를 사용하여 배열(Array)인지 확인합니다.
console.log(typeof options.arHoliday); --> object
console.log(options.arHoliday instanceof Array); --> true
console.log(Array.isArray(options.arHoliday)); --> true
배열이 전달되지 않거나 타입이 맞지 않으면 배열을 초기화합니다.
arHoliday = [];
함수에 공휴일 배열을 이용하여 달력의 날짜가 공휴일과 같으면 표시되도록 추가합니다.
function calendarHTML(date, options) {
// 데이터 검증
if (date == undefined || date == null || typeof date != "object" || !date instanceof Date) {
return "";
}
// 기본값 처리
if (options.showDay == undefined || options.showDay == null || typeof options.showDay != "boolean") {
options.showDay = true;
}
if (options.showFullDayName == undefined || options.showFullDayName == null || typeof options.showFullDayName != "boolean") {
options.showFullDayName = false;
}
if (options.showToday == undefined || options.showToday == null || typeof options.showToday != "boolean") {
options.showToday = true;
}
if (options.arHoliday == undefined || options.arHoliday == null || !Array.isArray(options.arHoliday)) {
options.arHoliday = [];
}
// 요일
var days = ["일", "월", "화", "수", "목", "금", "토"];
// 달력 연도
var calendarYear = date.getFullYear();
// 달력 월
var calendarMonth = date.getMonth() + 1;
// 달력 일
var calendarToday = date.getDate();
var monthLastDate = new Date(calendarYear, calendarMonth, 0);
// 달력 월의 마지막 일
var calendarMonthLastDate = monthLastDate.getDate();
var monthStartDay = new Date(calendarYear, date.getMonth(), 1);
// 달력 월의 시작 요일
var calendarMonthStartDay = monthStartDay.getDay();
// 주 카운트
var calendarWeekCount = Math.ceil((calendarMonthStartDay + calendarMonthLastDate) / 7);
// 오늘
var today = new Date();
var html = "";
html += "<table>";
if (options.showDay) {
html += "<thead><tr>";
for (var index = 0; index < days.length; index++) {
html += "<th";
if (index == 0) {
html += " class=\"sunday\"";
} else if (index == 6) {
html += " class=\"saturday\"";
}
html += ">" + days[index];
if (options.showFullDayName) {
html += "요일";
}
html += "</th>";
}
html += "</tr></thead>";
}
html += "<tbody>";
// 위치
var calendarPos = 0;
// 날짜
var calendarDay = 0;
for (var index1 = 0; index1 < calendarWeekCount; index1++) {
html += "<tr>";
for (var index2 = 0; index2 < 7; index2++) {
html += "<td>";
if (calendarMonthStartDay <= calendarPos && calendarDay < calendarMonthLastDate) {
calendarDay++;
html += "<span";
if (options.showToday && calendarYear == today.getFullYear() && calendarMonth == today.getMonth() + 1
&& calendarDay == today.getDate()) {
html += " class=\"today\"";
} else {
var holiday = false;
if (options.arHoliday.length > 0) {
// 공휴일
for (index3 = 0; index3 < options.arHoliday.length; index3++) {
var arHolidayDay = options.arHoliday[index3].date.split("-");
if (arHolidayDay.length == 2) {
if (parseInt(arHolidayDay[0]) == calendarMonth && parseInt(arHolidayDay[1]) == calendarDay) {
html += " class=\"holiday\" title=\"" + options.arHoliday[index3].title + "\"";
holiday = true;
break;
}
}
}
}
if (!holiday) {
if (index2 == 0) {
html += " class=\"sunday\"";
} else if (index2 == 6) {
html += " class=\"saturday\"";
}
}
}
html += ">" + calendarDay + "</span>";
}
html += "</td>";
calendarPos++;
}
html += "</tr>";
}
html += "</tbody>";
html += "</table>";
return html;
}
3월 1일(삼일절)이 붉은색으로 표시되는 것을 확인할 수 있습니다.
배열의 문제점
배열이 크기가 커지거나 검색 결과 뒤에 있으면 결과가 나올 때까지 배열을 for 문으로 검사하게 되어 속도가 느려지게 됩니다.
그래서 배열(Array)보다는 해시맵(HashMap)을 사용하는 것이 좋습니다.
해시맵(HashMap)이란
해시맵(HashMap)은 키(Key)와 값(Value)로 된 객체로 키(Key)를 해시코드(hashCode - 해시 알고리즘으로 생성된 정수)로 변환하여 해시 테이블(hash table - 키(Key)와 값(Value)으로 된 데이터를 저장하고 빠르게 데이터를 검색할 수 있는 자료 구조)에 저장하고 검색하여 값(Value)을 가져옵니다.
스크립트 내장 객체에는 해시맵(HashMap) 객체가 없습니다.
그렇지만 배열(Array)을 해시맵(HashMap)처럼 사용할 수 있습니다.
// 배열(Array)
var arHoliday = [];
// put
arHoliday[0] = {"date" : "3-1", "title" : "삼일절"}; --> 인덱스 사용
arHoliday.push({"date" : "3-1", "title" : "삼일절"}); --> push 메서드 사용
// get
console.log(arHoliday[0]); --> {date: '3-1', title: '삼일절'}
// 인덱스로 저장
console.log(arHoliday); --> 0: {date: '3-1', title: '삼일절'}
배열의 인덱스에 키(Key)를 적용하면 해시맵(HashMap) 객체처럼 사용할 수 있습니다.
// 해시맵(HashMap)
var hashmapHoliday = [];
// put
hashmapHoliday["3-1"] = {"title" : "삼일절"};
// get
console.log(hashmapHoliday["3-1"]); --> {title: '삼일절'}
// 키(Key)로 저장
console.log(hashmapHoliday); --> 3-1: {title: '삼일절'}
배열(Array)를 해시맵(HashMap)처럼 사용할 경우 length으로 배열의 크기를 알 수 없습니다.
그래서 Object.keyd() 메서드를 사용하여 키(Key)의 수를 얻을 수 있습니다.
// 배열(Array) 크기
console.log(options.arHoliday.length); --> 0
// 해시맵(HashMap) 크기
console.log(Object.keys(options.arHoliday).length); --> 1
함수를 해시맵(HashMap)을 사용하여 공휴일(holiday)을 표시하도록 변경하겠습니다.
// 해시맵(HashMap)
var hashmapHoliday = [];
hashmapHoliday["3-1"] = {"title" : "삼일절"};
var options = {
showFullDayName : true,
showToday : false,
arHoliday : hashmapHoliday
};
function calendarHTML(date, options) {
// 데이터 검증
if (date == undefined || date == null || typeof date != "object" || !date instanceof Date) {
return "";
}
// 기본값 처리
if (options.showDay == undefined || options.showDay == null || typeof options.showDay != "boolean") {
options.showDay = true;
}
if (options.showFullDayName == undefined || options.showFullDayName == null || typeof options.showFullDayName != "boolean") {
options.showFullDayName = false;
}
if (options.showToday == undefined || options.showToday == null || typeof options.showToday != "boolean") {
options.showToday = true;
}
if (options.arHoliday == undefined || options.arHoliday == null || !Array.isArray(options.arHoliday)) {
options.arHoliday = [];
}
// 요일
var days = ["일", "월", "화", "수", "목", "금", "토"];
// 달력 연도
var calendarYear = date.getFullYear();
// 달력 월
var calendarMonth = date.getMonth() + 1;
// 달력 일
var calendarToday = date.getDate();
var monthLastDate = new Date(calendarYear, calendarMonth, 0);
// 달력 월의 마지막 일
var calendarMonthLastDate = monthLastDate.getDate();
var monthStartDay = new Date(calendarYear, date.getMonth(), 1);
// 달력 월의 시작 요일
var calendarMonthStartDay = monthStartDay.getDay();
// 주 카운트
var calendarWeekCount = Math.ceil((calendarMonthStartDay + calendarMonthLastDate) / 7);
// 오늘
var today = new Date();
var html = "";
html += "<table>";
if (options.showDay) {
html += "<thead><tr>";
for (var index = 0; index < days.length; index++) {
html += "<th";
if (index == 0) {
html += " class=\"sunday\"";
} else if (index == 6) {
html += " class=\"saturday\"";
}
html += ">" + days[index];
if (options.showFullDayName) {
html += "요일";
}
html += "</th>";
}
html += "</tr></thead>";
}
html += "<tbody>";
// 위치
var calendarPos = 0;
// 날짜
var calendarDay = 0;
for (var index1 = 0; index1 < calendarWeekCount; index1++) {
html += "<tr>";
for (var index2 = 0; index2 < 7; index2++) {
html += "<td>";
if (calendarMonthStartDay <= calendarPos && calendarDay < calendarMonthLastDate) {
calendarDay++;
html += "<span";
if (options.showToday && calendarYear == today.getFullYear() && calendarMonth == today.getMonth() + 1
&& calendarDay == today.getDate()) {
html += " class=\"today\"";
} else {
var holiday = false;
if (Object.keys(options.arHoliday).length > 0) {
// 공휴일
var holidayInfo = options.arHoliday[calendarMonth + "-" + calendarDay];
if (holidayInfo != undefined && holidayInfo != null) {
html += " class=\"holiday\" title=\"" + holidayInfo.title + "\"";
holiday = true;
}
}
if (!holiday) {
if (index2 == 0) {
html += " class=\"sunday\"";
} else if (index2 == 6) {
html += " class=\"saturday\"";
}
}
}
html += ">" + calendarDay + "</span>";
}
html += "</td>";
calendarPos++;
}
html += "</tr>";
}
html += "</tbody>";
html += "</table>";
return html;
}
공휴일 내장 처리 및 임시 공휴일 처리
변경되지 않는 공휴일(holiday)을 함수에 내장시키고 Object.assign() 메서드를 사용하여 변경되거나 추가되게 처리하겠습니다. 그리고 임시 공휴일은 특정 연도만 있기 때문에 연도까지 포함하여 해시맵에서 검사 되게 처리합니다.
function calendarHTML(date, options) {
// 데이터 검증
if (date == undefined || date == null || typeof date != "object" || !date instanceof Date) {
return "";
}
// 기본값 처리
if (options.showDay == undefined || options.showDay == null || typeof options.showDay != "boolean") {
options.showDay = true;
}
if (options.showFullDayName == undefined || options.showFullDayName == null || typeof options.showFullDayName != "boolean") {
options.showFullDayName = false;
}
if (options.showToday == undefined || options.showToday == null || typeof options.showToday != "boolean") {
options.showToday = true;
}
// 공휴일
var hashmapHoliday = [];
hashmapHoliday["1-1"] = {"title" : "신정"};
hashmapHoliday["3-1"] = {"title" : "삼일절"};
hashmapHoliday["5-5"] = {"title" : "어린이날"};
hashmapHoliday["6-6"] = {"title" : "현충일"};
hashmapHoliday["8-15"] = {"title" : "광복절"};
hashmapHoliday["10-3"] = {"title" : "개천절"};
hashmapHoliday["10-9"] = {"title" : "한글날"};
hashmapHoliday["12-25"] = {"title" : "성탄절"};
if (options.arHoliday != undefined && options.arHoliday != null && Array.isArray(options.arHoliday)) {
Object.assign(hashmapHoliday, options.arHoliday);
}
// 요일
var days = ["일", "월", "화", "수", "목", "금", "토"];
// 달력 연도
var calendarYear = date.getFullYear();
// 달력 월
var calendarMonth = date.getMonth() + 1;
// 달력 일
var calendarToday = date.getDate();
var monthLastDate = new Date(calendarYear, calendarMonth, 0);
// 달력 월의 마지막 일
var calendarMonthLastDate = monthLastDate.getDate();
var monthStartDay = new Date(calendarYear, date.getMonth(), 1);
// 달력 월의 시작 요일
var calendarMonthStartDay = monthStartDay.getDay();
// 주 카운트
var calendarWeekCount = Math.ceil((calendarMonthStartDay + calendarMonthLastDate) / 7);
// 오늘
var today = new Date();
var html = "";
html += "<table>";
if (options.showDay) {
html += "<thead><tr>";
for (var index = 0; index < days.length; index++) {
html += "<th";
if (index == 0) {
html += " class=\"sunday\"";
} else if (index == 6) {
html += " class=\"saturday\"";
}
html += ">" + days[index];
if (options.showFullDayName) {
html += "요일";
}
html += "</th>";
}
html += "</tr></thead>";
}
html += "<tbody>";
// 위치
var calendarPos = 0;
// 날짜
var calendarDay = 0;
for (var index1 = 0; index1 < calendarWeekCount; index1++) {
html += "<tr>";
for (var index2 = 0; index2 < 7; index2++) {
html += "<td>";
if (calendarMonthStartDay <= calendarPos && calendarDay < calendarMonthLastDate) {
calendarDay++;
html += "<span";
if (options.showToday && calendarYear == today.getFullYear() && calendarMonth == today.getMonth() + 1
&& calendarDay == today.getDate()) {
html += " class=\"today\"";
} else {
var holiday = false;
if (Object.keys(hashmapHoliday).length > 0) {
// 공휴일(임시 공휴일 포함)
var holidayInfo = hashmapHoliday[calendarYear + "-" + calendarMonth + "-" + calendarDay];
if (holidayInfo == null) {
holidayInfo = hashmapHoliday[calendarMonth + "-" + calendarDay];
}
if (holidayInfo != undefined && holidayInfo != null) {
html += " class=\"holiday\" title=\"" + holidayInfo.title + "\"";
holiday = true;
}
}
if (!holiday) {
if (index2 == 0) {
html += " class=\"sunday\"";
} else if (index2 == 6) {
html += " class=\"saturday\"";
}
}
}
html += ">" + calendarDay + "</span>";
}
html += "</td>";
calendarPos++;
}
html += "</tr>";
}
html += "</tbody>";
html += "</table>";
return html;
}
2022년 3월 9일은 20대 대통령 선거일이었습니다. 그래서 임시 공휴일로 달력에서 공휴일로 표시되게 추가합니다.
function calendar(date) {
// 년월
$(".calendar-yearmonth").html(date.getFullYear() + "." + (date.getMonth() + 1));
// 임시 공휴일
var hashmapHoliday = [];
hashmapHoliday["2022-3-9"] = {"title" : "20대 대통령 선거일"};
var options = {
showFullDayName : true,
showToday : false,
arHoliday : hashmapHoliday
};
var html = calendarHTML(date, options);
$("#calendar").html(html);
}