PC版ページのサイドバーに表示されているカレンダー。
これはライブドアブログの公式ブログパーツで、過去記事へのリンクがついています。

このカレンダーを利用して咲-Saki-キャラのデータを表示するブログパーツを作ったので、例によって備忘録を書いておきます。

calendar
こんな風に↑マウスカーソルを乗せた日附が誕生日であるキャラのデータを表示するだけの単純な仕掛けですが、確認とかに便利かなと思います。
別の誕生日にマウスを移動するか、閉じるボタンをクリックすると閉じます。
カレンダーのタイトル部分をクリックして他の月を選んでも同じように動作します。

問題点としては、過去記事へのリンクのポップアップがあると若干バッティングして見づらいということと、Edge で奇妙な影が出るということです。
また、誕生日カード表示用のスクリプトを拡張して作っているので、年齢の計算は今のところキャラについては「本編のインハイ期間中の八月一日」、実在の人物については「今年の誕生日当日」の年齢を出すようにしてあります。
その辺の仕様はカレンダー用に改めた方がいいかもしれません。


今回のブログパーツは jQuery の DOM操作で要素を作っているので、HTMLには何も加えていません。
CSS を<style>タグで、JavaScript を<script>タグで書いただけです。

CSS

以前書いた WHO_OF_BIRTHDAY と重複する部分は省略します。
  1. データを表示するボックスの領域です。
    #bpbp{
        display:none;
        position:absolute;
        z-index:99999;
        font-size:12px;
        top:0;left:0;
    }
    
  2. データを表示する半透明の黒いシートです。
    #birthday-pop{
        width:180px;height:180px;
        background:rgba(0,0,0,.7);color:snow;
        padding:1em;line-height: 1.3em;
        overflow-y:scroll;
    }
    
  3. ボックスを閉じるボタンのデザインです。
    .bp-close{
        position:absolute;
        top:0;right:0;
        color:white;background-color:red;
        font-weight:bolder;
        opacity:.4;
        transition:.3s;
        padding:2px;
        z-index:100000;
        text-align: center;
        cursor:pointer;
    }
    .bp-close::before{
        content:'×';
    }
    .bp-close:hover{
        opacity:1;
    }
    
  4. ライブドアブログのスタイルシートを上書きします。
    span.calendar{
        cursor:default!important;
    }
    
    span.calendarはテキストを表示している要素であるため、マウスオーバーするとmousepointer-textというカーソルが出てしまうのがちょっと嫌だったので。

JavaScript

こちらは WHO_OF_BIRTHDAY のクロージャの中に、式を一行と、イベントリスナーを二つ追加しています。
  1. クロージャの中で使う変数を一つ定義。
    var mm = ('0' + $('#calendarhead-2232723').text().replace(/\s|\t|<|>/g,'').slice(5,-1)).slice(-2);
    カレンダーの上部に表示されている「<< ○○年○月」というテキストから、月の数字だけを抜き出しています。
    もっとすっきりと書けなかったのか…

  2. 閉じるボタンを押したときのイベント処理です。
    $(document).on('click', '.bp-close', function(){
        $('#bpbp').fadeOut('fast',function(){
            $(this).remove()
        })
    });
    
    初め、$(document).on('click', '.bp-close', function(){・・・の部分は $('.bp-close').click(function(){・・・と書いていたんですが、まったくクリックに反応しなくてビビりました。
    本スクリプトのように、要素を後から生成する場合はon()メソッドの方を使うといいようです。

  3. カレンダーの数字にマウスオーバーした時のイベント処理です。
    $('.calendar').hover(function(e){
        var dd = ('0'+$(this).text().replace(/\s/g,'')).slice(-2);
    マウスオーバーした部分のカレンダーの数字を読み取り、一ケタの場合は頭に0をつけます。
        if(dd.length){
            var bd = mm + '/' + dd, cnt = 0,
            prof = parseInt(mm)+'月'+parseInt(dd)+'日生まれのキャラ(@人)<br /><br />';
    bdは、咲-Saki-データベースの書式に合せ、誕生日を「01/01」というふうに0埋め表記した文字列です。
    profは、表示するデータの HTMLコードの文字列です。
    初期値として見出し部分を入れておき、これに個別データをつけ足していく感じです。
    @は、後でヒットしたデータ件数(cnt)に置き換えます。
            for(var i in _Data){
                if(_Data[i][BIRTHDAY]==bd){
                    prof += _makeProf(_Data[i]);
                    cnt++;
                }
            }
    誕生日が一致したらそのキャラのデータを_makeProf()という関数に渡し、HTMLコードである返り値を順次profに書き足していきます。
            if(cnt){
                prof = prof.replace(/@/,cnt);
    cntという変数にはヒットしたデータ数がカウントされているので、これが 0 でなければデータを表示させる処理を行います。
    まず、先述のようにprofという文字列変数の中の@という文字を、cntに格納されている数値に置き換えます。
    なお、置き換えるのは最初にマッチした@だけなので、万が一キャラクターデータに@という文字が含まれていても、そちらには影響しません。
                if($('#bpbp'))$('#bpbp').remove();
    すでに別のデータが表示されていたらその要素ごと消去します。
                $(document.body).append(
                    '<div id="bpbp" class="side-gap kage4"><div class="bp-close"></div><img alt="[NO IMAGE]"class=gap-img id=bp-illust width=180><div id="birthday-pop" class="gap-cover" align="left">'+prof+'&nbsp;</div></div>'
                );
    <body>に HTMLコードを つけ加えます。
    初めはthis、つまりマウスオーバーしたカレンダーの日附要素(span.calendar)に append しようとしました。そうすれば座標計算が要らないので楽だと思って。
    でも、祖先要素であるdiv#calendarplugin-2232723overflow:hiddenが設定してあったのでポップアップが見切れてしまうという問題が起こり、やっぱり<body>にしました。
    最後の方に&nbsp;(半角スペース)を入れてあるのは、ブラウザによってはデータが一番下までスクロールしないケースがあったので、応急処置です。
                $('#bp-illust').attr('src', '(画像フォルダへのパス)/saki-'+mm+dd+'.png');
    背景に表示させるイラストの URL を<img>タグのsrc属性値としてセットします。
    これも上のappend()で一緒に設定できますが、まあこういう書き方もできるという一例として。
    なお、画像ファイルが存在しない時は alt属性の文字列[NO IMAGE]が表示されます。目的外使用ですが。
    参考までに、ここで生成されたポップアップ要素をHTMLコードとして見易く表示すると、
    <!-- 5月28日、はっちゃんの例 -->
    <div id="bpbp" class="side-gap kage4">
        <div class="bp-close"></div>
        <img src="(パス)/saki-0528.png" alt="[NO IMAGE]" class="gap-img" id="bp-illust" width="180" />
        <div id="birthday-pop" class="gap-cover" align="left">
            5月28日生まれのキャラ(1人)<br /><br />
            <span class="prof-h">薄墨 初美</span><br />
            <span class="prof-p">うすずみ はつみ</span><br />
            永水女子3年<br />
            139cm <br />
            18歳(シノハユ 2-3歳)<br />
            <span class="prof-cv">辻あゆみ</span><br />
            <span class="prof-memo">悪石島出身。水泳が得意。</span>
            <br /><br />&nbsp;
        </div>
    </div>
    こんな感じです。
    ただ、この段階では座標の設定が済んでおらず、CSS の初期設定もdisplay:none;で非表示にしてあるので、最後の仕上げ。
                var rect = this.getBoundingClientRect();
                $('#bpbp').css({
                    top: rect.top + window.pageYOffset + 'px',
                    left: rect.left + window.pageXOffset + 'px'
                }).fadeIn('fast');
            }
        }
    });
    座標と一緒に上のマップ引数にdisplay:blockを並べてもOKですが、jQuery のfadeIn()だとふわっと現れてカッコいいので、そちらを使いました。

  4. (参考)_makeProf()関数
    これは WHO_OF_BIRTHDAY の新バージョンですでに使っている関数です。
    こんな感じで HTML を書き出していますよ、ということで。
    function _makeProf(dataO){
        /*名前・ルビ生成*/
        	var name1 = dataO[NAME1], name2 = dataO[NAME2], name3 = dataO[NAME3], name4 = dataO[NAME4];
        var name, ruby;
        if(name1[0]=='@'){/*欧米人*/
            name = name2 + (name1.length && name2.length ? ' ':'') + name1.slice(1);
            ruby = name4 + (name3.length && name4.length ?	'・': '') + name3;
        }
        else{/*それ以外*/
            name = name1 + (name1.length && name2.length ? ' ':'') + name2;
            ruby = name3 + (name3.length && name4.length ? ' ':'') + name4;
        }
    /*身長・血液型*/
        var tandb = (dataO[TALL] == ''? '':dataO[TALL] + 'cm ') + (dataO[BLOOD] == ''? '':dataO[BLOOD] + '型');
        if(tandb.length) tandb += '<br>';
    /*年齢計算*/
        var old, gen;
        gen = (dataO[GENERATION]==''? 9999:parseInt(dataO[GENERATION]));
        if(gen==9999){  /*  データ無し(高齢キャラの場合、gen<0はあり得るので大数を与える)   */
            old = '';
        }
        else if(gen<100){   /* キャラ */
            var YY1 = 77, YY2 = 62;
            var bd = dataO[BIRTHDAY];
            var m = parseInt(bd.slice(0,2));
            var sy;
            var md = 100*m + parseInt(bd.slice(-2));
            md += md<402? 1200:0;/* 04/01以前なら早生まれ   */
            sy = (YY2-gen<0)? '':'(シノハユ '+ ((YY2-gen-1)<0?'':YY2-gen-1)+(md!=1601?'-'+(YY2 - gen):'') + '歳)';
            old = (YY1 - (gen+(md - 801>0? 1:0))) + '歳' + sy + '<br>';
        }
        else{   /*  実在の人物   */
            old = (yyyy - gen) + '歳<br>';
        }
    /*Ritz'sメモ生成*/
        var memo = dataO[MEMO];
        if(memo.length){
            memo = '<span class="prof-memo">' + memo + '</span><br>';
        }
    
        return '<span class="prof-h">' + name + '</span><br><span class="prof-p">' + ruby + '</span><br>'
                + (dataO[BELONG] ==''? '':dataO[BELONG] + '<br>')
                + tandb + old
                + (dataO[CV] ==''? '':'<span class="prof-cv">'+dataO[CV]+'</span><br>')
                + memo + '<br>';
    }

    【5月31日追記】

    いくつか改善しました。

    • 誕生日データが存在する日の数字が青っぽくなるようにしました。
    • マウスを少し動かすと同じデータが再表示されてチラつく不具合を修正しました。
    • ポップアップの閉じるボタンを大きくしました。
    • 実在する人物は、現時点(ページ読み込み時)での満年齢が表示されるようにしました。

    そしてバグ報告

    • 記事へのリンクがある日附で、データが存在するのに数字が青くならず、ポップアップが表示されないことがあります。
      ページを再表示すれば青くなりますが、原因を調査中です。

  5. 【6月1日追記】

    上記バグの原因の見当はつきました(たぶん)。

    日附要素にこちらで与えている「データが存在する」というクラスが、最初のページ読込時に公式ブログパーツのスクリプトで上書きされ、消えてしまっているようです。(二回目以降の読込ではキャッシュがあるので公式の方が先に生成されるため、妨げにならない)

    スクリプトの実行順序を入れ替えてみましたが、ダメでした。

    対処に時間がかかりそうです…


    【6月2日追記】

    機能追加

    • 領域外クリックでもポップアップが閉じるようにしました。

    【6月3日追記】

    上記バグは、ボタン切替という仕様に変更することで解決しました。
    若干ゴマカシっぽいですが…


    【6月6日追記】
    • 過去記事へのリンクと誕生日、両者の強調表示がバッティングしないよう、モードによって完全に分離しました。
    • 切替ボタンのデザインを少しカッコよくしました。
    • データ表示中にマウスを押下すると下の画像が見えるようにしました。
      ただし、画像がまだ全体の半分くらいしか用意できていませんが…
      コツコツ追加していく予定です。