JavaScriptで動く!時計を作ってみよう

腕時計

今日は、自分の時計がパソコン上で動きだす!
現在時刻を取得して針を動かすスクリプトをかいたので
解説していきます。

いのえー
いのえー

こだわりは秒針の動き!
SEIKOロードマーベルの毎時36000振動の
超ハイビートの動きを再現しました。

まずは完成したものをどうぞ!

時計が動き出す

おそろしく長い記事です。YouTube動画も作成しましたが、やはりダラダラ長いのと、
あまりに視聴維持率が低かったため、限定公開にしています。

JavaScriptで動く腕時計の作りかた

JavaScriptで動く!時計を作ってみよう

ごく簡単なプログラミングです。
やったことない人でも理解できるように、専門用語は補足しつつ解説します。

用意するもの

用意するものは以下の通り。
順に説明します。

用意するもの
  • 正面からの時計の写真2枚
  • 切り抜きツール(標準のペイント3DでもOK)
  • エディター(標準のメモ帳でもOK)

正面からの時計の写真2枚

まずは正面から時計の写真を2枚撮りましょう。斜めの画像でも
めちゃくちゃ手間と時間をかければ可能でしょうが、今回はド正面でやっていきます。

どこか景色のいい場所で、背景がぼける感じで撮ってみても面白いと思います。
針のない時計の画像を作る際に便利なので、指してる時間を変えて2枚撮影してください。

切り抜きツール(標準のペイント3DでもOK)

撮影した写真から、使用する画像を作成するために
画像の切り抜きツールが必要です。私はフォトショップを使用しますが、
無料であればGIMP、あとは標準のペイント3Dでも(少し癖がありますが)できると思います。

切り抜きツール(いずれか)
  • フォトショップ
  • GIMP(ギンプ)
  • ペイント3D

エディター(標準のメモ帳でもOK)

プログラムを書いていくためのエディターが必要です。
コードをコピペしていくだけなら、メモ帳でも大丈夫ですよ。
イチから書いたり、少しアレンジを加える場合は専用のエディターが良いでしょう。
私は無料のVSコードを使っています。

画像の作成

では、撮影した写真を加工して、使用する画像を作っていきましょう。
作る画像は以下の通り。

作成する画像
  • 針のない文字盤画像
  • 針だけの画像(時針・分針・秒針)
  • 針を留めてるイメージの画像

最後の「針を留めてるイメージの画像」は無くてもOKです。
一番上に重ねることで”いい感じ”になったので。順に解説していきます。

針のない文字盤画像

まずはベースとなる文字盤の画像を作成します。
文字盤の画像に針が写っていても、その針は動きません。
針のない画像を作ってやる必要があります。

作り方は人それぞれ
  • ペイントで文字盤の同系色で針を塗りつぶす
  • 針の部分を覆うようにもう一枚の画像から切り出して貼る
  • 重ねて色味の違いを利用して合成する

針だけの画像(時針・分針・秒針)

次に写真から針を切り出します。切り出しには画像編集ソフトを使用します。
切り抜いた針は、画像サイズと中心を揃えて12時位置を指すようにしておきましょう。
切り抜いた部分が透過するようにPNG形式で保存します。

私はフォトショップを使用しましたが、無料ソフトであればGIMPが良いでしょう。
自由選択は出来ませんがウインドウズ10であれば標準の3Dペイントの
マジック選択でも何とかできると思います。

切り抜いた部分が透過するように
作成した画像はすべてPNG形式で保存しておきます。
今回は1000px四方の画像でやっていきます。

今作ったそれぞれの画像は最終的に重ねていくわけなんですが、
私はついでに、針の抑えの部分の画像も作りました。

一番上に、この動かない抑えの画像があるほうが自然な仕上がりになりました。
まぁこの辺りは好みですので、いろいろ試してみてください。

ページ上に配置

画像の準備が出来たら、ページ上に配置していきます。
手順は次の通り。順に解説します。

  • HTMLで画像を表示させる
  • CSSで画像を重ね合わせる

HTMLで表示させてみよう

HTMLの全体像はコチラ。

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <title>時計が動き出す</title>
</head>
<body>
    <div id="watch">
        <img id="image_case" class="watch_parts" src="case.png" >
        <img id="image_hour" class="watch_parts" src="hour.png" >
        <img id="image_minute" class="watch_parts" src="minute.png" >
        <img id="image_second" class="watch_parts" src="second.png" >
        <img id="image_osae" class="watch_parts" src="osae.png" >
    </div>
</body>
</html>
いのえー
いのえー

ウッ…と思ったら手順を分解してみましょ!

HTML記述の手順
  • 文章宣言や準備
  • ページ上に画像を表示させる
  • 画像を重ねる準備をする

順に解説していきます。

文章宣言や準備
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <title>時計が動き出す</title>
</head>
<body>
   
</body>
</html>

まずは文章宣言と準備です。時計とは全く関係ないのでコピペでOKですが
内容はザックリこんな感じ。

記述内容をザックリ解説
  • <!DOCTYPE HTML>
    →このドキュメントはHTML文章で書いてるよ
  • <html>
    →ここからHTMLが始まるよ
  • <head>
    →まずはこのページの情報を書くよ
  • <meta charset=”utf-8″>
    →utf-8という文字コードで書いているよ
  • <title>時計が動き出す</title>
    →ページのタイトルは「時計が動き出す」だよ

そして<body>と</body>の間には
実際にページ上に表示させたい情報を書いていきます!

ページ上に画像を表示させる
<body>
        <img src="case.png" >
        <img src="hour.png" >
        <img src="minute.png" >
        <img src="second.png" >
        <img src="osae.png" >
</body>

では用意した画像を、ページ上に表示させてみましょう。
画像を表示させるときはイメージタグを使います。

イメージタグは<img>で記述します。srcはsource属性。ソース…つまり源(みなもと)です。
表示させたい画像の源となるデータを指定しています。

これでページ上に画像が表示されますが、
まだ文字盤の画像や針の画像がバラバラに並んでいるはずです。

画像を重ねる準備をする
<body>
    <div id="watch">
        <img id="image_case" class="watch_parts" src="case.png" >
        <img id="image_hour" class="watch_parts" src="hour.png" >
        <img id="image_minute" class="watch_parts" src="minute.png" >
        <img id="image_second" class="watch_parts" src="second.png" >
        <img id="image_osae" class="watch_parts" src="osae.png" >
    </div>
</body>

バラバラに並んだ画像をCSSで重ねるわけですが
HTMLでは、まず重ねる準備をしましょう。

全ての画像をDIVで囲う

画像を重ねる時に必要なので、すべての画像をDIV要素で囲います。
DIV要素は特に意味のない箱のようなものと理解しておけばOKです。

今回はDIV要素がこれしかないので付ける必要はないですが
念のためDIVにIDを振っておきましょう。
全ての画像を囲ったDIVのIDをwatchとしました。

全ての画像にクラス名を付ける
 <img id="image_case" class="watch_parts" src="case.png" >
  <img id="image_hour" class="watch_parts" src="hour.png" >
  <img id="image_minute" class="watch_parts" src="minute.png" >
  <img id="image_second" class="watch_parts" src="second.png" >
  <img id="image_osae" class="watch_parts" src="osae.png" >

画像それぞれに同じクラス名を振っておきましょう。
今回はwaitchパーツとしてみました。

それぞれにID名を付ける

この針の画像を動かすときに必要なので
それぞれにidも振っておきます。
imageアンダーバー アワーみたいな感じで
それぞれに指定しました。

HTMLまとめ

HTMLはここまで。
この時点では、まだそれぞれの画像はバラバラです。

さて、お次はCSSで画像を重ねていきましょう!

CSSで画像を重ねてみよう

  <style>
        #watch {
            position: relative;
            width: 500px;
            height: 500px;
        }

        .watch_parts {
            position: absolute;
        }
    </style>

次はCSSで画像の表示位置を指定します。
やることは2点。

CSSの指定
  • 親要素のDIVにサイズ指定
  • 子要素のパーツ画像に絶対配置指定

順番に解説します。

親要素のDIVにサイズ指定
#watch {
            position: relative;
            width: 500px;
            height: 500px;
        }

まずは親要素のDIVにサイズを指定します。
#watchとは、HTMLで全ての画像を囲ってID名watchを付けたDIV要素を指します。
widthは幅、heightは高さで、今回は500px四方としました。

positionプロパティは、その名の通りポジションを決めるものです。
今回は必要ないですが、時計以外にも表示させたいものがある場合は
position:relative;として、相対配置させる必要があります。

相対配置とは…相手のことを考えた配置のこと。
他の要素に重ならないように配置されます。

子要素のパーツ画像に絶対配置指定

子要素とはクラス名watch_partsの画像たちです。
これらは重ねたいのでposition:absolute;を指定し絶対配置していきます。

絶対配置とは…絶対にココに配置するんだ!という強い意志のもと
他の要素のことを考えず、重なってでも決めた場所に配置します。

クラス名watch_partsのそれぞれの画像が、他の画像に関係なく
親要素のDIVに対して絶対的に配置されます。
その結果、同じ位置に重なり合って表示されました。

CSSまとめ

時計が動き出す

CSSはここまで。
この時点での表示はこんな感じです。
写真を重ねただけなのでもちろん動くはずもなく
12時位置をさしたままです。

それぞれの画像はPNG画像なので
透過されて一番下のimage_caseも表示されていますね。
針の画像は12時を指して重なり合っているので
少しわかりにくいかもしれません。

では、いよいよ時計を動かしてみましょう!

配置した画像を動かす

さて、ここからはJavaScriptで針の画像を動かしていきます。
手順はこんな感じです。

  • 関数起動の準備
  • 現在時刻を取得する
  • 針の画像を回転させる
  • 針が刻む頻度を指定する(振動数)

まず準備をしてから、下3つを実行する関数を作成するイメージです。
順番に解説します。

関数起動の準備

 <script>
        // ページ読み込み後から0.1秒毎に関数起動
        window.onload = function () {
            timerID = setInterval("getTime()", 100);
        };

まずはページを読み込んだあとに関数を起動させるように
window.onloadを書いています。準備のようなものだと思っておけばOKです。

次のsetInterval(セットインターバル)が重要で、
「何」を「どういう間隔(=インターバル)」で動かすか?という数値をセットしています。

ここでは「getTime関数」を「100ミリ秒毎」に起動させると指定しました。

1秒=1000ミリ秒。100ミリ秒は0.1秒です。

それでは「getTime関数」を作っていきましょう!

getTime関数を作る

ここからは「getTime関数」を作っていきます。
getTimeという名前は何でもOKなので、toKei関数でも、hariWoMawasu関数でもOKです。
この関数でやりたいことは以下

自作関数に組み込むもの
  • 現在時刻を取得する
  • 針の画像の角度を取得
  • 針の画像を回転させる
  • 針が刻む頻度を指定する(振動数)

順番に解説します。

いのえー
いのえー

いよいよ、時計の針を動かしていきますよー!

現在時刻を取得する
 // 針を動かす関数
        function getTime() {
        
 // 現在時刻の取得し変数へ    
        var mydate = new Date();
        
        var hour = mydate.getHours();
        var minute = mydate.getMinutes();
        var second = mydate.getSeconds();
        var mllisecond = mydate.getMilliseconds();

まずは現在時刻を取得しましょう。JavaScriptの組み込みオブジェクトである
Dateオブジェクトから取得します。

組み込みオブジェクトというのは、
JavaScriptがもともと用意している関数です。

まずは新しいDateオブジェクトを生成し
変数myDateに突っ込んでいます。ここに現在時刻に関する全ての情報が詰まっているイメージです。

ただこれでは、時針と分針、秒針を別々に動かすことができないので
それぞれの針の動きに必要なデータだけを分けて取得します。


        var hour = mydate.getHours();

一番上のhourで説明します。
左辺でhourという変数を用意して右辺を代入しています。

右辺は先ほど現在時刻の情報を突っ込んだ変数myDateからgetHours();
読んで字のごとくでアワーをゲットしています。

現在時刻と一概にいっても
何年何月何日何時何分何秒ナニナニナニまで全てが返ってくるので
変数hourには、「何時」にあたる部分だけを入れておきます。

同じ要領で変数minuteには分だけを、secondには秒だけを
mllisecondにはミリ秒の値だけを入れておきます。

針の画像の角度を取得
 // 現在時刻を表示

        var hdeg = (hour % 12) * (360 / 12);
        var mdeg = minute * (360 / 60);
        var sdeg = second * (360 / 60);

次に、ここまで取得した値を針の角度に変換していきます。

時針

時間の針はご存じの通り12時間で一周します。
一周は360度なので、1時間で360÷12で30度動くことが分かります。

例えば3時を指している短針の位置というのはスタートを12時位置とすると
30度×で90度になります。

時間を角度に変換するにあたって、問題がひとつ。
夜中の3時も、おやつの時間の午後3時も、腕時計では同じ角度なわけですが
Dateオブジェクトが用意しているgetHoursスクリプトでは
3時と15時というように、違う数字で返ってきてしまいます。

この時の対処法はいくつかあって、例えばif文を使って、
「もし値が13以上24以下だったら12を引いて返す」みたいな条件を書いてもいいのですが
今回はシンプルに算術演算子の%をつかって記述していきます。

算術演算子の%・・・割り算の余りを出してくれる演算子。

先ほどの15を12で割った余りは3。
そして、3を12で割ったあまりも3です。
※ちょっとイメージしにくいかもしれませんが
3÷12は0あまり3ですよね。

そんな感じで、割り算の余りは、3時も15時も
同じ「3」になることがわかりましたので
これを使って記述していきます。

        var hdeg = (hour % 12) * (360 / 12);

右辺では、ここまでの説明を式で表しています。
日本語にすると
現在時刻を12で割った値×一周を12で割った値 という感じです。

左辺ではhdegという変数を用意して、右辺で算出した値を代入しています。
※角度の単位がdegなので
時間の針の角度を示す変数をhdegとしました。

分針

続いて分針です。分針は1時間で一周します。
1時間は60分なので
1分では360÷60で6度動きます。

分単位には時間のように午前午後はないですから、
単純に、現在の分に、1分あたりに進む角度をかければ
現在の分を示す角度が得られます。

例えば今が3時半なら、30分×6度で180度ですね。
分針は12時位置をスタートして180度進んだ位置にいるはずです。

では先ほどと同じく、
今度はミニッツのデグなので変数をmdegとして
分針の角度を示す式を記述しておきます。

        var mdeg = minute * (360 / 60);
秒針

最後に秒針です。秒針も1分で一周するので分針と同じ要領です。
1分は60秒なので1秒では360÷60で6度動きます。
ですので、現在の秒を示す角度は
現在の秒に1秒当たりに進む6度をかけて求められます。

例えば今が3時30分10秒であれば
10秒×6度で60度です。
秒針は12時位置をスタートして60度進んだ位置にいるはずです。

というわけで秒針の角度を求める式も、
例によってセコンドのデグなので
変数sdegに入れておきます。

        var sdeg = second * (360 / 60);
針の画像を回転させる
 //短針の表示
        document.getElementById("image_hour").style.transform = "rotate(" + hdeg + "deg)";
        //長針の表示
        document.getElementById("image_minute").style.transform = "rotate(" + mdeg + "deg)";
        //秒針の表示
        document.getElementById("image_second").style.transform = "rotate(" + sdeg + "deg)";

ここでは取得した角度を使って、実際に針の画像を回転させていきます。

これにはrotateというプロパティを使います。
その名の通り回転させるためのものです。
右辺から解説します。

"rotate(" + hdeg + "deg)";

rotateは回転、hdegは先ほど時計の針の角度を入れた変数です。
最後の”deg”は角度の単位「度」を表しています。
これを実際に時計を表示させているHTML文章に反映させる必要があります。
それが左辺ですね。

document.getElementById("image_hour").style.transform

getElementByIdというのでdocument(=HTML文章)から
image_hour(=任意で振ったID)を持つ要素を引っ張り出しています。

分針、秒針も同様に指定すれば、針が動き出します。

針が刻む頻度を指定する(振動数)

続いて針が刻む頻度を指定しましょう。動いているとはいえ
時計好きならば、これでは納得はできないはずです。

動きが不自然な理由

この段階では、例えば時間の針は分針が一周すると1メモリ動きます。
もっと具体的に言うと、getHoursの値が3から4に変わった時に
時間の針が3から4に移ります。

3時59分までは3を指していて、4時になったら4を指します。
これで時計と言えるでしょうか。

また分針も同様で、3時30分59秒までは30分を指していて
00秒に戻ると31になります。

そして秒針も1秒で1メモリ進みます。これではクォーツ時計です。

決してクォーツ時計が悪いというわけではなくて、
今回素材として使っているのは
セイコーが誇る毎時36000振動のハイビートウォッチ「ロードマーベル」なわけなので
この動きはいただけませんね。

針の動きをリアルにする

現在、これらの針の画像は0.1秒おきに現在時刻を取得して針の表示角度を変更しています。
0.1秒たって何時何分何秒を取得して、それに合う角度を表示、
また0.1秒たって何時何分何秒を取得して、
それに合う角度を表示、というのを繰り返しています。

3時10分10秒も、3時59分59秒も何時の部分は3ですよね。
なので変数hourに入る値は3であって、
hdegに記述された式の計算結果はどちらも90度です。

本来、時間の針というのは
例えば3時には3を指していて3時半には3と4の間、
3時59分には限りなく4に近いけど、微妙にまだ
みたいな感じでじわじわじわじわと動くんですよね。

これを再現したいと思います。

角度を足していく

どうやって再現していくかというと、その都度角度を取得するのではなく、
角度を少しづつ足していく記述をします。

まずは時間の針ですね。

時間の針が1時間で動くのは
一周360度を12で割った30度ですよね。
その30度の中で、分の経過に合わせてじわじわ動いてほしいわけです。

今回は1分単位で動かしたいと思います。
時間の針が1分で進む角度は
現在の分÷60分の値を、1時間で進む30度に掛け合わせることで求められます。

例えば今が3時半だとすると
30分÷60分が2分の1、要は0.5ですよね。
そしてこの値に一周360度を12で割った30度をかけると
15度となります。30分経過すると時間の針は15度動くことがわかります。

まとめて記述するとこんな感じですね。

hdeg += (minute / 60) * (360 / 12);

先ほど用意した短針の角度を示す変数hdegにどんどん足しています。

+=というのは算数では習わない演算子ですが
元の値に足して、それを代入という意味です。

そして、取得した現在時刻の分の値を示す変数minutesを60分で割った値と、
一周360度を12で割った30度を掛け合わせています。

分針の動きも同じ要領です。
分針が1分間で動くのは一周360度を60で割った6度ですよね。
その6度の中で、秒の経過に合わせてじわじわ動いてほしいわけです。

今回は1秒単位で動かしたいと思います。
分針が1秒で進む角度は
現在の秒数÷60秒の値に1分で進む6度を掛け合わせることで求められます。

例えば今が3時30分30秒だとすると
30秒÷60秒が2分の1、要は0.5ですよね。
そしてこの値に一周360度を60で割った6度をかけると3度となります。
30秒経過すると分針は3度動くことがわかります。

まとめて記述するとこんな感じですね。

            mdeg += (second / 60) * (360 / 60);

先ほど用意した分針の角度を示す変数mdegに
取得した現在時刻の秒の値を示す変数secondを60秒で割った値と、
一周360度を60で割った6度を掛け合わせた値をどんどん加算し代入しています。

この時点では、短針長針はじわじわと動き
秒針は1秒毎にチクタク動くような状態です。

時計のスクリプトとしては、もう十分なレベルだとは
思いますが、このブログはプログラミングブログではなく腕時計チャンネルです。

毎時36000振動の超ハイビートムーブメントを搭載する
セイコーのロードマーベルの秒針がチクタク動いていては話にならないでしょう!
時計の振動数については、こちらの記事で詳しくどうぞ。

というわけで、ここからは秒針の動きを、
超ハイビート仕様にしていきます!

ハイビートの秒針を再現する

いよいよ大詰めです。36000振動のハイビートの秒針を再現しましょう。
要領は先ほどまでの時間の針や分針と同じなんですが、少し頭を使う必要があります。

まずは、Dateオブジェクトから取得できるミリ秒についてです。

ミリ秒というのは1000分の1秒、
つまり「0.なになになに」の部分が返ってきます。

それに対して、毎時36000振動の秒針の動きは
毎秒に直すと10振動、つまり0.1秒に1回動かしてやる必要があります。

現在時刻から取得できる単位がミリ秒に対して、
必要なのが100ミリ秒なのでmllisecondを100で割ることで求められます。

例えば500ミリ秒は100で割ることで
5”100ミリ秒”と表すことが出来ますよね。これはつまり0.5秒ということです。

次に秒針が0.1秒で動く角度ですが、
60秒で一周するわけですから1秒の10分の1の0.1秒単位では、
その10倍の600回刻んで一周することになります。

つまり360÷600で0.6ですね。秒針は0.1秒で0.6度動くことがわかります。

例えば今が3時30分30.5秒であれば
取得したミリ秒500を100で割った値に一周360度を600で割った値を掛けることで3度となります。
3時30分30秒から31秒にかけては6度動くわけなので
0.5秒時点で3度という計算結果が正しいことがわかりますね。

秒針の角度の変数であるsdegに加算し代入していきます。
実際の式がこちら。

 sdeg += (mllisecond / (1000/10)) * (360 / 600)

現在時刻からミリ秒を取得している変数mllisecondを100で割った100ミリ秒単位の数字を取得し、
それに一周360度を600で割った値を掛けたものを左辺のsdegにどんどん代入しています。

ここでポイントなるのは、この超ハイビート36000振動のロードマーベルは、
スムーズに動いて0.1秒で0.6度進むわけではなくて
あくまで0.1秒ごとに0.6度動くということです。

これを実現しているのは最初のほうで指定したsetIntervalです。
セットインターバルでgetTime関数を100ミリ秒毎に起動させるというように指定しています。

 window.onload = function () {
            timerID = setInterval("getTime()", 100);
        };

これによって、
秒針の角度の変数であるSdegに0.6度を加算していく関数が0.1秒ごとに起動し、
ロードマーベルの36000振動の針の動きを再現しています。

ついでなんで、他の振動数の時計の秒針の動きを再現するための式も作りました。

28800振動の再現
 // 28800振動(ロレックス他)
        sdeg += (mllisecond / 125) * (360 / 480)

Rolexをはじめ多くの時計に採用されている28800振動の動きを再現する式です。

21600振動の再現
  // 21600振動(スピマスプロ・パテック)
        sdeg += (mllisecond / 166) * (360 / 360)

スピードマスタープロフェッショナルや昔のパテックフィリップなどに採用されている
21600振動の優雅なロービートの動きを再現する式です。

振動数変更の解説

最後に、どんな振動数でも対応できるように解説しておきます。
1秒(=1000ミリ秒)を、それぞれの振動数の時計が1秒あたりに刻む回数で割ることで
それぞれの振動数の時計の秒針が1回刻む時間を算出しています。

それとは別に一周360度を、それぞれの振動数の時計の秒針が1周するのに刻む回数で割ることで、
1刻み辺りに進む角度を求めています。

算出した2つの値を掛け合わせたものを、秒針の角度を示す変数に入れています。

まとめ

というわけで、完成です。
ついに50年前の手巻きのセイコーがWEB上で時を刻み始めました。

巻かなくてもとまらない、
常に現在時刻を取得し日差もない
サイバーロードマーベルの完成です。
お疲れさまでした!

YouTube動画でも解説しています。

腕時計オーバーホール業者ランキング
時計修理専門店CIEN(シエン)

CIENさんは、元ロレックスの技術者さんを始め、
メーカー出身者が揃う、まさに時計修理のプロ集団です。
見積もりは無料で、
作業を依頼しない場合にもキャンセル料は掛かりません。
見積もり依頼をすると、無料で梱包キットが届くので、
依頼したい時計を入れて送るだけです。

時計修理専門店WATCH_COMPANY

最後にご紹介するのはウォッチカンパニーさんです。
時計雑誌「パワーウォッチ」などでご存知の方も多いでしょう。
中古時計販売店からの依頼も請け負っている
大規模な修理業者さんです。
もちろん個人でも見積もり依頼できます。

腕時計
スポンサーリンク
ブログランキング
この記事が気に入ったらシェアしてくださいね
いのえーをフォローする
いのえー.jp

コメント

タイトルとURLをコピーしました