Little Strange Software

スマホアプリの開発を行う LittleStrangeSoftware のブログです。

【JavaScript】アナログ時計、JavaScript部分のコード解説

f:id:little_strange:20210929234535p:plain

 

 どうも!LSSです!!

 

【JavaScript】アナログ時計を作ってみました

で、即興でアナログ時計を作ってみました。

 

画面を構成する、CSS部分についての解説はしていましたが、今回は肝心の「JavaScript」部分についての解説記事となります。

 

 

コード(script部分のみ)

<script>
tokeitm=setInterval(function(){
tokein=((Date.now()-(new Date()).getTimezoneOffset()*60000)%86400000)/1000;
tokeih.style.transform='rotate('+(((tokein%43200)/43200)*360-90)+'deg)';
tokeim.style.transform='rotate('+(((tokein%3600)/3600)*360-90)+'deg)';
tokeis.style.transform='rotate('+(((tokein%60)/60)*360-90)+'deg)';
},1000);
</script>

 

※HTML部分に、3時方向を向いた3本の針(IDはそれぞれ「tokeih」「tokeim」「tokeis」)があり、その針の回転角度を制御するスクリプトとなります。

 

 

コード解説(JavaScript部分)

やたらと ( ) が多くて、ややこしそうなコードになっていますねw

順にひも解いていきます。

 

setInterval

<script>
tokeitm=setInterval(function(){
tokein=((Date.now()-(new Date()).getTimezoneOffset()*60000)%86400000)/1000;
tokeih.style.transform='rotate('+(((tokein%43200)/43200)*360-90)+'deg)';
tokeim.style.transform='rotate('+(((tokein%3600)/3600)*360-90)+'deg)';
tokeis.style.transform='rotate('+(((tokein%60)/60)*360-90)+'deg)';
},1000);
</script>

 

今回のスクリプトは、1つの「setInterval」が全文を囲んでいます。

setIntervalは「一定時間ごとに、指定した関数を実行する」もので、

タイマーオブジェクト=setInterval(呼び出される関数,呼び出す間隔);

という書式で記述します。

呼び出す間隔の部分はミリ秒(1/1000秒)で指定します。

 

例えば、

a=setInterval('test()',100);

と書くと、別途用意した「test()」という関数を100ミリ秒(つまり0.1秒)毎に呼び出す事になります。

 

今回の場合は、別途関数を用意する事はせず、関数名を入れるところに、

function(){中略}

と、中略部分が数行に渡るコードを入れました。

 

この書き方だと、関数は関数名を持たず、即席で実行される内容を書く事ができます。
(関数名を持たない、という事は、他から呼び出して利用する事ができない、という事でもあります。今回の例ではその必要がないため、この書き方を採用しました。)

 

そして最後に、呼び出す間隔を「1000」としているので「1000ミリ秒(つまり1秒)」ごとに、中身が実行される事になります^^

 

時刻を秒で取得

さて、その呼び出される関数の内容は4行で書いていますが、まずその1行目から。

 

tokein=((Date.now()-(new Date()).getTimezoneOffset()*60000)%86400000)/1000;

の部分ですね。

 

ここでは、変数「tokein」に「日付が今日になってからの経過秒数」を代入しようとしています。

例えば、0時を回った直後、「0時0分3秒」なら「3」が入るようにしたいわけです。

 

( ) がたくさんありますが、わかりやすいよう色分け・改行すると、次のようになります。

 

tokein=
(
(Date.now()-(new Date()).getTimezoneOffset()*60000)
%86400000
)/1000;

 

Date.now()

「Date.now()」は「1970年1月1日 0時0分0秒からの経過ミリ秒」を数値で取り出す事ができます。

例えば、

<script>
document.write(Date.now());
</script>

というコードを実行すると

…という、凄い桁数の数値になりますw(約50年前からのミリ秒なので、さもありなん)

 

時刻を数値として取り扱えるので、かなり使い勝手がいいですね^^

 

そして、1日をミリ秒で言うと「86400000」ミリ秒(60*60*24*1000)となるので、
Date.now()%86400000
(%は余りを算出する演算子)は「今日になってからの経過ミリ秒」となります。

 

ところが…ここに落とし穴

 

Date.now()で取り出せる「1970年1月1日 0時0分0秒からの経過ミリ秒」というのは、実は「国際標準時」での計算結果となります。

「国際標準時」グリニッジ天文台(inイギリス)での時刻、ですね。

ja.wikipedia.org

 

そして、ご存知の通り、地球には「時差」というものがあります。

日本では兵庫県明石市の子午線において、太陽が真上に来る時刻を正午とする時刻が採用されていますが、これはグリニッジを中心とした国際標準時と「9時間の時間差」があります。

 

というわけで、日本、もしくは他の国で、それぞれ使用されている「時刻」にあわせるためには「時差」を考慮する必要が出てきます。

 

getTimezoneOffset()

JavaScriptで「時差」を取得するのは、

日付オブジェクト.getTimezoneOffset()

という関数によって「分」単位で取得できます。

「日付オブジェクト」を作成する必要がでてきますが、今回はカンタンに、

(new Date()).getTimezoneOffset()

と、即席で日付オブジェクトを利用する事にしました。

…で、単位が「分」なもので、Date.now()の単位「ミリ秒」にあわせるべく、「60000」を掛けてから引き算したものが、

Date.now()-(new Date()).getTimezoneOffset()*60000

という式になります^^

 

そして、先ほどと同様に、

(Date.now()-(new Date()).getTimezoneOffset()*60000)%86400000

とする事で「時差を考慮した、今日になってからの経過ミリ秒」にしたもの
tokein=((Date.now()-(new Date()).getTimezoneOffset()*60000)%86400000)/1000;
1000で割って「秒」としたものを、変数「tokein」に代入したんですね^^

 

注:ただし、この式では「5.457秒」のように小数点以下も含んだ秒数となります。
小数点以下を切り捨てるために、
tokein=Math.float(((Date.now()-(new Date()).getTimezoneOffset()*60000)%86400000)/1000);
と後から修正しました^^;;;

 

…一行目からだいぶ長くなっちゃいました^^;

3本の針の角度を決めるのに必要な「今日になってからの秒数」が取得できたので、あとはそれを元に針の角度をそれぞれ指定していく事になります。

 

時針の角度計算

tokeih.style.transform='rotate('+(((tokein%43200)/43200)*360-90)+'deg)';

↑この部分ですね。

JavaScript「tokeih.style.transform=〇〇」と書くのは、CSS「#tokeih{transform:〇〇;}」と書くのと同じ事を意味します。

 

ここで「43200」という数値を使っていますが、これは「12時間を秒単位にしたもの(12*60*60)」です。

時計の時針は12時間で一周(360度)するので、まず12時間で割った余りを
tokein%43200
で算出しています。

…次にそれをまた「43200」で割るのが、
(tokein%43200)/43200
です。

こうする事で「12時間ごとに区切った場合の、現在の区切り範囲内における現在時刻の比率が取得できる事になります。
(この数値は0以上1未満の範囲に必ず収まります。)

 

例えば、「日付が変わってから18時間経過(=18時)」だと、12で割った余り=6時間で、それを12で割ると「0.5」という比率って事になるわけです。

 

次にこれに、一周=360度なので360を掛けます。

((tokein%43200)/43200)*360

18時=0.5の例でいうと、0.5*360で180度、という事になります。
時計の真上(0時)から時計回りに180度回転した位置である、「6時」の位置に来るようにしたかったんですね^^

 

ただ、今回の「アナログ時計」では、最初の配置が「3時方向」となっているため、ここでもまた「90度」戻してあげないといけません。

((tokein%43200)/43200)*360-90

として90を引いた結果(18時だと90という数値になります)を、元の「3時方向」の角度から回転させてあげたいので、

tokeih.style.transform='rotate('+(((tokein%43200)/43200)*360-90)+'deg)';

としたところで完成です!

 

18時に この計算が実行されると、
tokeih.style.transform='rotate(90deg)';
と書くのと同じ事になり、これはCSS「#tokeih{transform:90deg;}」と指定するのと同じ結果になるため、「3時方向から時計回りに90度回転した位置」でめでたく「6時」の角度に時針が向くことになるんですね^^

 

分針、秒針も同様に。

あとの2行、
tokeim.style.transform='rotate('+(((tokein%3600)/3600)*360-90)+'deg)';
tokeis.style.transform='rotate('+(((tokein%60)/60)*360-90)+'deg)';
も、まったく同様の理屈で、区切りの単位を
「tokeim(分針)は一周3600秒、tokeis(秒針)は一周60秒」
として、「比率を算出→360を掛ける→90を引く」事で、それぞれの針の角度をJavaScriptから指定しています。

 

って、かなり長くなってしまいましたが…

上記のような内容を「1秒ごとに毎回呼び出して実行する」事で、3本の針の角度が設定されて、アナログ時計の動作が実現しています^^

 

 

あとがき

わずか数行のコードの解説に、かなりの文量を使ってしまいました^^;

 

あれですよ。
これはJavaScriptが難しいからじゃなくて、自分の説明が下手だからであって、
「LSSの説明文を嫌いになっても、JavaScriptを嫌いにならないでください!」
って言いたくなるところですwww

 

 

 

ってなとこで、今回はこのへんで!

次回もまた、よろしくお願いします^^