アナログ時計のスクリプトを作ろう

プロジェクトを作ったところで、アナログ時計の肝ともいえる部分、時計の針を描画するスクリプトを作ってみようと思います。

canvasタグの使い方

JavaScript では、画面の描画ができないと思われてきました。しかし最近のブラウザでは、<canvas>タグというHTML要素が追加されて、JavaScript でグラフィックの描画が行えるようになっています。そして、AIR の JavaScript でも、この<canvas>タグが利用できるのです。そのため、アナログ時計を作るのに、この<canvas>を利用すれば、Flash や Java アプレットの力を借りることなく自由に描画を行うことができるのです。

簡単に、<canvas> タグの使い方を確認してみましょう。まず、準備として、HTMLの中に、<canvas>タグを記述します。そして、JavaScript から、canvas 要素を取得し、続いて描画のためのコンテキストを取得ます。以下は、線を(左上から右下へ)1本描画するという簡単なサンプルです。

<html><body>
<canvas id="a_canvas"></canvas>
<script>
    // [1] canvas 要素を得る
    var a_canvas = document.getElementById("a_canvas");
    a_canvas.width  = 90;
    a_canvas.height = 90;
    // [2] コンテキストを得る
    var context = a_canvas.getContext("2d");
    // [3] 線の太さや色を設定
    context.lineWidth = 3;
    context.strokeStyle = "#ff0000";
    // [4] 描画
    context.beginPath();    // 描画開始
    context.moveTo(5,5);    // 開始点
    context.lineTo(85,85);  // 線を引く
    context.stroke();       // 描画終了
</script>
</body></html>

線を描画してみたところ

アナログ時計では、、長針と短針、そして秒針の3つの線を引くことで時間を表すことができますので、線の引き方さえわかれば、もう半分はできたと言っても良いでしょう。これを手軽に使えるように、drawLine() という関数を作ってみました。

// 線を描画する関数
function drawLine(context, x1, y1, x2, y2) {
    context.beginPath();
    context.moveTo(x1, y1);
    context.lineTo(x2, y2);
    context.stroke();
}

時計の針の描画

次に時計の針を描画してみたいと思います。その前に、ちょっと頭を柔らかくしておきましょう。だいたいの時計は正円です。そして、時計の針はその正円の中をくるくる回ります。

円の1周が360度ですので、時間が3時を指す時、短針は90度の位置にあり、6時なら180度、9時なら270度、12時で0度に戻るということが分かります。つまり、1時間は30度ですが、これは、次のような式であらわすことができます。

  短針の角度=時間 ÷ 12 × 360

この式が分かれば、長針や秒針も同じ式で書くことができることが分かるでしょう。

  長針の角度=分 ÷ 60 × 360
  秒針の角度=秒 ÷ 60 × 360

ここまで分かれば、あとは、この角度を線として描画するだけです。線を描画する場合、時計の中心から角度に応じた線を引きます。

そのために、JavaScript の Math.sin() と Math.cos() 関数を利用します。この関数は、三角関数と言って、引数に角度(単位はラジアン)に応じたサイン(正弦)、コサイン(余弦) を計算して返します。(※上の式で求めた角度の単位は「度」なので「ラジアン」に変換してから座標を計算します。)

以上のことを考えて、角度と長さを指定すると、円の中心から線を描画する関数を作ってみました。

// 中心座標の指定
var centerX    = 150;
var centerY    = 150;
var baseLength = 150;
// 角度や線の長さに応じて針を描画する関数
function drawLineRad(deg, length, color, width) {
    deg = deg - 90;                  // 90度左へ回転する
    var rad = (Math.PI / 180 * deg); // 度からラジアンに変換
    var len = baseLength * length;   // 線の長さを計算
    var x = centerX + Math.cos(rad) * len; // X座標を計算
    var y = centerY + Math.sin(rad) * len; // Y座標を計算
    context.lineWidth = width;
    context.strokeStyle = color;
    drawLine(context, centerX, centerY, x, y); // 線を描画
}

アナログ時計の完成

そして、以下のような背景画像を用意して、これと時計の針を重ね合わせることにします(背景画像の作り方はこの後紹介します)。

以下のリンク先に「clock-back01.png」を用意しましたので、「名前を付けてファイルへ保存」でデスクトップに「clock-back01.png」という名前で保存します。これをエクスプローラー上でコピーして、Aptana StudioのProjectパネルで、先ほど作ったプロジェクト「MyAnalogClock」を選択して、[Ctrl]+[V]で貼り付けます。

背景画像clock-back01.png

そして、Aptanaでファイル「MyAnalogClock.html」を以下のように書き換えます。

<html>
<body>
  <!-- 背景の画像を表示 -->
  <img src="clock-back01.png"
    style="position:fixed; top:0px; left:0px;"/>
  <!-- 時計の針を描画する canvas -->
  <canvas id="a_canvas"
    style="position:fixed; top:0px; left:0px;"/>

<script type="text/javascript">
    // 描画のための初期設定
    var clockWidth  = 300;
    var clockHeight = 300;
    var centerX = clockWidth / 2;
    var centerY = clockHeight / 2;
    var baseLength = clockWidth / 2;
    // canvas 要素を得る
    var a_canvas = document.getElementById("a_canvas");
    a_canvas.width = clockWidth;
    a_canvas.height = clockHeight;
    a_canvas.left = 0;
    a_canvas.top = 0;
    // コンテキストを得る
    var context = a_canvas.getContext("2d");
    // 毎秒時計を描画するように設定する
    var timerid = setInterval(drawClock, 1000);
    drawClock();
    // 時計の描画処理
    function drawClock(){
        // 一度針をクリアする
        context.clearRect(0,0,300,300);
        // 現在時刻を得る
        var now = new Date();
        var hour = now.getHours() % 12;
        var min  = now.getMinutes();
        var sec  = now.getSeconds();
        // 時計の針の角度を計算する
        hour = hour + min / 60; // 時は分に応じて少し進める
        var hour_deg = 360 * hour / 12;
        var min_deg  = 360 * min / 60;
        var sec_deg  = 360 * sec / 60;
        // 針を描画する
        drawLineRad(hour_deg, 0.5, "#000000", 7);
        drawLineRad(min_deg,  0.7, "#000000", 5);
        drawLineRad(sec_deg,  0.9, "#FF0000", 1);
    }
    // 角度や線の長さに応じて針を描画する関数
    function drawLineRad(deg, length, color, width) {
        deg = deg - 90; // 90度左へ回転する
        var rad = (Math.PI / 180 * deg); // 度からラジアンに変換
        var len = baseLength * length;
        var x = centerX + Math.cos(rad) * len;
        var y = centerY + Math.sin(rad) * len;
        context.lineWidth = width;
        context.strokeStyle = color;
        drawLine(context, centerX, centerY, x, y);
    }
    // 線を描画する関数
    function drawLine(context, x1, y1, x2, y2) {
        context.beginPath();
        context.moveTo(x1, y1);
        context.lineTo(x2, y2);
        context.stroke();
    }
</script>
</body></html>

スクリプトを記述したら、画面上部の実行ボタンをクリックしてみましょう。アナログ時計が動き出します。

画面上部の実行ボタンをクリックします

とりあえずアナログ時計が完成です。

アナログ時計が動きます