1 | 年 |
1 | 月 |
1 | 日 |
1 | 時 |
1 | 分 |
1 | 秒 |
2進法の数を10進に換算します
211 | 210 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2048 | 1024 | 512 | 256 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
合計 | 0 |
2進法の数が、数の書き表しかたの1つなのだと直感的にわかるものとして考えました。
秒が動いているので、これが現在時刻だとわかります。年月日と比べ、デスクトップの時計と見比べて10進法の表現以外に表現方法があることを実感して欲しいのです。
加えて、整数の2進表現と10進表現の欄では月、日、時、分などの2進の数を入力することで、10進の数に直して確認することができるようにしました。
body内では年月日時分秒にそれぞれidをつけるだけです。tdタグでなくても構いません。
<table class="reg"> <tbody> <tr><td id="year">1 </td><td>年</td></tr> <tr><td id="month">1 </td><td>月</td></tr> <tr><td id="day">1 </td><td>日</td></tr> <tr><td id="hour">1 </td><td>時</td></tr> <tr><td id="min">1 </td><td>分</td></tr> <tr><td id="sec">1 </td><td>秒</td></tr> </tbody> </table>
html5ではscriptタグに type="text/javascript" を書かなくてもいいことになっています。
<script> //日時を取得し分解して所定の場所に表示する //setTimeoutで1秒ごとにくり返す function bclock() { var now = new Date(); var year = now.getFullYear().toString(2); var month = (now.getMonth()+1).toString(2); var day = now.getDate().toString(2); var hour = now.getHours().toString(2); var min = now.getMinutes().toString(2); var sec = now.getSeconds().toString(2); pyear.firstChild.nodeValue = year; pmonth.firstChild.nodeValue = month; pday.firstChild.nodeValue = day; phour.firstChild.nodeValue = hour; pmin.firstChild.nodeValue = min; psec.firstChild.nodeValue = sec; setTimeout('bclock()',1000); } //グローバル変数としてhtml読み込み中に宣言 var pyear,pmonth,pday,phour,pmin,psec; //load後要素を変数に入れ時計をスタートする function init(){ pyear = document.getElementById("year"); pmonth = document.getElementById("month"); pday = document.getElementById("day"); phour = document.getElementById("hour"); pmin = document.getElementById("min"); psec = document.getElementById("sec"); bclock(); } //load後初期化ルーチンを呼び出す window.onload = function() { init(); } </script>
.toString(2)は2進数にするメソッドです。
pyear.firstChild.nodeValue :pyearは.getElementById("year")で得られた要素でそのfirstChildはその中のテキストノードを表します。nodeValueはテキストノード内のテキストです。この例では初期値には1が入っています(id="year"のtd内に1とあることを指す)。ここに文字列が入っていないとエラーになります。
setTimeout('bclock()',1000) :1000ミリ秒後にbclock()(これは自分自身です)を呼ぶという指定です。厳密に考えると関数の処理の長さだけ1秒より多くかかりますから、何回かの繰り返しをすると2秒進んでしまうということも起こるはずですが、0,1なので気がつくことはないでしょう。気になるなら、500ぐらいに設定するのもよいですが、負荷がかかることですし実害がなければこれでいいでしょう。
javascriptはvarを付けない変数はグローバルになるので、init()の外のvar宣言はなくても動きますが、グローバルとして意識するために書いています。
init()内で var pyear などと宣言してしまうと、init()の外では参照できない変数になってしまいます。逆に変数に値を入れる命令文は外に出すとhtmlファイルが全部読み込まれる前に解釈される危険があります。その場合、id="year"の要素が読み込まれていないと.getElementById()が失敗して値が代入されません。そこでinit()という関数に入れ、次のwindow.onload = でファイルの読み込み後に実行されるようにします。html内のjavascriptでは定番の書き方です。
<table class="b12"> <tbody> <tr class="pw"> <!-- 2の累乗の行 --> <td>2<sup>11</sup></td><td>2<sup>10</sup></td> <td>2<sup>9</sup></td><td>2<sup>8</sup></td> <td>2<sup>7</sup></td><td>2<sup>6</sup></td> <td>2<sup>5</sup></td><td>2<sup>4</sup></td> <td>2<sup>3</sup></td><td>2<sup>2</sup></td> <td>2<sup>1</sup></td><td>2<sup>0</sup></td></tr> <tr id="tbtn"> <!-- 0,1の行 --> <td>0</td><td>0</td> <td>0</td><td>0</td> <td>0</td><td>0</td> <td>0</td><td>0</td> <td>0</td><td>0</td> <td>0</td><td>0</td></tr> <tr id="tflp"> <!-- 対応する10進数の行 --> <td class="k4">2048</td><td class="k4">1024</td> <td class="k3">512</td><td class="k3">256</td> <td class="k3">128</td><td>64</td> <td>32</td><td>16</td> <td>8</td><td>4</td> <td>2</td><td>1</td></tr> <tr class="sum"> <!-- 合計の行 --> <td colspan="6">合計</td> <td id="tsum" colspan="6">0</td> </tr> </tbody></table>
styleは適切に指定しておきます
.b12 { margin:1%; border:none; } .b12 td{ text-align:center; border:none; padding:2px 0; } #tbtn td{ font-size:150%; width:1.5em; height:2em; border:solid 1px #99f; padding:2px 0; cursor:pointer; } .k4{ font-size:75%; /*4桁のとき*/ } .k3{ font-size:85%; /*3桁のとき*/ } #tsum{ font-size:150%; text-align:center; color: #039; } .sum td{ border-top:solid 1px #99f; }
window.onload = function()のinit()にtinit()を加えます。
window.onload = function() { init(); tinit(); } var tbtns,tflps,tsum; var flpcolor = new Array("#ccc","#039"); //2進表現と10進表現の初期化 //td要素の配列をtbtns,tflpsに用意することと //イベントリスナーの取り付け function tinit() { var btnsrow = document.getElementById("tbtn"); tbtns = btnsrow.getElementsByTagName("td"); var flpsrow = document.getElementById("tflp"); tflps = flpsrow.getElementsByTagName("td"); for(var i=0; tbtns.length>i; i++){ tbtns[i].setAttribute("onclick","tflip(this)"); } tsum = document.getElementById("tsum"); tcalc(); } //1,0のトグルスイッチを処理後、10進法に変換 function tflip(tgt){ tgt.firstChild.nodeValue = 1-tgt.firstChild.nodeValue; tcalc(); } //10進法に変換して代入。そのビットの値の色指定もする function tcalc(){ var sum = 0; for(var i=0; tbtns.length>i; i++){ sum *=2; var bit = Number(tbtns[i].firstChild.nodeValue); sum += bit; tflps[i].setAttribute("style","color:"+flpcolor[bit]+";"); } tsum.firstChild.nodeValue = sum; }
btnsrow.getElementsByTagName("td") :btnsrowはid="tbtn"で得られたtrオブジェクト。その中のtdを配列としてgetします。
forでその配列の要素一つ一つにonclickのイベントリスナーをとりつけます。
このイベントリスナーをとりつける方法はいくつかありますが、一番平和な方法にしています。タグ内のid="hoge"とかsrc="hoge"などと同様に、onclick="hoge"として文字列を設定する方法です。イベントリスナーをとりつける方法はについては、いろいろ試しましたので、いつか解説したいと思います。
イベントリスナーはtflip()を呼びます。引数thisにはクリックされたtdを指すオブジェクトが代入されてきます。このtdの中の0,1の値を入れ替えるわけです。
この値が0であれば、1-0で1になります。
この値が1であれば、1-1で0になります。
このあとtcalc();を呼び出します。
tcalc()ではtbtns配列の0,1から10進数を計算します。Number()は値を数値にするためです。nodeValueで得た値は文字列なので、このままでは + 演算で文字の連結になってしまいます。
tcalc()ではさらに2048,1024,...の入っているtdにもstyle="hoge"の形でcssを設定しています。グローバルのArrayの値の0,1のどちらかの色に決まります。そのビットに相当する数が加えられる時に目立つ色にするという目的です。