Windowsのデスクトップに表示するデジタル時計をHTAでささっと作る

# はじめに
今の職場には時計がない。仕事に没頭すると会議に遅刻しそうになったりする。視線移動が少なくて済むよう Windows のデスクトップ上で適切な（それなりに目立つけど邪魔にならない）大きさで表示する時計を自作することにした。

ということで，お手軽にユーザーインターフェースを作れる HTA（HTML Application）で作成することにする。

# 描画エンジンの変更
HTML5 の canvas を使って時刻を描画するのが楽なのだが，デフォルト（IE6）では対応していないため，IE9 に切り替える必要がある。

```html
<meta http-equiv="X-UA-Compatible" content="IE=9" />
```

# ウィンドウのリサイズ
一応 HTML 部分で `canvas` のサイズを指定しているが，ここでは無効であり，実際には JavaScript 部分の `setAttribute()` で決定している。初期化時にウィンドウサイズを計測し，`canvas` の大きさを超過する分だけウィンドウを小さくしている。つまり，ウィンドウを `canvas` の大きさに合わせている。

```css:CSS部分
body {
  margin: 0px;
  padding: 0px;
}
```

```javascript:JavaScript部分
canvas.setAttribute("width",  144);
canvas.setAttribute("height",  50);
var dx = window.innerWidth  - canvas.offsetWidth;
var dy = window.innerHeight - canvas.offsetHeight;
window.resizeBy(-dx, -dy);
```

```html:HTML部分
<body><canvas id="canvas" width=144 height=50></canvas></body>
```

# デジタル時計の数字の描画
数字(0～9)は横32ピクセル×高さ50ピクセル，コロン(:)は横16ピクセル×高さ50ピクセルで作成している。この画像は自分がゼロから作成したオリジナルである。なので各自ダウンロードして自由に使ってもらって構わない。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/dfdc48bd-d976-37af-1fa6-d3085ff26f26.png>

こうして作成した画像 DigitalClock.PNG をイニシャライズ時に読み込む。

```javascript:イニシャライズ部分
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
canvas.setAttribute("width",  144);
canvas.setAttribute("height",  50);
image = new Image();
image.src = "DigitalClock.PNG";
```

そして周期呼び出し時に現在の時刻を取得し，時間と分の数字（二桁）を描画する。数字に相当する矩形領域を`image` から `context` にコピーする。

```javascript:周期呼び出し部分
var t = new Date();
var h = ("0" + t.getHours()  ).slice(-2);
var m = ("0" + t.getMinutes()).slice(-2);
var a = h.charAt(0);
var b = h.charAt(1);
var c = m.charAt(0);
var d = m.charAt(1);
context.drawImage(image,  a * 32, 0, 32, 50,   0, 0, 32, 50);
context.drawImage(image,  b * 32, 0, 32, 50,  32, 0, 32, 50);
context.drawImage(image,  c * 32, 0, 32, 50,  80, 0, 32, 50);
context.drawImage(image,  d * 32, 0, 32, 50, 112, 0, 32, 50);
context.drawImage(image, 10 * 32, 0, 16, 50,  64, 0, 16, 50);
```

# アイコン画像
本スクリプトで使用しているアイコン DigitalClock.ICO は Windows の shell32.dll から抽出したものなので公開できない。なので各自用意して欲しい。※ただしアイコンがなくても動く。

```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
footer {
  fontColor: black;
  fontSize: 16;
}
</style>
title <img https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/3ced04f4-ab43-302b-79b1-9dc65ffe3895.png>
footer 図１　shell32.dll のアイコン一覧
@enduml
```

# 実装コード
実装コードを以下に示す。一応，文字コードを `Shift_JIS` と指定しているが，日本語はコメントだけなので指定は不要かもしれない。

```html:DigitalClock.HTA
<html>
<head>
<meta http-equiv="MSThemeCompatible" content="yes" />
<meta http-equiv="X-UA-Compatible" content="IE=9" />
<meta http-equiv="content-type" content="text/html; charset=Shift_JIS" />
<title>CLOCK</title>
<HTA:APPLICATION ID="DigitalClock"
  APPLICATIONNAME="DigitalClock"
  BORDER="thin"
  BORDERSTYLE="normal"
  CAPTION="yes"
  ICON="DigitalClock.ICO"
  INNERBORDER="no"
  MAXIMIZEBUTTON="no"
  MINIMIZEBUTTON="no"
  SHOWINTASKBAR="yes"
  SINGLEINSTANCE="yes"
  SYSMENU="yes"
  VERSION="1.0"
  WINDOWSTATE="normal"
  SCROLL="no"
  SCROLLFLAT="no"
  SELECTION="yes"
  CONTEXTMENU="yes"
  NAVIGABLE="yes"
/>
<style type="text/css">
body {
  margin: 0px;
  padding: 0px;
}
</style>
<script languate="jscript">
//------------------------------------------------------------------------------
// グローバル変数
//------------------------------------------------------------------------------
var canvas;
var context;
var image;
//------------------------------------------------------------------------------
// 初期化
//------------------------------------------------------------------------------
function initial() {
  canvas = document.getElementById("canvas");
  context = canvas.getContext("2d");
  canvas.setAttribute("width",  144);
  canvas.setAttribute("height",  50);
  image = new Image();
  image.src = "DigitalClock.PNG";
  image.onload = function(event) {
    update();
    setInterval(update, 15 * 1000);
  }
  var dx = window.innerWidth  - canvas.offsetWidth;
  var dy = window.innerHeight - canvas.offsetHeight;
  window.resizeBy(-dx, -dy);
}
//------------------------------------------------------------------------------
// 時間の更新
//------------------------------------------------------------------------------
function update() {
  var t = new Date();
  var h = ("0" + t.getHours()  ).slice(-2);
  var m = ("0" + t.getMinutes()).slice(-2);
  var a = h.charAt(0);
  var b = h.charAt(1);
  var c = m.charAt(0);
  var d = m.charAt(1);
  context.drawImage(image,  a * 32, 0, 32, 50,   0, 0, 32, 50);
  context.drawImage(image,  b * 32, 0, 32, 50,  32, 0, 32, 50);
  context.drawImage(image,  c * 32, 0, 32, 50,  80, 0, 32, 50);
  context.drawImage(image,  d * 32, 0, 32, 50, 112, 0, 32, 50);
  context.drawImage(image, 10 * 32, 0, 16, 50,  64, 0, 16, 50);
}
window.onload = initial;
</script>
</head>
<body><canvas id="canvas" width=144 height=50></canvas></body>
</html>
```

# 動作画面

こんな感じ。

```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
footer {
  fontColor: black;
  fontSize: 16;
}
</style>
title <img https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/77e679e0-2a15-bd68-a044-5b76e3dd44be.png>
footer 図２　動作画面
@enduml
```

# 今後の課題

最前面表示の指定ができないので，せっかく作った時計だけど他のアプリのウィンドウの後ろに隠れてしまうことがある・・・

最前面表示する方法が分かった。詳しくは下記の記事を参照されたい。

[Windowsアプリを最前面表示にして起動するPowerShellスクリプトをささっと作る - Qiita](https://qiita.com/TETSURO1999/items/9951ad4343b29b21bfea)