FullCalendar用來做日程管理功能非常強大,但是唯一不足的地方是沒有將中國農歷歷法加進去,今天我將結合實例和大家分享如何將中國農歷中的節氣和節日整合到FullCalendar中,從而增強其實用性。
HTML首先是要載入jQuery庫和fullcalendar插件。
<script src='js/jquery-1.9.1.min.js'></script>
<script src='js/fullcalendar.min.js'></script>
然後在body中,建立日歷容器div#calendar。
<div id="calendar"></div>
使用jQuery調用fullcalendar插件,方法如下,值得一提的是events數據源來自json.php,這個PHP文件負責讀取數據並返回json格式的日程安排數據給前端。
$(function() {
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
selectable: true,
events: 'json.php' //數據源
});
});
以上代碼就可以展示一個日歷界面,但是需要加入農歷,則需要將農歷算法代碼整合到fullCalendar中,並且需要將fullCalendar.js中的代碼稍微改動下,以下是網友@太空飛豬以及/可愛/玫瑰提供的中國農歷算法javascript版,再此一並感謝!
function RunGLNL() {
var today = new Date();
var d = new Array("周日", "周一", "周二", "周三", "周四", "周五", "周六");
var DDDD = d[today.getDay()];
DDDD = DDDD + " " + (CnDateofDateStr(today)); //顯示農歷
DDDD = DDDD + SolarTerm(today); //顯示二十四節氣
document.write(DDDD);
}
function DaysNumberofDate(DateGL) {
return parseInt((Date.parse(DateGL) - Date.parse(DateGL.getFullYear() + "/1/1")) / 86400000) + 1;
}
function CnDateofDate(DateGL) {
var CnData = new Array(
0x16, 0x2a, 0xda, 0x00, 0x83, 0x49, 0xb6, 0x05, 0x0e, 0x64, 0xbb, 0x00, 0x19, 0xb2, 0x5b, 0x00,
0x87, 0x6a, 0x57, 0x04, 0x12, 0x75, 0x2b, 0x00, 0x1d, 0xb6, 0x95, 0x00, 0x8a, 0xad, 0x55, 0x02,
0x15, 0x55, 0xaa, 0x00, 0x82, 0x55, 0x6c, 0x07, 0x0d, 0xc9, 0x76, 0x00, 0x17, 0x64, 0xb7, 0x00,
0x86, 0xe4, 0xae, 0x05, 0x11, 0xea, 0x56, 0x00, 0x1b, 0x6d, 0x2a, 0x00, 0x88, 0x5a, 0xaa, 0x04,
0x14, 0xad, 0x55, 0x00, 0x81, 0xaa, 0xd5, 0x09, 0x0b, 0x52, 0xea, 0x00, 0x16, 0xa9, 0x6d, 0x00,
0x84, 0xa9, 0x5d, 0x06, 0x0f, 0xd4, 0xae, 0x00, 0x1a, 0xea, 0x4d, 0x00, 0x87, 0xba, 0x55, 0x04
);
var CnMonth = new Array();
var CnMonthDays = new Array();
var CnBeginDay;
var LeapMonth;
var Bytes = new Array();
var I;
var CnMonthData;
var DaysCount;
var CnDaysCount;
var ResultMonth;
var ResultDay;
var yyyy = DateGL.getFullYear();
var mm = DateGL.getMonth() + 1;
var dd = DateGL.getDate();
if (yyyy < 100) yyyy += 1900;
if ((yyyy < 1997) || (yyyy > 2020)) {
return 0;
}
Bytes[0] = CnData[(yyyy - 1997) * 4];
Bytes[1] = CnData[(yyyy - 1997) * 4 + 1];
Bytes[2] = CnData[(yyyy - 1997) * 4 + 2];
Bytes[3] = CnData[(yyyy - 1997) * 4 + 3];
if ((Bytes[0] & 0x80) != 0) {
CnMonth[0] = 12;
}
else {
CnMonth[0] = 11;
}
CnBeginDay = (Bytes[0] & 0x7f);
CnMonthData = Bytes[1];
CnMonthData = CnMonthData << 8;
CnMonthData = CnMonthData | Bytes[2];
LeapMonth = Bytes[3];
for (I = 15; I >= 0; I--) {
CnMonthDays[15 - I] = 29;
if (((1 << I) & CnMonthData) != 0) {
CnMonthDays[15 - I]++;
}
if (CnMonth[15 - I] == LeapMonth) {
CnMonth[15 - I + 1] = -LeapMonth;
}
else {
if (CnMonth[15 - I] < 0) {
CnMonth[15 - I + 1] = -CnMonth[15 - I] + 1;
}
else {
CnMonth[15 - I + 1] = CnMonth[15 - I] + 1;
}
if (CnMonth[15 - I + 1] > 12) {
CnMonth[15 - I + 1] = 1;
}
}
}
DaysCount = DaysNumberofDate(DateGL) - 1;
if (DaysCount <= (CnMonthDays[0] - CnBeginDay)) {
if ((yyyy > 1901) && (CnDateofDate(new Date((yyyy - 1) + "/12/31")) < 0)) {
ResultMonth = -CnMonth[0];
}
else {
ResultMonth = CnMonth[0];
}
ResultDay = CnBeginDay + DaysCount;
}
else {
CnDaysCount = CnMonthDays[0] - CnBeginDay;
I = 1;
while ((CnDaysCount < DaysCount) && (CnDaysCount + CnMonthDays[I] < DaysCount)) {
CnDaysCount += CnMonthDays[I];
I++;
}
ResultMonth = CnMonth[I];
ResultDay = DaysCount - CnDaysCount;
}
if (ResultMonth > 0) {
return ResultMonth * 100 + ResultDay;
}
else {
return ResultMonth * 100 - ResultDay;
}
}
function CnYearofDate(DateGL) {
var YYYY = DateGL.getFullYear();
var MM = DateGL.getMonth() + 1;
var CnMM = parseInt(Math.abs(CnDateofDate(DateGL)) / 100);
if (YYYY < 100) YYYY += 1900;
if (CnMM > MM) YYYY--;
YYYY -= 1864;
return CnEra(YYYY) + "年";
}
function CnMonthofDate(DateGL) {
var CnMonthStr = new Array("零", "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "臘");
var Month;
Month = parseInt(CnDateofDate(DateGL) / 100);
if (Month < 0) {
return "閏" + CnMonthStr[-Month] + "月";
}
else {
return CnMonthStr[Month] + "月";
}
}
function CnDayofDate(DateGL) {
var CnDayStr = new Array("零",
"初一", "初二", "初三", "初四", "初五",
"初六", "初七", "初八", "初九", "初十",
"十一", "十二", "十三", "十四", "十五",
"十六", "十七", "十八", "十九", "二十",
"廿一", "廿二", "廿三", "廿四", "廿五",
"廿六", "廿七", "廿八", "廿九", "三十");
var Day;
Day = (Math.abs(CnDateofDate(DateGL))) % 100;
//hanlichen mod
if ("初一" == CnDayStr[Day]) {
// alert(SolarTerm(DateGL));
return CnMonthofDate(DateGL);
} else {
if (SolarTerm(DateGL) != "") {
return SolarTerm(DateGL);
} else {
return CnDayStr[Day];
}
}
}
function DaysNumberofMonth(DateGL) {
var MM1 = DateGL.getFullYear();
MM1 < 100 ? MM1 += 1900 : MM1;
var MM2 = MM1;
MM1 += "/" + (DateGL.getMonth() + 1);
MM2 += "/" + (DateGL.getMonth() + 2);
MM1 += "/1";
MM2 += "/1";
return parseInt((Date.parse(MM2) - Date.parse(MM1)) / 86400000);
}
function CnEra(YYYY) {
var Tiangan = new Array("甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸");
var Dizhi = new Array("子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥");
return Tiangan[YYYY % 10] + Dizhi[YYYY % 12];
}
function CnDateofDateStr(DateGL) {
if (CnMonthofDate(DateGL) == "零月") return " 請調整您的計算機日期!";
else return "農歷" + CnYearofDate(DateGL) + " " + CnMonthofDate(DateGL) + CnDayofDate(DateGL);
}
function SolarTerm(DateGL) {
var SolarTermStr = new Array(
"小寒", "大寒", "立春", "雨水", "驚蟄", "春分",
"清明", "谷雨", "立夏", "小滿", "芒種", "夏至",
"小暑", "大暑", "立秋", "處暑", "白露", "秋分",
"寒露", "霜降", "立冬", "小雪", "大雪", "冬至");
var DifferenceInMonth = new Array(
1272060, 1275495, 1281180, 1289445, 1299225, 1310355,
1321560, 1333035, 1342770, 1350855, 1356420, 1359045,
1358580, 1355055, 1348695, 1340040, 1329630, 1318455,
1306935, 1297380, 1286865, 1277730, 1274550, 1271556);
var DifferenceInYear = 31556926;
var BeginTime = new Date(1901 / 1 / 1);
BeginTime.setTime(947120460000);
for (; DateGL.getFullYear() < BeginTime.getFullYear();) {
BeginTime.setTime(BeginTime.getTime() - DifferenceInYear * 1000);
}
for (; DateGL.getFullYear() > BeginTime.getFullYear();) {
BeginTime.setTime(BeginTime.getTime() + DifferenceInYear * 1000);
}
for (var M = 0; DateGL.getMonth() > BeginTime.getMonth(); M++) {
BeginTime.setTime(BeginTime.getTime() + DifferenceInMonth[M] * 1000);
}
if (DateGL.getDate() > BeginTime.getDate()) {
BeginTime.setTime(BeginTime.getTime() + DifferenceInMonth[M] * 1000);
M++;
}
if (DateGL.getDate() > BeginTime.getDate()) {
BeginTime.setTime(BeginTime.getTime() + DifferenceInMonth[M] * 1000);
M == 23 ? M = 0 : M++;
}
var JQ = "";
if (DateGL.getDate() == BeginTime.getDate()) {
JQ += SolarTermStr[M];
}
return JQ;
}
將以上代碼直接復制粘貼到從官網下載的fullcalendar.js的最後。然後關鍵的是我們要對fullcalendar.js原有的代碼中程序日歷天數的代碼段做修改。
大概在第2385行開始,其中的if語句中的部分修改為以下代碼
if (showNumbers) {//月視圖天數數字顯示
var cnMonth = CnMonthofDate(date);//農歷月
var cnDay = CnDayofDate(date);//農歷日
var solar = SolarTerm(date);//農歷節氣
if(solar!='') cnDay=solar;
var cnMonDay = cnMonth+cnDay;
var holiday = '';
if(cnDay=='正月')
holiday = '春節';
switch(cnMonDay){
case '正月初一': holiday = '春節';break;
case '正月十五': holiday = '元宵';break;
case '五月初五': holiday = '端午';break;
case '八月十五': holiday = '中秋';break;
case '九月初九': holiday = '重陽';break;
case '臘月三十': holiday = '除夕';break;
}
html += "<div class='fc-day-number'><span class='solarday'>"+ cnDay+"</span>
<span class='holiday'>"+holiday+"</span>" + date.getDate() + "</div>";
}
以上代碼中,調用了農歷算法,計算出日歷中對應的農歷日期包括節氣,在這裡我們還做了特殊節日的處理,比如春節、端午、中秋等,然後我們要將農歷與公歷以及特殊節日同時顯示在fullcalendar中,這時就要修改css來控制使得公歷日期顯示在左上,農歷顯示在右上,特殊節日顯示在中間。
.fc-grid .fc-day-number{padding: 0 2px; position:relative}
.fc-grid .fc-day-number span.solarday{float:right;color:#999}
.fc-grid .fc-day-number span.holiday{position:absolute; left:40%}