まめわざは、なるべく自社で開発するという方針から、細部まで自社で作成しております。
以前から企画しておりましたが、今後「まめわざの中身」シリーズとして、構成部品の内容を紹介してまいります。
自社開発のために非効率な部分もあるかと思いますが、少しでも役に立つ部分があれば幸いです。
今回は、その1としてJavascriptでカレンダーを描写する方法をご紹介いたします。
var dfn_holidays = {"2015/1/1":1};
var dfn_thead = ["日", "月", "火", "水", "木", "金", "土"];
var cal = function(year, month) {
//現在のタイムスタンプ
var now_ts = new Date().getTime();
//表示対象月の1日の曜日
var first_day = new Date(year, month - 1, 1).getDay();
var last_date = new Date(year, month, 0).getDate();
//thead
var thead = "<tr>";
for(var day = 0; day <= 6; day++) {
thead += "<td" + (day == 0 || day == 6 ? " class=\"" + (day == 0 ? "sun" : "sat") + "\"" : "") + ">" + dfn_thead[day] + "</td>";
}
thead += "</tr>";
//tbodyを生成
var tbody = "";
for(var row = 1, date = 0, fin = false; row <= 6; row++) {
if(fin) {
break;
}
tbody += "<tr>";
for(var day = 0; day <= 6; day++) {
var td = "";
var cls = [];
//その月の最初の日に達したらdateをカウント開始
if(date == 0 && day == first_day) {
date++;
}
//dateが存在する場合
if(date >= 1 && date <= last_date) {
td = date;
//クラスの設定:holiday
if(dfn_holidays[year + "/" + month + date]) {
cls.push("holiday");
}
//クラスの設定:past(過去の場合)
if(new Date(year, month - 1, date, 23, 59, 59).getTime() < now_ts) {
cls.push("past");
}
date++;
}
//dateが上限を超えた場合
if(date > last_date) {
fin = true;
}
//クラスの設定:sat(土曜日)・sun(日曜日)
if(day == 0) {
cls.push("sun");
} else if(day == 6) {
cls.push("sat");
}
tbody += "<td" + (cls.length > 0 ? " class=\"" + cls.join(" ") + "\"" : "") + ">" + td + "</td>";
}
tbody += "</tr>";
}
return "<table><caption>" + year + "/" + month + "</caption><thead>" + thead + "</thead><tbody>" + tbody + "</tbody></table>";
};
あるyear(4桁)とmonthに応じたカレンダーを生成する関数を定義します。
var cal = function(year, month) {};
戻り値はテーブルのHTMLですので、以下の利用例のようにご利用いただけます(利用例では<div id="test"></div>にカレンダーを設置しています)。
下記のように「6行のループの中で、日~土のループを実行してる」のが、この処理の骨格です。
6列のループは、カレンダーが最大6行にまでしかならない(6x7=42マスあれば、どのような月でも描写できる)ためです。
//↓6行のループを実行
for(var row = 1; row <= 6; row++) {
//曜日のループ(0:日~6:土)を実行
for(var day = 0; day <= 6; day++) {
}
}
次に、この骨格に日付表示を設置します。
まず、「いつから日付のカウントをはじめるか」の判定のために、対象月の最初の日(○月1日)の曜日を下記のように用意します。
var first_day = new Date(year, month - 1, 1).getDay();
new Date(年, 月, 日)としてDateオブジェクトを定義する際、関数の引数であるyearとmonth(ただしJavascriptのmonthは表示する月マイナス1になるのに注意)に合わせて「日=1」を指定し、getDay()で曜日番号を取得します。
同じく、「いつになったらカウントをやめるか」の判定のために、対象月の最後の日付を下記のように取得します。
var last_date = new Date(year, month, 0).getDate();
月に翌月(month=month - 1 + 1)、日に0を指定し、「次月の0日」を指定することで「当月の最終日」をgetDate()から取得します。
これらを使ってループを以下のようにします。
for(var row = 1, date = 0; row <= 6; row++) {
tbody += "<tr>";
for(var day = 0; day <= 6; day++) {
var td = "";
//その月の最初の日に達したらdateをカウント開始
if(date == 0 && day == first_day) {
date++;
}
if(date >= 1 && date <= last_date) {
td = date;
date++;
}
tbody += "<td>" + td + "</td>";
}
tbody += "</tr>";
}
dateは0からスタートし、初めにdayがfirst_dayになる日にdateのカウントをスタートします。
以降、last_dateに達するまでdateのカウントは続き、tdタグ内にdateを設置します。
尚、カレンダーは常に6行とは限らず4~5行の月もあるため、「date > last_date」となった時点で外側のrowのループを抜け出す処理を加えることでこれに対応できます。上のコードではfinというフラグを用いてこれを実行しています。
その他の部分は、全てクラスの設置です。下記のように3種類のクラスを別々に判定して設置しています。
最後に、下記のように曜日をループしてテーブルのヘッダを作成します。この際、0(日曜)~6(土曜)の変換用にdfn_theadを利用します。
必要に応じて、土曜・日曜にクラスを設定します。
ヘッダーが不要な場合は丸ごとカットして構いません。
//thead
var thead = "<tr>";
for(var day = 0; day <= 6; day++) {
thead += "<td" + (day == 0 || day == 6 ? " class=\"" + (day == 0 ? "sun" : "sat") + "\"" : "") + ">" + dfn_thead[day] + "</td>";
}
thead += "</tr>";