JavaScriptのCanvasとrotate()関数を使って動く時計を描画してみる

まずHTML側は

  <body onload="init()">
    <canvas id="aaa" width="250" height="250" style="background-color:#ffffcc;"></canvas>
    <p id="now"></p>
    <p id="debug"></p>
  </body>

とした。ページ読込時にinit関数を呼び出して、そこでキャンバスの設定を行う予定。キャンバスのサイズは250×250の黄色。

init関数は以下のように。

<script>
  var ctx;
  var intervalID = NaN;

  function init() {
    var canvas = document.getElementById("aaa");
    ctx = canvas.getContext("2d");
    ctx.translate(125,125); //0,0を125,125へ移動

    clearInterval(intervalID);
    intervalID = setInterval(moveClock, 1000);

  }

グローバル変数でctxと、intervalID を宣言。
translate(125,125)関数によって、座標軸を右へ125下へ125行った場所を0,0に変更しますした。ここに時計の円を描く予定です。

setInterval関数を使って1000ミリ秒(1秒)ごとに、描画をするようにしました。moveClock関数で描画を実行します。

moveClock関数は以下のようにしました。

  function moveClock() {

    ctx.clearRect(-125, -125, 250, 250);//描画をいったん全部消す

    //時計板の円を描く
    ctx.strokeStyle = "#aaaaaa";
    ctx.fillStyle = "#00ffff";
    ctx.lineWidth = 5;
    ctx.beginPath();
    ctx.arc(0, 0, 100, 0, 2*Math.PI); //125,125を中心とする半径100の円
    ctx.closePath();
    ctx.stroke();

    //現在時刻を取得
    var now = new Date();
    h = now.getHours() % 12; //24時間表記から12時間表記へ
    m = now.getMinutes();
    s = now.getSeconds();


    document.getElementById("now").textContent = h + "時" + m + "分" + s + "秒";

    //短針は12時間で1回転、角度は360÷12= 30度ずつ回転する
    //長針は1時間で1回転、角度は360÷60= 6度ずつ回転する
    //秒針は1分で1回転、 〃

    var tansinAngle = 30/180*Math.PI * h; //短針の角度
    var chosinAngle = 6/180*Math.PI * m; //長針の角度
    var byosinAngle = 6/180*Math.PI * s; //秒針の角度


    document.getElementById("debug").textContent = "短針角度:" + 30*h + " 長針角度:" + 6*m + " 秒針角度: " + 6*s;


    ctx.save(); //状態を保持
    ctx.rotate(byosinAngle); //秒針ぶんだけ回転させて
    //秒針の描画
    ctx.strokeStyle = "#666666"; //線の色
    ctx.lineWidth = 1; //線の幅
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(0, -90);
    ctx.stroke();
    ctx.restore(); //状態をsaveのポイントに戻す


    ctx.save(); //状態を保持
    ctx.rotate(chosinAngle); //長針ぶんだけ回転させて
    //長針の描画
    ctx.strokeStyle = "#6666ff"; //線の色
    ctx.lineWidth = 3; //線の幅
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(0, -80);
    ctx.stroke();
    ctx.restore(); //状態をsaveのポイントに戻す



    ctx.save(); //状態を保持
    ctx.rotate(tansinAngle); //秒針ぶんだけ回転させて
    //秒針の描画
    ctx.strokeStyle = "#ff6666"; //線の色
    ctx.lineWidth = 5; //線の幅
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(0, 50);
    ctx.stroke();
    ctx.restore(); //状態をsaveのポイントに戻す

  }

時計の描画はこのようにしました。まず前回描画したものを消さないといけないので、ctx.clearRect(-125, -125, 250, 250)を行っています。これは座標(-125,-125)から幅250高さ250をクリアしています。

時計板の円を描くのは前回やったような感じ。

現在時刻を取得して、HTMLのpタグのnowに表示。

時計の「短針」「長針」「秒針」の角度をラジアンで求めています。

短針は1~12時で1週360度だから1時間あたり30度ずつ動くので30/180*Math.PI * h;で計算。
長針は1週360度だけど1分単位に6度ずつ動くので6/180*Math.PI * m;で計算。
同様に秒針は6/180*Math.PI * s;で計算。

まずまず秒針の描画。

ctx.save()関数で状態を保持しています。
rotate関数を使って座標をbyosinAngleだけ回転してからmoveToで円の中心(0,0)から、lineToで(0,-90)まで直線を描画。
描画が終われば、ctx.restore()で、saveした時点の座標に戻す。

これを、短針と長針も同じように描画。この関数が1000ミリ秒ごとに読み込まれるので、時計が動いているように針がまわってくれるようになりました。

CodePenの記述は以下のとおり。

See the Pen
canvas-myclock
by pghappy (@pghappy)
on CodePen.

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