前作ったものを1週間ほど使ってみて、いろいろと手直しをして、使い続けてもいいかなと思ったのがこちら。
変更点は次の通り
- 以前は右端にあった日の出、日の入りを示すゲージを円周に配置
これにより、その部分だけ24時間計見た異なものになった。 - 上記に合わせ、24時間計の部分を見やすく改良。
- 現在の時刻は赤枠の黄色線にした。
- 3,9,15,21時をわかりやすい色と線にした。
0,6,12,18時はそれぞれ90度位置になるため、現状のままでもわかりやすいのでそのまま - 24時間計の描画を、中のテキストの描画の後に行う。
テキストの描画領域は四角形で、その四角形の部分をバックグラウンド色で描画されてしまうため、描画する順番により、24時間計の線が一部欠けてしまう部分があったため。
- 日の出、日の入り時刻を表すテキストのフォントサイズを大きめにする。
見やすいものかどうかについては、実機で確認しないと分からない部分が多く、シミューレーターで見やすくても、実機では見づらいと感じたものが結構あった。
コードは以下の通り。
一応、コメントも入れてみた。
using Toybox.WatchUi;
using Toybox.Graphics;
using Toybox.System;
using Toybox.Lang;
using Toybox.Time;
using Toybox.Position;
class DigitalView extends WatchUi.WatchFace {
var center; // 画面の中心座標[x,y]
var bmBluetooth; // bluetoothのビットマップ
var whBluetooth; // bluetoothビットマップの幅と高さ
var xyBluetooth; // bluetoothビットマップの描画のためのxy座標
var yBluetooth; // bluetoothの青丸描画のためのy座標
var bmNotify; // メールビットマップ
var yNotify; // メールビットマップのy座標
var fnLarge; // 大きいフォント
var fnNormal; // 小さいフォント
var fnLargeSize; // 大きいフォントの高さ
var fnNormalSize; // 小さいフォントの高さ
var viewSecX; // 秒の描画x座標
var sinRad899; // 日没・日の出計算用の固定値
var toRad; // 度・ラジアン変換用固定値
var doViewSec = false; // 高電力モード時に秒を描画するためのフラグ
// 低電力モードに入った場合に呼び出される関数
function onEnterSleep() {
doViewSec = false;
}
// 高電力モードに入った場合に呼び出される関数
function onExitSleep() {
doViewSec = true;
}
function initialize() {
WatchFace.initialize();
bmBluetooth = WatchUi.loadResource(Rez.Drawables.BluetoothIcon);
whBluetooth = [bmBluetooth.getWidth() / 2, bmBluetooth.getHeight() / 2];
bmNotify = WatchUi.loadResource(Rez.Drawables.NotifyIcon);
fnLarge = Graphics.FONT_NUMBER_MEDIUM;
fnNormal = Graphics.FONT_LARGE;
toRad = Math.PI / 180.0;
sinRad899 = Math.sin(-0.899 * toRad);
}
// 描画情報が決定後のリソースなどの計算用
function onLayout(dc) {
center = [dc.getWidth()/2, dc.getHeight()/2];
fnLargeSize = [Graphics.getFontAscent(fnLarge), dc.getFontHeight(fnLarge)];
fnNormalSize = [Graphics.getFontAscent(fnNormal), dc.getFontHeight(fnNormal)];
var widthLarge = dc.getTextWidthInPixels("00:00", fnLarge) + 2;
var widthNormal = dc.getTextWidthInPixels("00", fnNormal) + 2;
viewSecX = center[0] + (widthLarge + widthNormal) / 2.0 - widthNormal;
yNotify = center[1] + fnNormalSize[1] * 0.5 - bmNotify.getHeight() / 2 + 2;
yBluetooth = center[1] + fnNormalSize[1] * 1.5;
xyBluetooth = [30, yBluetooth - whBluetooth[1]];
}
// 時間・日付を描画する
// 時間は24時間制。分と秒は0リーディング2桁
// 日付は、「月/日 曜日」といった日本風なフォーマットのみとする
function drawTime(dc, timeM, timeS) {
var y = center[1] - fnLargeSize[0];
if (doViewSec) {
dc.drawText(viewSecX - 2, y,
fnLarge, timeS.hour + ":" + timeS.min.format("%02d"), Graphics.TEXT_JUSTIFY_RIGHT);
dc.drawText(viewSecX + 2, center[1] - fnNormalSize[0],
fnNormal, timeS.sec.format("%02d"), Graphics.TEXT_JUSTIFY_LEFT);
}
else {
dc.drawText(center[0], y,
fnLarge, timeS.hour + ":" + timeS.min.format("%02d"), Graphics.TEXT_JUSTIFY_CENTER);
}
dc.drawText(center[0], y - fnNormalSize[0],
fnNormal, timeS.month + "/" + timeS.day + " " + timeM.day_of_week,
Graphics.TEXT_JUSTIFY_CENTER);
}
// 心拍数を求める
// 心拍が求められない場合は---を返す
private function retrieveHeartrateText() {
var currentHeartrate = ActivityMonitor.getHeartRateHistory(1, true).next().heartRate;
if (currentHeartrate != ActivityMonitor.INVALID_HR_SAMPLE) {
return currentHeartrate.format("%d");
}
else {
return "---";
}
}
// 歩数・心拍数などの情報を表示
function drawInformation(dc) {
var info = ActivityMonitor.getInfo();
// 歩数
dc.drawText(center[0], center[1],
fnNormal, info.stepGoal.format("%5d") + "/" + info.steps.format("%5d"),
Graphics.TEXT_JUSTIFY_CENTER);
// 心拍数
dc.drawText(center[0] - 5, center[1] + fnNormalSize[1],
fnNormal, retrieveHeartrateText(),
Graphics.TEXT_JUSTIFY_RIGHT);
}
// Bluetoothとイベント通知アイコンの表示
function drawNotify(dc) {
var info = System.getDeviceSettings();
if (info.notificationCount > 0) {
// メールアイコンの表示
dc.drawBitmap(14, yNotify, bmNotify);
}
if (info.phoneConnected) {
// BLEアイコンの表示
// 青い丸はビットマップでの描画ではなく楕円を描画している
dc.setColor(Graphics.COLOR_DK_BLUE, Graphics.COLOR_BLACK);
dc.fillEllipse(xyBluetooth[0] + 12, yBluetooth, whBluetooth[0] - 1, whBluetooth[1] - 1);
dc.drawBitmap(xyBluetooth[0], xyBluetooth[1], bmBluetooth);
}
}
// 時計回りで円弧を描画する
// 角度はDC::drawArcに習い度
function drawArc(dc, centerXY, radius, sAngle, eAngle) {
if (sAngle < eAngle) {
sAngle += 360;
}
var angle = eAngle * toRad;
var stepAngle = 12.0 * toRad;
var toAngle = sAngle * toRad;
var spos = [centerXY[0] + radius * Math.cos(angle), centerXY[1] - radius * Math.sin(angle)];
for (; angle < toAngle; angle += stepAngle) {
var epos = [centerXY[0] + radius * Math.cos(angle), centerXY[1] - radius * Math.sin(angle)];
dc.drawLine(spos[0], spos[1], epos[0], epos[1]);
spos = epos;
}
dc.drawLine(spos[0], spos[1], centerXY[0] + radius * Math.cos(toAngle), centerXY[1] - radius * Math.sin(toAngle));
}
// 日の出時刻を求める関数、返却は[日の出,日の入り]で、それぞれ00:00からの通算分が入る
// 閏年は考慮せず、また1/1からの通算日計算もアバウトにしているので、その分精度は下がる(一応今のところ1~2分位の誤差か?)
function timeSunSetRise(xy, n) {
var y = xy[0] * toRad;
// 日付をラジアンに変換
var w = (((((n.month - 1) * 30.416 + n.day - 1).toLong()) % 365) + 0.5) * 2.0 * Math.PI / 365.0;
// 近似式で太陽赤緯を求める
var d = ( + 0.33281
- 22.984 * Math.cos(w) - 0.34990 * Math.cos(2.0 * w) - 0.13980 * Math.cos(3.0 * w)
+ 3.7872 * Math.sin(w) + 0.03250 * Math.sin(2.0 * w) + 0.07187 * Math.sin(3.0 * w)) * toRad;
// 近似式で均時差を求める
var e = + 0.0072 * Math.cos(w) - 0.0528 * Math.cos(2.0 * w) - 0.0012 * Math.cos(3.0 * w)
- 0.1229 * Math.sin(w) - 0.1565 * Math.sin(2.0 * w) - 0.0041 * Math.sin(3.0 * w);
// 太陽の時角幅を求める(視半径、大気差などを補正 (-0.899度) )
var t = (Math.acos( (sinRad899 - Math.sin(d) * Math.sin(y)) / (Math.cos(d) * Math.cos(y)))) / toRad;
// 日の出, 日の入り時刻を返す
var c = xy[1] - 315.0;
return [
(((-t - c) / 15.0 - e) * 60).toLong(),
((( t - c) / 15.0 - e) * 60).toLong()];
}
// 日の出・日の入りに関する情報を表示する
// ここで取り扱う時間は00:00からの通算分としている
// 時計枠(丸)を24時間の時間のみを表すアナログ計とする。そこに日が出ていない時間を白の円弧で描画する。
// 時間を表すマークは緑の棒で描画。45度にある時間、3,9,15,21時は太い白で描画し時間の区切りが分かるようにする。
function drawSun(dc, time) {
var info = Position.getInfo();
if (info != null && info has :position) {
var work = info.position.toDegrees();
var sunTime = timeSunSetRise(work, time);
var now = time.hour * 60 + time.min;
// 次の日の出・日の入りの時刻を表示
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
var str = "";
if (now < sunTime[0] || sunTime[1] <= now) {
// 今は夜なので次の日の出を表示(にしたいが今は今日の日の出になっている)
if (sunTime[1] <= now) {
// 現在時刻が日没後0:00前なので翌日の情報を用意する
time.day++;
var sunTime1 = timeSunSetRise(work, time);
sunTime[0] = sunTime1[0];
}
str = (sunTime[0] / 60).format("%2d") + ":" + (sunTime[0] % 60).format("%2d");
}
else {
// 今は日中なので日没時刻を表示
str = (sunTime[1] / 60).format("%2d") + ":" + (sunTime[1] % 60).format("%2d");
}
dc.drawText(center[0] + 10, center[1] + fnNormalSize[1],
fnNormal, str, Graphics.TEXT_JUSTIFY_LEFT);
// 日が出ていない時間を白の円弧で表示
var radius = center[0] - 1;
dc.setPenWidth(3);
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
drawArc(dc, center, radius, 270 - 0.25 * sunTime[1], 270 - 0.25 * sunTime[0]);
// 1時間単位の線を描画
dc.setColor(Graphics.COLOR_GREEN, Graphics.COLOR_BLACK);
radius = center[0] - 8;
var radius2 = center[0] - 10;
for (var i = 0; i < 360; i += 15) {
var arrowAngle = i * toRad;
var vSin = Math.sin(arrowAngle);
var vCos = Math.cos(arrowAngle);
if (i % 90 == 45) {
dc.setPenWidth(5);
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
dc.drawLine(
center[0] + vCos * center[0],
center[1] - vSin * center[0],
center[0] + vCos * radius2,
center[1] - vSin * radius2);
dc.setPenWidth(3);
dc.setColor(Graphics.COLOR_GREEN, Graphics.COLOR_BLACK);
}
else {
dc.drawLine(
center[0] + vCos * center[0],
center[1] - vSin * center[0],
center[0] + vCos * radius,
center[1] - vSin * radius);
}
}
// 現在時刻を示す針を表示
var arrowAngle = (270 - 0.25 * now) * toRad;
radius = center[0] - 10;
var vSin = Math.sin(arrowAngle);
var vCos = Math.cos(arrowAngle);
dc.setPenWidth(6);
dc.setColor(Graphics.COLOR_PINK, Graphics.COLOR_BLACK);
dc.drawLine(
center[0] + vCos * center[0],
center[1] - vSin * center[0],
center[0] + vCos * radius,
center[1] - vSin * radius);
dc.setPenWidth(4);
dc.setColor(Graphics.COLOR_YELLOW, Graphics.COLOR_BLACK);
dc.drawLine(
center[0] + vCos * center[0],
center[1] - vSin * center[0],
center[0] + vCos * radius,
center[1] - vSin * radius);
dc.setPenWidth(1);
}
}
// バッテリー情報を表示
function drawBattery(dc) {
var status = System.getSystemStats();
dc.setColor(Graphics.COLOR_GREEN, Graphics.COLOR_BLACK);
dc.drawText(center[0], dc.getHeight() - fnNormalSize[1] - 8,
fnNormal, status.battery.format("%3.0f"),
Graphics.TEXT_JUSTIFY_CENTER);
}
// Update the view
function onUpdate(dc) {
dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_BLACK);
dc.clear();
var now = Time.now();
var nowM = Time.Gregorian.info(now, Time.FORMAT_MEDIUM);
var nowS = Time.Gregorian.info(now, Time.FORMAT_SHORT);
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
drawTime(dc, nowM, nowS);
drawInformation(dc);
drawNotify(dc); // 色の変更有
drawBattery(dc); // 色の変更有
drawSun(dc, nowS); // 色・幅の変更有
}
function onPartialUpdate( dc ) {
// 計測したい処理を実行する
onUpdate(dc);
}
}
コメント