Garminウォッチフェイスの作成:アナログ時計

時針、分針、秒針を三角形のマークにしたアナログ時計。

目盛りは、時間を表すものを2ドット幅・長めにして描画。時間と時間の間は5等分にし、1ドット幅・短めに描画。
時分秒を表すのに、針形状ではなく3角形のマークのマークにし、頂点方向を外周に向けるように描画している。

一応、考えられるだけの手動最適化をしているが、全部の処理に約100msかかっている。ただこれでも初期バージョンの半分ぐらいの処理時間にはなったのだが。

using Toybox.WatchUi;
using Toybox.Graphics;
using Toybox.System;
using Toybox.Lang;
using Toybox.Math;

class sample1View extends WatchUi.WatchFace {

    var center;
    var pi2;		// Math.PI * 2.0

    function initialize() {
        WatchFace.initialize();
        pi2 = Math.PI * 2.0;
    }

    // Load your resources here
    function onLayout(dc) {
        center = [dc.getWidth()/2, dc.getHeight()/2];
    }

    // 角度の絶対値を使用し座標を生成しハッシュマークを表示する
    function drawHashMarks(dc) {
    	var vLong = center[0] - 10;
    	var vShort = center[0] - 5;
    	var aDel = Math.PI / 30.0;
    	for (var i = 0; i < 60; ++i) {
	    	var vAngle = aDel * i;
    		var vSin = Math.sin(vAngle);
    		var vCos = Math.cos(vAngle);
    		if (i % 5 == 0) {
				dc.setPenWidth(2);
				dc.drawLine(center[0] + center[0] * vSin, center[1] + center[0] * vCos,
					center[0] + vLong * vSin, center[1] + vLong * vCos);
    		}
    		else {
				dc.setPenWidth(1);
				dc.drawLine(center[0] + center[0] * vSin, center[1] + center[0] * vCos,
					center[0] + vShort * vSin, center[1] + vShort * vCos);
    		}
    	}
    }
    
    // 3角マークを、角度の絶対値で作成して表示
    function drawMark(dc, radius, angle, size) {
    	var vSin = Math.sin(angle);
    	var vCos = Math.cos(angle);
    	
    	var cPos = [center[0] + radius * vSin, center[1] - radius * vCos];
    	
    	var angle1 = angle + pi2 / 3.0;
    	var angle2 = angle + Math.PI * 4.0 / 3.0;

    	var vPoints = [
    		[cPos[0] + size * vSin, cPos[1] - size * vCos],
    		[cPos[0] + size * Math.sin(angle1), cPos[1] - size * Math.cos(angle1)],
    		[cPos[0] + size * Math.sin(angle2), cPos[1] - size * Math.cos(angle2)]
    	];
    	dc.fillPolygon(vPoints);
    }

    // 時分の針を表示
    function drawHMHand(dc) {
    	var wAngle = pi2 / 60.0;
        var clockTime = System.getClockTime();
        dc.setColor(Graphics.COLOR_RED, Graphics.COLOR_BLACK);
        drawMark(dc, center[0] * 0.83, ((clockTime.hour % 12) * 60 + clockTime.min) / 12.0 * wAngle, 12);
        dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
        drawMark(dc, center[0] * 0.85, clockTime.min * wAngle, 6);
        drawMark(dc, center[0] * 0.80, clockTime.sec * wAngle, 6);
    }

    // Update the view
    function onUpdate(dc) {
        dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
        dc.clear();
    	drawHashMarks(dc);
    	drawHMHand(dc);
    }
}

ちなみに、目盛りを描画する処理にHashMarksとつけたのだが、これはConnect IQのサンプルの目盛りを描画する関数にそう付けられていたから。時計の目盛りのことを英語名ではhash marksというのだろうか。

追記(1/14)

sin/cosの使用位置がx,yで逆だった。恥ずかしい。
ソースコードは面倒なので、修正しない予定。

コメント

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