作る喜び
スポーツや学業で得意、不得意はつきものです。好きなもの、得意なものだけに傾注せずに幅広く知識や技量を習得しなさいと教育者は語ります。社会の仕組みがそのように作られているのならば、それもやむを得ないことでしょう。
オリンピックがたけなわです。強制された練習では世界一は難しいようです。苦しいけれど楽しいといった雰囲気がないと長続きしません。自由研究においても創作意欲、創る喜びを感じて欲しいものです。
先日、夏休み自由研究で絵日記を作るを発表しましたが、今回、改訂しましたので、第2弾としてお届けします。
改良点
最大の改良点は、再利用(リユース)にあります。ゴミを減らすことの一つに再利用があります。絵日記は当日、1回限りの利用は少なく、作成や読込みにおいて、複数日にまたがることが多く、このたびの改訂で読込みなどが改良されています。
再実行にはアプリのロードをし直すのが簡単ですが、システム全体に負荷をかけることになります。この場合、再利用の処理を考慮するとパフォーマンスが向上します。
絵日記描画概要
ここでは説明上、多くの画面が表示されます。クリックして動作させるには末尾の実行例画面を用います。
イベントと駆動処理
ブラウザがウェブサイトの読込み完了時に、日記のカレンダーを作成し、カレンダーの日付をクリックしたときに、指定された日記のページをめくる処理を設定します。また、別の日付の日記を見ることができるように前画面に戻る駆動処理を関連づけます。
ローカル環境における実行方法
サイト上で実行するコードは『サンプルコード』に示してありますが、右クリック-ページのソースを表示にて得る方法もあります。それから4行目のUPLOAD定数を”image/”;のように変更し、enikkiData.jsや画像ファイルを所定のところに用意して実行環境を作り上げます。
夏休みの自由研究で絵日記を作るを完全に理解してから第2弾に進まれますように。また、ローカル環境におけるJavaScriptを実行する際、『JAVAScriptがローカル環境で利用できるか』などの記事を参考にされるとよいでしょう。
手作りへの想い
毎日の天候を逐一、記録に残すことは簡単に見えて地道な努力が必要です。かつて、8月末日にまとめて新聞に載ったことがありました。今では気象庁やライブドアなどのサイトから過去の天気を無料でダウンロードすることができます。
公開されたAPIを組み込んで、天気予報を記事の中に埋め込むことは天気情報を取得する関数で取り上げました。割りとスムースにできた記憶がありますが、過去の天気をオンラインで取得することは難しそうなので将来の宿題にしました。
コードの説明
①1行、htmlタグの宣言。
②2行、別ファイルとして作成されたソースコード[enikkiData.js]を読み込む。
③4行、ローカル環境で動作させる場合は、UPLOAD定数を変更する。
④5~6行、描画位置の調整用。
⑤7行、夏休み開始日を定義する。7月14日ならば13と定義。
⑥9~10行、絵日記画像を早めにロードする。
⑦11行、ロード時に起動する関数を定義する。前画面に戻るボタンの押下でも起動。
⑧12~45行、関数の起動イベントが2種、引数を持つ。
⑨15行、再実行のとき、前画面を消去する。
⑩16~22行、横縦のグリッド線を表示、外側は太い線で。
⑪23~29行、日記作成済みなら升目を色付きでマーク。
⑫30~31行、7月と8月を区別する表示色を設定する。
⑬32~33行、日付番号を表示する。
⑭35~38行、所定の位置に7月、8月をピンク色で表示。
⑮39~40行、サンプル絵日記を透かし絵で描画する。
⑯41行、透過率を元に戻しておく。
⑰42~43行、初回の時、clickイベントリスナーを登録。
⑱46~70行、canvas clickイベント関数を定義, 指定された日記のページをめくる。
⑲47~51行、7行7列のマウスクリック位置の升目を特定する。
⑳52~54行、夏休み期間外を無効にし、日記表示日を通算番号に変換
2157~69行、絵日記を表示する。この行で前表示をクリアする。
2260行、天候データを作成する。
2359~63行、月日と天候を表示する。
2464行、前画面に戻るメッセージに切り替える。
2565~66行、日記本文を表示する。
2667~69行、絵日記画像をロードし、500ミリ秒後に、描画されるように設定。
2772~74行、前画面に戻るボタンが押されたときに動作する処理
2876~78行、ロードが指定されて500ミリ秒後に絵日記画像が表示される。
2979~90行、スラッシュを改行コードに変換してテキストを表示する関数。
3091~93行、日付を画像ファイル名に変換する関数。
3196行、サイトがロードされるときに駆動する関数を取り付ける。
3299行、前画面に戻るボタンが押されたときに動作する関数を取り付ける。
33100行、canvasエリアを定義する。
サンプルコード
<html> <script src="https://aidesign.lolipop.jp/wp-content/uploads/2016/08/enikkiData.js" charset="Shift_JIS"></script> <script type="text/javascript" charset="Shift_JIS"> const UPLOAD="https://aidesign.lolipop.jp/wp-content/uploads/2016/08/"; //"image/"; const BX = 10; //描画位置規定値-x Medium-B.html const BY = 10; //描画位置規定値-y const z = 13; //7月14日 var ctx; //コンテキストを退避する var eImage = new Image(); //えにっき画像を早めにロードする eImage.src = UPLOAD+"asagao.png";//ファイル名を指定して画像をロードする function starting(regist){ //ロード時に起動する関数、カレンダーを作る var canvas = document.getElementById('calender'); //描画コンテキストの取得 if (canvas.getContext){ //サポートか ctx = canvas.getContext('2d'); //描画コンテキスト ctx.clearRect(0, 0, 720, 540); //画面をクリア for(var i=0; i<8; ++i){ //0 1 2 3 4 5 6 7 ctx.beginPath(); ctx.lineWidth = (i%7) ? 1 : 4; //外枠を太くする, 0/7の時は4, 1~6の時は1 ctx.moveTo(BX, BY+i*45); ctx.lineTo(BX+60*7, BY+i*45); //x-axis ctx.moveTo(BX+i*60, BY); ctx.lineTo(BX+i*60, BY+45*7); //y-axis ctx.stroke(); } for(i=0; i<49; ++i){ //49日間の日付を表示する var x = i % 7; //x方向位置 var y = Math.floor(i / 7); //y方向位置 if(enikki[i][0] != ""){ //天候が設定されているか ctx.fillStyle = "lightcyan"; //"aliceblue"; ctx.fillRect(BX+x*60+4, BY+y*45+3, 53, 40); } ctx.font = "32px 'MS Pゴシック'"; ctx.fillStyle = (i < (31-z)) ? "darkgreen": "cornflowerblue"; //7 or 8 var s = " " + String((i+z)%31+1); ctx.fillText(s.slice(-2), BX+x*60+14, BY+y*45+34);//日付番号を表示 } ctx.fillStyle = "pink"; ctx.font = "72px 'MS Pゴシック'"; //フォントの設定 ctx.fillText("7", BX+42, BY+117); //7月 ctx.fillText("8", BX+42, BY+252); //8月 ctx.globalAlpha = 0.3; //透過率を設定 ctx.drawImage(eImage, 110, 18, 285, 300); //サンプルえにっきを表示 ctx.globalAlpha = 1; //透過率を元に戻す if(regist==0) return; //初回ならば、clickイベントリスナーを登録する canvas.addEventListener( 'click', leafDiary, false ); // DOMレベル2 } } function leafDiary(e){ //canvas clickイベント関数を定義, 指定された日記のページをめくる var button = e.target.getBoundingClientRect(); var mouseX = e.clientX - button.left - BX; //60 var mouseY = e.clientY - button.top - BY; //45 var x = Math.floor(mouseX / 60); //7列 var y = Math.floor(mouseY / 45); //7行 if(x<0 || x>6) return; //夏休み期間外は無効、横 if(y<0 || y>6) return; //夏休み期間外は無効、縦 var w = y * 7 + x; //日記表示日を通算番号に変換 var v = (w < (31-z)) ? 7 : 8; //7 or 8 var d = (w+z)%31+1; //1~31 if(enikki[w][0] == "") alert(v+"月"+d+"日の日記は未完です。早めの完成を願っています。"); else{ //この処理で絵日記を表示する ctx.clearRect(0, 0, 720, 540); //以前の表示をクリア var make = " 天候:"+enikki[w][0]; //天候 ctx.fillStyle = "steelblue"; ctx.font = "28px 'MS 明朝'"; ctx.fillText(v+"月" + d + "日" + make, BX, BY+12); document.getElementById("bk").innerHTML="前画面に戻る"; ctx.font = "18px 'MS Pゴシック'"; msgOut(enikki[w][1], 0, 30); //改行処理で本文を出力 var imgFile = new Image(); //画像を早めにロードするための準備 imgFile.src = fileName(v*100+d); //日付からファイル名を作成, 画像をロードする setTimeout(function(){outPut(imgFile);}, 500);//読込み時間がかかるので500ミリ秒間、遅らせる } } function goBack(){ //前画面に戻るボタンが押されたときに動作する関数 document.getElementById('bk').innerHTML=' '; starting(0); //カレンダーを作る } function outPut(imgFile){ //読込みが指定されて500ミリ秒後に実行される ctx.drawImage(imgFile, 0, 65, imgFile.width, imgFile.height);//日記を表示 } function msgOut(msg, vx, vy){ //改行するfillText関数 var ary = ""; for(var m=l=0; l<msg.length; ++l){ //スラッシュ検出で改行する var c = msg.substr(l, 1); if(c != '/') ary += c; else{ //改行する ctx.fillText(ary, BX+vx, BY+vy+(m++)*20);//文章を1行ずつ表示 ary=""; //次の行に移行の準備 } } ctx.fillText(ary, BX+vx, BY+vy+m*20); //最後に残った文章 } function fileName(vd){ //指定日からファイル名を作成する関数 return UPLOAD+("0"+vd).slice(-4)+".png"; //"image/"+("0"+vd).slice(-4)+".png"; } </script> </head> <body onLoad="starting(1);"> <font size=4 color='maroon'>《自由研究-絵日記を作る2,2016-08-20》Ver 0.04,©Aidesign,2016</font><BR> <font color='cyan'>■</font><font color='orange'>の日付を指定して日記を表示。□の日付の日記は未完。</font> <button id="bk" onClick="goBack();"> </button><BR> <canvas id="calender" width="720" height="540" style="border: 0px blue solid"></canvas> </body> </html>
実行例
《自由研究-絵日記を作る2,2016-08-20》Ver 0.04,©Aidesign,2016
■の日付を指定して日記を表示。□の日付の日記は未完。