NANIGE BLOG
2023.11.08
2023.11.08

jQueryでカレンダーを作る ~パート3~

これで最後になります。今回は祝日を適用させてカレンダーを完成させていきたいと思います。

前回までの内容

あわせて読みたい

jQueryでカレンダーを作る ~パート1~

あわせて読みたい

jQueryでカレンダーを作る ~パート2~

コード

まずはお急ぎの方のために完成形のコードを書きました。

ただ今回はこれだけでは祝日が適用されません。

祝日のデータは外部のcsvを参照しています。

$(document).ready(function () {

    //作成したいカレンダーの年月を入れる
    const year = 2000
    const month = 2


    $(".calendar").html(CreateCalendar(year, month))
    HolidayCheck()
});
function CreateCalendar(year, month) {
    const weeks = ['日', '月', '火', '水', '木', '金', '土']
    //取得する月の1日の情報
    const startDateOfMonth = new Date(year, month - 1, 1)
    //取得する月の最終日の情報
    const lastDateOfMonth = new Date(year, month, 0)
    //1日の曜日
    const startDay = startDateOfMonth.getDay()
    //取得する月のカレンダーの行数
    const Calendarline = CalendarLine(startDay, lastDateOfMonth.getDate())
    var CalendarElement = "<table>"
    //カレンダーの曜日の行を作成
    CalendarElement += "<tr>"
    for (let w = 0; w < 7; w++) {
        CalendarElement += "<td class = w" + w + ">" + weeks[w] + "</td>"
        if (w == 6) {
            CalendarElement += "</td>"
        }
    }
    var currentDate = 1;
    for (let line = 0; line < Calendarline; line++) {
        CalendarElement += "<tr>"
        for (let w = 0; w < 7; w++) {
            //カレンダーの一行目の場合は1日の曜日より前の枠は空欄にする
            //最終日を超えた場合の枠も空欄にする
            if ((line == 0 && w < startDay)) {
                CalendarElement += "<td></td>"

            }
            else if (currentDate > lastDateOfMonth.getDate()) {
                CalendarElement += "<td></td>"
                currentDate++
            }
            else {
                CalendarElement += '<td class = "w' + w + ' date" data-date ="'+ String(year)+ String(month)+ String(currentDate) +'">' + currentDate + '</td>'
                currentDate++
            }

        }
        CalendarElement += "</tr>"
    }
    return CalendarElement
}


// //1日の曜日とその月の日数を引数にしてその月の行を返す関数
function CalendarLine(startDay, lastDateOfMonth) {
    //(例)1日が(金)で最終日が31日の場合6行になる。→31日(日)
    if (startDay + lastDateOfMonth >= 35) {
        return 6;
    }
    //うるう年でない2月の1日が日曜日の場合
    else if (startDay + lastDateOfMonth <= 28) {
        return 4
    }
    //それ以外はすべて5行
    else {
        return 5
    }
}

//csvを読み込んで祝日を適用する
function HolidayCheck() {

    // CSVファイルのパス
    const csvFilePath = "syukujitsu.csv";

    $.ajax({
        type: "GET",
        url: csvFilePath,
        dataType: "text",
        success: function (csvData) {

            // CSVデータを行ごとに分割
            const lines = csvData.split('\n');

            // 各行のデータを処理
            lines.forEach(line => {
                const columns = line.split(',');
                const dateStr = columns[0]; // 年月日 (例)2023/10/9
                const holidayName = columns[1]; // 祝日名
                
                //2023/10/9 → 2023109 に変換
                const date = dateStr.replace(/\//g,"")
                $('.date').each(function () {
                    if ($(this).data('date') == date){
                        $(this).addClass('holiday')
                        $(this).append('<div class="holidayName">'+holidayName+'</div>')
                    }
                })
            });

        },
        error: function (xhr, status, error) {
            console.error('CSVファイルの読み込みエラー:', status, error);
        }
    });

}

.calendar{
    text-align: right;
}
td{
    width: 100px;
    height: 50px;
    position: relative;
    border-bottom: solid 1px rgb(202, 202, 202);
    font-size: 22px;
}
.w0{
    color: red;
}
.w6{
    color: rgb(55, 125, 231);
}
.holiday{
    color: red;
}
.holidayName{
    position: absolute;
    font-size: 10px;
    bottom: 0px;
    right: 0px;
}

仕組みを解説

今回は先ほども言ったように外部のcsvを参照して祝日を適用させています。

というのも、祝日とは決まった日付になるとは限りません

2021年にあったようにオリンピックに合わせて祝日を変更したりといったことも過去にはありました。

csvファイルをダウンロード

そういったことにも対応ができるように内閣府が出している祝日のcsvデータを今回は使うことにします。

下にリンクを貼っておきますので是非使ってみましょう

昭和30年(1955年)から令和6年(2024年)国民の祝日(csv形式:20KB)

※令和6年までのデータしかありませんので遠い未来のカレンダーには適用できません。

今回このcsvファイルは今書いているjsファイルと同じ階層に置いたものとして話を進めていきます。

画像ファイル7

csvファイルの中身

ではまずこのcsvファイルの中身をのぞいていきましょう。

画像ファイル1

中身をエクセルで見てみるとこのように年月日祝日の名称が入っているだけのシンプルなものになります。

「昔の祝日はこうだったんだぁ」と悦に浸っていましたが全く関係ないので進めていきましょう。

jQueryの内容

前回のコードに追加する関数があります。

今回はHolidayCheck()という名前の関数を作ります。

この関数はcsvを読み込んでカレンダーに祝日を適用させるということをします。

ですが・・・

まずは前回まで使っていたCreateCalendar()という関数に追記をしていきたいと思います。

前回までのカレンダーでは各カレンダーの日付(以降セルと呼びます。)には曜日を判定する情報しかありませんでした。

以下のように木曜日のセルにはw4というクラス名。土曜日のセルにはw6というクラス名を付与していました。

画像ファイル2

ですが、これではcsvから日付と祝日のデータを取得してもどのセルに適用すればよいかわかりません。

ということで今回は各セルにデータ属性を付与していきます。

データ属性とは標準のHTML要素に追加情報を格納するために使用するカスタム属性です

具体的な使い方としては

<div class="testclass" data-name="takeshi" data-age="secret"></div>

このように「data-」に続く形で自由に追加情報を付け足すことができます。

今回はdata-dateとして各セルに情報を付与していきます。

付与の仕方

各セルにはこのように追記していきます。

CalendarElement += '<td class = "w' + w + ' date" data-date ="'+ String(year)+ String(month)+ String(currentDate) +'">' + currentDate + '</td>'

こうすることでdata-dateには2020116のような数値が振られることになります。

今回はついでにdateというクラス名も追加しました。

後で使います。

イメージは以下の通りです。

画像ファイル5

HolidayCheck()関数

では準備が整ったところで祝日を適用させるHolidayCheck()関数を作っていきましょう

function HolidayCheck() {

    // CSVファイルのパス
    const csvFilePath = "syukujitsu.csv";

    $.ajax({
        type: "GET",
        url: csvFilePath,
        dataType: "text",
        success: function (csvData) {

            // CSVデータを行ごとに分割
            const lines = csvData.split('\n');

            // 各行のデータを処理
            lines.forEach(line => {
                const columns = line.split(',');
                const dateStr = columns[0]; // 年月日 (例)2023/10/9
                const holidayName = columns[1]; // 祝日名
                
                //2023/10/9 → 2023109 に変換
                const date = dateStr.replace(/\//g,"")
                $('.date').each(function () {
                    if ($(this).data('date') == date){
                        $(this).addClass('holiday')
                        $(this).append('<div class="holidayName">'+holidayName+'</div>')
                    }
                })
            });

        },
        error: function (xhr, status, error) {
            console.error('CSVファイルの読み込みエラー:', status, error);
        }
    });

}

今回はこの関数が呼ばれたら、

  1. csvファイルにアクセスする
  2. 情報を取り出す。
  3. 使いやすい形に変換する
  4. カレンダーに適用する

この順番で実行していきます。

まず6行目の$.ajaxという部分ですがこれはjQueryのライブラリの一部で非同期にサーバーと通信できるものです。

今回は隣に置いたcsvファイルに非同期でアクセスしているわけですね。

10行目のsuccessというところでアクセスに成功した後の記述をしています。

まず、csvデータを取得したあと

const lines = csvData.split('\r\n');

このように改行部分で分割して配列に代入しています。

こうすることでlinesの中身は以下のようになります。

['国民の祝日・休日月日,国民の祝日・休日名称', '1955/1/1,元日', '1955/1/15,成人の日', ・・・以下略

次に各行のデータを処理していきます。

linesという配列に対してforEach文で回していきます


lines.forEach(line => {
    const columns = line.split(',');
    const dateStr = columns[0]; // 年月日 (例)1955/1/1
    const holidayName = columns[1]; // 祝日名
    
    //1955/1/1 → 195511 に変換
    const date = dateStr.replace(/\//g,"")
    $('.date').each(function () {
        if ($(this).data('date') == date){
            $(this).addClass('holiday')
            $(this).append('<div class="holidayName">'+holidayName+'</div>')
        }
    })
});

一つずつ説明していきます。

まず3行目でカンマ区切りでcolomnsという配列に代入します。

colomnsには以下のようなデータが入ります。

[1955/1/1,元日]

これを4行目5行目でそれぞれdateStrholidayNameに代入していきます。

次に8行目で日付のデータを変換していきます。

先に作ったdata-date属性の値の形を思い出してください。

1955年1月1日であれば195511という値がセルに振られていたと思います。

ということで1955/1/1のスラッシュ(/)を取っ払いましょう。

以下のコードで変換できます

dateStr.replace(/\//g,"")

今回は正規表現を使って変換をしています。

正規表現についてはここでは詳しくやりませんが、

以下の本を片手に勉強していくと面白いと思います。

 

次に9行目のところから先ほど付与したクラス名date(各セル) に対してif文で条件分岐しながら祝日の情報を付与します。

ここではセルのdata-date属性の値と変換したcsvの値が合致した時に祝日の情報を増やしています。

具体的にクラス名holidayと新たにセルにdivタグの要素を追加しています。

divタグの要素には祝日名が入っています。

実際に1955年1月1日のセルであればどのような要素になるかというと

<td class="w6 date holiday" data-date="195511">
1
<div class="holidayName">元日</div>
</td>

このようになります。

これでjQueryの操作は終わりです。

cssを適用

最後にcssを当てていきます。

これはお好みで良いですが、holidayNameにあてるcssだけ注意しましょう。

position:absoluteにしないと日付の数字がずれてしまいます。

.calendar{
    text-align: right;
}
td{
    width: 100px;
    height: 50px;
    position: relative;
    border-bottom: solid 1px rgb(202, 202, 202);
    font-size: 22px;
}
.w0{
    color: red;
}
.w6{
    color: rgb(55, 125, 231);
}
.holiday{
    color: red;
}
.holidayName{
    position: absolute;
    font-size: 10px;
    bottom: 0px;
    right: 0px;
}

まとめ

これでカレンダーの完成です。

画像ファイル6

全3回に渡ってやってきましたが、まだまだカスタマイズできます。

年月を自由に変更できるようにしたり独自の休日を入れたりと今回の内容を踏まえて応用をすることもできます。

是非とも挑戦してみてください。

以上!!

ABOUT ME
たけし
元教育業界で講師を務め

未経験で転職を成功。

現在はWEBを中心に

SEとして活躍中

djangoやlaravelを主に扱う

保有資格:

・ AWS SAA(ソリューションアーキテクトアソシエイト)

・統計検定2級

・日商簿記2級
【解決方法】User Profile Serviceサービスによるサインインの処理に失敗しました。ユーザープロファイルを読み込めません
わかりやすく解説!ALBでEC2にアクセスする方法
意外に難しい…?クアラルンプール国際空港から市内への移動
ABOUT ME
たけし
元教育業界で講師を務め

未経験で転職を成功。

現在はWEBを中心に

SEとして活躍中

djangoやlaravelを主に扱う

保有資格:

・ AWS SAA(ソリューションアーキテクトアソシエイト)

・統計検定2級

・日商簿記2級