LoginSignup
2

More than 1 year has passed since last update.

 年末なので、カレンダー作りでも。
 っていうか、前回お月様を描画するプログラムを作ったのは、月齢カレンダーが作りたかったからだったのでした。
 カレンダー売り場にも一つは必ずありますよね~☆
 日付の他に、その日の月齢とお月様の形が載っているアレです。

今月のカレンダー作る

 年末なんだから、来年のカレンダー作るんじゃないのかって話ですけどまあとりあえず、まずはこんなの。
カレンダー1.jpg

枠組みを作る

 カレンダーはテーブルで表示することにして、枠だけ先にHTML設定で作っておきます。
 あと、曜日を表示するとこは何年何月のカレンダーでも変わらないので、先に作っちゃいます。

#曜日欄作成
曜日記号=["日","月","火","水","木","金","土"]。 # 表示用の記号。
色指定=[赤色,黒色,黒色,黒色,黒色,黒色,青色,銀色]。
曜=空。
曜日記号を反復
    曜=曜に「<th id="曜日_{対象キー}">{対象}</th>」を追加。
ここまで。

#HTML設定
「<table id="暦">
<thead><tr><th colspan="7" id="年月"></th></tr></thead>
<thead id="曜日"><tr>{曜}</tr></thead>
<tbody id="日付"></tbody></table>」をDOM親要素へHTML設定。

#土日に色付ける
7回
    「#曜日_{回数-1}」の「色」に色指定[回数-1]をDOMスタイル設定。
ここまで。

 この段階で実行しても、日月火水木金土と、曜日が表示されるだけですけど、表示するための場所はできています。
 HTMLのidにふつーに全角文字使えるって、最近知った! よきよき~♪♪♪

日付の取得

 なでしこさんでは、今日で、今日の日付が取得出来ます(時間はです)

今日を表示。# 2021/12/21

 とゆうわけで、今日の日付から年と月を取出して、今月の最初の日付にします。
 ついでにこれを、カレンダーの年月表示欄に反映。

対象日=今日。
対象日を「/」で区切る。
対象年=それ[0]。対象月=それ[1]を整数変換。
対象日=「{対象年}/{対象月}/1」

#年と月を表示
「#年月」に「{対象年}年{対象月}月」をHTML設定。

暦データ作る

 今のところは日付表示欄に必要なデータは「日」だけなので、直接tdのhtml作りながら突っ込んでもいいかとも思うけど、後々表示したいデータが増えたり、カレンダーの形を変えたり出来るようにしたくなった時のために、暦データとゆう辞書型変数を先に作っておくことにする。

 曜日番号取得で、今月の一日が何曜日かを調べます。番号で取得されるので、週頭の日曜日から何日目に当たるかが分かります。
 1日より前の部分は空白にせず、よくある感じで薄く前月の日付を表示させたいです。
 ここで! なでしこには日付加算という超便利な素敵命令があります☆
 「+0/0/1」で1日後、「-0/0/1」1日前という感じで日付の加算減算ができて、月や年が変わるのも全部なでしこさんがやって下さいます。
 というわけで、今月の1日に曜日番号取得で得た日数をマイナスで日付加算してやれば、カレンダーの最初の日付が分かるし、ニシムクサムライとか閏年とか気にせずカウントアップしながら加算していけばいいだけ!

##暦データ
対象日=「{対象年}/{対象月}/1」
開始位置=対象日の曜日番号取得。
暦データ=空配列。C=0。
6回
  7回
    日数=C-開始位置。  # 開始日からの日数。
    正負記号=「+」。
    もし、(日数の符号)=「-1」ならば、正負記号は「-」。
  日数=日数の絶対値。 # v3.2.31以降必要
    日付=対象日に「{正負記号}0/0/{日数}」を日付加算。
    暦データ[C]は空辞書。
    暦データ[C]["日付"]=日付。
    日付=日付を『/』で区切る。
    暦データ[C]["年"]=日付[0]。
    暦データ[C]["月"]=日付[1]を整数変換。
    暦データ[C]["日"]=日付[2]を整数変換。
    C=C+1。
  ここまで。
  対象日に「{正負記号}0/0/{日数+1}」を日付加算。
  それを『/』で区切る。月=それ[1]。
  もし、月=対象月でなければ、抜ける。
ここまで。

 あと重要なのが、カレンダーの行数ですかね。
 今月のカレンダーは5週までなので7×5のマスを作れば良く、必要なデータも35日分なんですが、6週ある月も結構あります。っていうか来年の一月が既にしてそうです。あと、2月などは4週しか無いって場合もありますよね。
 それで・・・繰り返しは7×6回にしておいて、7日ごとに翌週最初の日付けをチェックして、もし月が変わっていたら繰り返しから抜けるようにしました。

暦データを日付欄に反映

##日付欄作成
日=空。
暦データを反復
    もし、対象キー%7=0ならば、日=日に「<tr>」を追加。
    日=日に「<td id="日付_{対象キー}">{対象["日"]}</td>」を追加。
    もし、対象キー%7=6ならば、日=日に「</tr>」を追加。
ここまで。
「#日付」に日をHTML設定。

 日付欄も土日に色付ける。
 HTML設定してからじゃないと、スタイル設定できません!(いや、当然っちゃ当然のことでしたが;;;)

##日付欄装飾
暦データを反復
    「#日付_{対象キー}」の「行揃え」に「中央」をDOMスタイル設定。
    もし、対象["月"]=対象月ならば、
      「#日付_{対象キー}」の「色」に色指定[対象キー%7]をDOMスタイル設定。
    違えば、
      「#日付_{対象キー}」の「色」に色指定[7]をDOMスタイル設定。
    ここまで。
ここまで。

 できました!
 対象日を変更して、ちゃんと来年1月が6週になることも確認☆

万年カレンダーにする

 今月のとか来年のとかケチなことは言わず、ずっと見れるようにする。
 もっとも、APIで月齢が取得出来る範囲は2005年~2050年とのことなので、その範囲内で。

 既に手動で対象日を変えれば違う年月のカレンダーが表示出来るようにはなっているので、変更出来るUIを作れば良いだけなんだよね。
 年と月の選択出来るセレクトボックスと、一月ごとと一年ごとに進めたり戻したり出来るボタンと、今月に戻ってこれるボタンくらいあればいいよね?

 HTMLにUI表示する場所を追加。

「<table id="暦">
<thead><tr><th colspan="7" id="年月"></th></tr></thead>
<thead><tr><th colspan="7" id="UI"></th></tr></thead>
<thead id="曜日"><tr>{曜}</tr></thead>
<tbody id="日付"></tbody></table>」をDOM親要素へHTML設定。

UI作成

 月は当然1~12、年は2005~2050の連番で配列にして、それのセレクトボックス作成すればOK☆

#セレクトボックスのアイテム
年リスト=空配列。
数を2005から2050まで繰り返す。年リスト[数-2005]=数。ここまで。
月リスト=空配列。
数を1から12まで繰り返す。月リスト[数-1]=数。ここまで。

#---UI作成-----
「#UI」にDOM親要素設定。
年セレクト=年リストのセレクトボックス作成。
「年」のラベル作成。
月セレクト=月リストのセレクトボックス作成。
「月 」のラベル作成。

前年ボタン=「≪」のボタン作成。
前月ボタン=「<」のボタン作成。
今月ボタン=「今月」のボタン作成。
翌月ボタン=「>」のボタン作成。
翌年ボタン=「≫」のボタン作成。

イベント

 ココでも日付加算が活躍しますよ!
 月なら「-0/1/0」「+0/1/0」、年なら「-1/0/0」「+1/0/0」で、一月前、一月後、1年前、1年後という計算が、簡単に出来ちゃうんです☆ 素晴らしい!

 あとは、それで計算した日付を新しい対象日としてカレンダーを作れば良いので、対象日から暦データを作って表示するまでの一連をカレンダー作成とゆう関数にして、呼び出すようにします。

#---イベント-----
今月ボタンをクリックした時には
    対象日=今日。
    対象日のカレンダー作成。
ここまで。
前月ボタンをクリックした時には
    対象日に「-0/1/0」を日付加算して、年チェック。
    もし、それがいいえでなければ、対象日はそれ。
    対象日のカレンダー作成。
ここまで。
翌月ボタンをクリックした時には
    対象日に「+0/1/0」を日付加算して、年チェック。
    もし、それがいいえでなければ、対象日はそれ。
    対象日のカレンダー作成。
ここまで。
前年ボタンをクリックした時には
    対象日に「-1/0/0」を日付加算して、年チェック。
    もし、それがいいえでなければ、対象日はそれ。
    対象日のカレンダー作成。
ここまで。
翌年ボタンをクリックした時には
    対象日に「+1/0/0」を日付加算して、年チェック。
    もし、それがいいえでなければ、対象日はそれ。
    対象日のカレンダー作成。
ここまで。

 セレクトボックスは、内容が変更された時にイベントを発生させたいですが、変更した時みたいな命令がないので、「onchange」にDOMイベント設定

年セレクトの「onchange」に「年月変更」をDOMイベント設定。
月セレクトの「onchange」に「年月変更」をDOMイベント設定。

●年月変更
    対象年=年セレクト["value"]。
    対象月=月セレクト["value"]。
    対象日=「{対象年}/{対象月}/1」
    対象日のカレンダー作成。
ここまで。

●(対象日の)年チェック
    対象日を「/」で区切る。対象年=それ[0]。
    もし、対象年が2005から2050の範囲内ならば、対象日で戻る。
    いいえで戻る。
ここまで。

 できました!

月齢を取得して描画

 前回やったとうりですが、APIのパラメーターを増やします。
 Version2は、一回のリクエストでデータを連続取得の出来る、loopintervalというパラメーターがあります。1日ごとの月齢を1ヶ月分一気に取得することも出来るんですね。
 前回は当日のお月様を表示するだけでしたが、この機能を使って月齢カレンダーを作りたいというのがあったので、Version2を使ってみていました。

月齢取得API=「https://mgpn.org/api/moon/v2position.cgi?」
URL=月齢取得API&「time={開始日}T12:00&lat={緯度}&lon={経度}&loop=42&interval=1440」。

 intervalは、60分*24時間=1440分。
 loopは、めんどくさいので42日間固定でまるっと取得することにする。
 これを、暦データに反映し、tdには、これまでの日付に加えて月を描画するキャンバスと月齢を表示するdivを用意して、最後に描画。

##日付欄作成
日=空。
暦データを反復
    C=対象キー。
    もし、対象キー%7=0ならば、日=日に「<tr>」を追加。
    日=日に「<td id="日付_{C}">
      <div id="日_{C}">{対象["日"]}</div>
      <canvas id="月描画_{C}" width="30" height="30"></canvas>
      <div id="月齢_{C}">{対象["月齢"]}</div>
    </td>」を追加。
    もし、対象キー%7=6ならば、日=日に「</tr>」を追加。
ここまで。
「#日付」に日をHTML設定。

##個別装飾
暦データを反復
    C=対象キー。
    「#日付_{C}」の「行揃え」に「中央」をDOMスタイル設定。
    もし、対象["月"]=対象月ならば、
        「#日付_{C}」の「色」に色指定["日付"][対象キー%7]をDOMスタイル設定。
        「#月齢_{C}」の「色」に色指定["月齢"][0]をDOMスタイル設定。
        月色は色指定["月"][0]。影色は色指定["月"][2]
    違えば、
        「#日付_{C}」の「色」に色指定["日付"][7]をDOMスタイル設定。
        「#月齢_{C}」の「色」に色指定["月齢"][1]をDOMスタイル設定。
        月色は色指定["月"][1]。影色は色指定["月"][3]
    ここまで。
     もし、対象["日付"]=今日ならば、「#日付_{C}」の「ボーダー」に「2px solid {赤色}」をDOMスタイル設定。
    「#日付_{C}」の「文字サイズ」に「16px」をDOMスタイル設定。
    「#月齢_{C}」の「文字サイズ」に「11.5px」をDOMスタイル設定。
    「#月描画_{C}」へ描画開始。
    [15,15]へ15で対象["月齢"]の月描画。
ここまで。

 今月じゃない部分は日付同様、月齢表示や月の描画色も灰色っぽく落とします。
 あと、ずっと忘れてたけど、今日の日付が分かるように、赤い枠で囲みます。
 その他のCSSも色々良きように整えて、完成! やったね!!(≧▽≦)
月齢カレンダー.jpg

動作確認

 プログラムの全文もこちらから(シンタックスハイライト付きで!)見れます。

 イイ感じです☆
 特にれすぽんしぶ的な?調整はしていないのですが、アプリページの方で開くと、ワタシのスマホでピッタリいい感じに表示されるので、ご満悦です♪♪♪

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2