ロック画面にアナログ時計を表示する1

ロック画面は、使える範囲がかなりあります。
だからこそ、ロック画面の表示に拘る方が多いのではないでしょうか。
私も拘る方なのですが、ロック画面のLCD時計を消すだけでなく、ロック解除スライダーも消してまで、ロック画面を広く使う方もいらっしゃいます。
拘ることでインパクトや個性のあるロック画面に仕上がったものを目にしますが、時計表示でさえド派手になってしまったものも目にします。
個人的な考えですが、「見た目」と「機能性」のバランスを考えると、「機能性」を重視したいので、ここではアナログ時計表示ウィジェットを作ろうと思います。
シンプル時計と違って、多少は見た目も気にして装飾していくつもりです。

<注意>
ここでは、デフォルトの時計は不要なので、脱獄アプリの「LockScreen Clock Hide」をインストールしてデフォルトの時計を消して下さい。
書式変更テーマを併用して、デフォルトの時計を消すこともできます。
さらに、今回は、各々iPhoneに設定したロック画面の背景を使って、ウィジェットの背景画像にしたり、文字盤をつくったりしますので、「Wallpaper JPEGifier」をインストールしておいて下さい。
なお、どちらもインストールしなくても、ウィジェット動作の確認はできます。
見た目の問題であり、確認のし易さを向上させるためですので、各自の判断でインストールして下さい。

基本ファイルとその確認

サンプルファイル構成

今回作るサンプルウィジェットを含むテーマファイルの基本構成は右図の通りです。
ファイルのダウンロードはこちらーー>ダウンロード
LockBackground.htmlは、ロック画面で実行されるウィジェットです。
style.cssは見た目の設定をし、script.jsは時計を動かします。

では、ファイルを1つ1つ見ていきましょう。

サンプルHTML

HTMLから見ていきましょう。
以下に示すのが、LockBackground.htmlの中身(ソース)です。

<!DOCTYPE html>
<html>
 <head>
  <meta name="viewport" content="width=device-width,minimum-scale=0.5"/>
  <meta charset="UTF-8">
  <meta name="format-detection" content="telephone=no">
  <script src="./script.js" type="text/javascript"></script>
  <link href="./style.css" rel="stylesheet" type="text/css" />
 </head>
 <body onload="init()">
  <canvas id="clock" width="640" height="640"></canvas>
 </body>
</html>

サンプルHTMLソース1

もうお馴染みとなった、日本語表示可能且つ、幅640のRetina仕様です。
中身はcanvasのみです。
canvasの大きさは、HTMLで指定しています。
スタイルシートで指定すると拡大表示になってしまうし、Javascriptで指定するにも面倒臭いので、HTMLで指定しました。

HTMLが読み込まれたら、Javascript内の関数init()が実行されます。

ページトップへ

サンプルスタイルシート
* {
   margin: 0px;
   padding: 0px;
   border: 0px;
}
body {
   width: 640px;
   height: 960px;
}
#clock {
   margin-top: 80px;
}

サンプルスタイルシート1

次に、スタイルシート(style.css)を見ていきましょう。

canvasの縦位置を80ピクセルにしました。

ページトップへ

サンプルJavaScript

では、次にJSファイルを見ていきましょう。
以下に示すのが、script.jsの中身(ソース)です。

function init() {
 var canvas = document.getElementById("clock");
 var ctx = canvas.getContext("2d");
 setTime(ctx);
}

function setTime(ctx) {
 get_date = new Date();
 cr_seconds = get_date.getSeconds();
 ctx.beginPath();
 ctx.lineWidth = 3;
 ctx.strokeStyle = "red";
 ctx.moveTo(320, 320);
 ctx.lineTo(320+ 320*Math.cos(cr_seconds*Math.PI/30), 320+
                      320*Math.sin(cr_seconds*Math.PI/30));
 ctx.stroke();

 setTimeout(function(){setTime(ctx);},1000);
}

サンプルJavaScript1

script.jsには、2つの関数があります。
HTMLが読み込まれた時に実行するinitと、時計の中枢であるsetTimeです。
initは、初期設定のようなものをまとめておくために用意しました。

var canvas = document.getElementById("clock");
var ctx = canvas.getContext("2d");

この2つはセットで覚えて構いません。
サンプルにおけるcanvasオブジェクトを取得し、そのcanvasオブジェクトから描画用コンテキストを取得しています。
このコンテキストのメソッドやプロパティを利用することで描画が可能となります。

setTime(ctx);

初期設定を終えて、実際の描画処理に入る部分です。
単純に呼び出すのではなく、取得したコンテキストを引数にしています
それが今回のポイントなのですが、変数の有効範囲の問題があるのです。
関数内の変数は、その関数内でのみ有効なので、取得したコンテキストをctxに格納しても、そのctxはinit内だけ有効なので、setTimeでctxを使おうとしても使えないのです。
initのctxと、setTimeのctxは、同じctxという変数名でも、まったく別モノなんですね。
なので、このctxを引数にすることで、setTimeでもinit内で取得したコンテキストがそのまま使えるようになります。

では、実際の描画関数であるsetTimeを見ていきましょう。

get_date = new Date();
cr_seconds = get_date.getSeconds();

現在の時刻を取得し、そこから「秒」を抜き出しています。

ctx.beginPath();

取得したコンテキストに描画を開始します。

ctx.lineWidth = 3;
ctx.strokeStyle = "red";

線の太さを3ピクセルにし、線の色を赤にしています。

ctx.moveTo(320, 320);
ctx.lineTo(320+ 320*Math.cos(cr_seconds*Math.PI/30), 320+
                      320*Math.sin(cr_seconds*Math.PI/30));

moveToで、描画のスタート位置を、320,320に移動します。
幅640の正方形に時計を表示しようとしているので、320,320は中心を表します。
lineToで、線を引くのですが、どこまで線を引くかが数式で表現されています。
半径320の円の座標を計算しているのですが、詳しくは説明しません。
ラジアン変換も合わせてググって下さい。

ctx.stroke();

これで、実際に描画します。
準備をしておいて、一気に書き出すという感じです。

setTimeout(function(){setTime(ctx);},1000);

以上の処理を1秒後に呼び出します。
自分自身を1秒後に呼び出すので、1秒毎に描画されることになります。

ページトップへ

サンプル表示

サンプル表示1

基本サンプルファイルを実行すると、右のようになります。

一秒毎に赤い線が描画され、きちんと秒針の役目を果たして・・・



・・・って、ダメぢゃん!!
どんどん線が増えちゃって、どうすんの???


まぁ、ここからスタートということで・・・





今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

バグを取る

プログラム的には何の問題もなく、きちんと動いています。
意図した通りに動作しない」という本来の意味でのバグを取りましょう。

今回はJavaScriptのみで対応します。

JavaScriptを変更する

前回のバグは、一度描画したものを消していないから発生してしまいました。
「消してから描く」という繰り返しで、目的を達成することにします。

function setTime(ctx) {
 get_date = new Date();
 cr_seconds = get_date.getSeconds();
 s_rad = (cr_seconds*6)*(2*Math.PI)/360;

 ctx.beginPath();
 ctx.clearRect(0, 0, 640, 640);
 ctx.lineWidth = 3;
 ctx.strokeStyle = "red";
 ctx.moveTo(320, 320);
 ctx.lineTo(320+ 320*Math.cos(s_rad), 320 + 320*Math.sin(s_rad));
 ctx.stroke();

 setTimeout(function(){setTime(ctx);},1000);
}

サンプルJavaScript2

描き始めにclearRectを使っています。
(0,0)から(640,640) の矩形範囲を消すことで、書き直しています。
たったこれだけで、バグ取り完了です。

せっかくなので、秒を角度にしその角度をラジアンへ変換する数式を変数化しました。

ページトップへ

サンプル表示

サンプル表示2

変更したサンプルファイルを実行すると、右のようになります。

1秒毎に秒針が進んでいるように見えます。
思った以上にきちんと動いていますね。

ちょっとビックリです。




今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

ソースを見直す

バグを取ってきちんと動作したことを確認しましたが、残りの針に進む前に、ソースを見直しておきます。
これまでは、プログラミングで座標を計算し、その座標でcanvas上に針を描画したのですが、今回は針を描画したcanvasを回転させることにします。
「回転する針を描画」するのではなく、「描画した針を回転」させる訳です。
回転作業はスタイルシートに任せることにします。

JavaScriptを変更する

今回はスタイルシートを使うので、要素の特定のためにidをそのまま使います。
そのため、引数がcanvasとctxの2つになりました。

function init() {
 var canvas = document.getElementById("clock");
 var ctx = canvas.getContext("2d");
 setTime(canvas, ctx);
}

function setTime(canvas, ctx) {
 get_date = new Date();
 cr_seconds = get_date.getSeconds();
 s_angle = cr_seconds*6;
 canvas.style.webkitTransform = "rotate(" + s_angle + "deg)";

 ctx.beginPath();
 ctx.lineWidth = 3;
 ctx.strokeStyle = "red";
 ctx.moveTo(320, 320);
 ctx.lineTo(320 , 0);
 ctx.stroke();

 setTimeout(function(){setTime(canvas, ctx);},1000);
}

サンプルJavaScript3

引数が2つになったことよりも、特筆すべき点があります。
回転をスタイルシートに任せることで、ラジアンではなくそのまま角度指定できます。
この段階でもソースがシンプルになるのですが、描画の記述自体もシンプルになっています。
回転に関する記述は必要ないので、中心から上に向かって1本線を引くだけで済む訳です。

ページトップへ

サンプル表示

ソースを見直しただけですので、実行結果に変化はありません。


今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

ソースを見直す2

ソースを見直すことで、回転動作をスタイルシートに移行しました。
そのおかげで、引数が2つになったのですが、今回は引数に関して見直します。
関数内で変数を定義したので、その変数は「ローカル変数」と呼ばれ、その関数内でしか変数が有効ではありません。
ローカル関数を使ったので、引数を使ってやり取りした訳なんですね。
ローカル変数とは違い、全体で有効な「グローバル変数」というものがあります。
サンプルでは、どの関数からでも同じ変数を使いたいので、今回は、この「グローバル変数」を使ってソースを見直します。

JavaScriptを変更する

引数にしていたcanvasとctxをグローバル変数にするために、関数の外で宣言します。

var canvas, ctx;
function init() {
 canvas = document.getElementById("clock");
 ctx = canvas.getContext("2d");
 setTime();
}

function setTime() {
 get_date = new Date();
 cr_seconds = get_date.getSeconds();
 s_angle = cr_seconds*6;
 canvas.style.webkitTransform = "rotate(" + s_angle + "deg)";

 ctx.beginPath();
 ctx.lineWidth = 3;
 ctx.strokeStyle = "red";
 ctx.moveTo(320, 320);
 ctx.lineTo(320 , 0);
 ctx.stroke();

 setTimeout("setTime()", 1000);
}

サンプルJavaScript4

引数をグローバル変数にすることで、関数の呼び出しが簡素になっています。
ソースが複雑になる前に導入しておくべきかと思い、このタイミングで紹介しました。

ページトップへ

サンプル表示

今回もソースを見直しただけですので、実行結果に変化はありません。


今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

ソースを見直す3

スタイルシートで回転させることで、描画の時に線の角度を考える必要がなくなりました。
しかし、よくよく考えたら、毎秒描画してるんですよね。
せっかく、初期設定用の関数と時計動作用の関数を分けているので、針の描画は初期設定で済ませるべきですよね?
という訳で、ソースを見直して役割をハッキリさせましょう。

JavaScriptを変更する

基本的に、描画の部分を移動するだけで済みます。

var canvas, ctx;
function init() {
 canvas = document.getElementById("clock");
 ctx = canvas.getContext("2d");

 ctx.beginPath();
 ctx.lineWidth = 3;
 ctx.strokeStyle = "red";
 ctx.moveTo(320, 320);
 ctx.lineTo(320 , 0);
 ctx.stroke();

 setTime();
}

function setTime() {
 get_date = new Date();
 cr_seconds = get_date.getSeconds();
 s_angle = cr_seconds*6;
 canvas.style.webkitTransform = "rotate(" + s_angle + "deg)";

 setTimeout("setTime()", 1000);
}

サンプルJavaScript5

ホントに移動しただけですね。

ページトップへ

サンプル表示

今回もソースを見直しただけですので、実行結果に変化はありません。


今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

すべての針を導入する

秒針でのプログラミングで、それなりにソースを煮詰めたので、長針と短針を加えましょう。
基本的には、秒針のタグやソースをそのまま流用すればOKです。

サンプルHTML

HTMLの追加分から見ていきましょう。
以下に示すのが、LockBackground.htmlの中身(ソース)です。

<!DOCTYPE html>
<html>
 <head>
  <meta name="viewport" content="width=device-width,minimum-scale=0.5"/>
  <meta charset="UTF-8">
  <meta name="format-detection" content="telephone=no">
  <script src="./script.js" type="text/javascript"></script>
  <link href="./style.css" rel="stylesheet" type="text/css" />
 </head>
 <body onload="init()">
  <div id="clock">
   <canvas id="hour" width="640" height="640"></canvas>
   <canvas id="minute" width="640" height="640"></canvas>
   <canvas id="second" width="640" height="640"></canvas>
  </div>
 </body>
</html>

サンプルHTMLソース6

これまでは秒針だけだったのでcanvasも1つでしたが、今回から3つになりました。
それぞれの針を個別に回転させるため、長針・短針・秒針の3つにそれぞれ独立したcanvasを用意します。
そして、この3つをグループにして管理するために、divタグで括ります。

ページトップへ

サンプルスタイルシート
* {
   margin: 0px;
   padding: 0px;
   border: 0px;
}
body {
   width: 640px;
   height: 960px;
}
#clock {
   margin-top: 80px;
   position: relative;
}

#hour, #minute, #second {
   position: absolute;
}

サンプルスタイルシート6

次に、スタイルシート(style.css)を見ていきましょう。

3つのcanvasをグループ内で絶対配置し、すべてを重ねて表示するために、position指定を追加しました。

ページトップへ

サンプルJavaScript

では、次にJSファイルの追加分を見ていきましょう。
以下に示すのが、script.jsの中身(ソース)です。

var id_hour, ctx_hour;
var id_minute, ctx_minute;
var id_second, ctx_second;

function init() {
 id_hour = document.getElementById("hour");
 ctx_hour = id_hour.getContext("2d");
 id_minute = document.getElementById("minute");
 ctx_minute = id_minute.getContext("2d");
 id_second = document.getElementById("second");
 ctx_second = id_second.getContext("2d");
 // 短針
 ctx_hour.beginPath();
 ctx_hour.lineWidth = 30;
 ctx_hour.strokeStyle = "silver";
 ctx_hour.moveTo(320, 320);
 ctx_hour.lineTo(320, 160);
 ctx_hour.stroke();
 // 長針
 ctx_minute.beginPath();
 ctx_minute.lineWidth = 20;
 ctx_minute.strokeStyle = "silver";
 ctx_minute.moveTo(320, 320);
 ctx_minute.lineTo(320, 0);
 ctx_minute.stroke();
 // 秒針
 ctx_second.beginPath();
 ctx_second.lineWidth = 3;
 ctx_second.strokeStyle = "red";
 ctx_second.moveTo(320, 320);
 ctx_second.lineTo(320, 0);
 ctx_second.stroke();

 setTime();
}

function setTime() {
 get_date = new Date();
 cr_hours = get_date.getHours();
 cr_minutes = get_date.getMinutes();
 cr_seconds = get_date.getSeconds();

 h_angle = cr_hours*30;
 id_hour.style.webkitTransform = "rotate(" + h_angle + "deg)";
 m_angle = cr_minutes*6;
 id_minute.style.webkitTransform = "rotate(" + m_angle + "deg)";
 s_angle = cr_seconds*6;
 id_second.style.webkitTransform = "rotate(" + s_angle + "deg)";

 setTimeout("setTime()", 1000);
}

サンプルJavaScript6

秒に関する記述をコピーし、「時間」と「分」の仕様にしただけです。
針の描画の部分ですが、それなりの太さにし、色をシルバーにしてみました。
角度計算の部分ですが、「分」と「秒」は60で一周(360度)するので6倍していますが、「時間」に関しては12で一周(360度)するので30倍しています。

ページトップへ

サンプル表示

サンプル表示6

基本サンプルファイルを実行すると、右のようになります。

とりあえず1分以上眺めてみましたが、きちんと動いているようです。




今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

文字盤も導入する

針が揃ったところで、文字盤も導入しましょう。

サンプルHTML

では、文字盤用canvasの追加分から見ていきましょう。
以下に示すのが、LockBackground.htmlの中身(ソース)です。

<!DOCTYPE html>
<html>
 <head>
  <meta name="viewport" content="width=device-width,minimum-scale=0.5"/>
  <meta charset="UTF-8">
  <meta name="format-detection" content="telephone=no">
  <script src="./script.js" type="text/javascript"></script>
  <link href="./style.css" rel="stylesheet" type="text/css" />
 </head>
 <body onload="init()">
  <div id="clock">
   <canvas id="bg" width="640" height="640"></canvas>
   <canvas id="hour" width="640" height="640"></canvas>
   <canvas id="minute" width="640" height="640"></canvas>
   <canvas id="second" width="640" height="640"></canvas>
  </div>
 </body>
</html>

サンプルHTMLソース7

一番後ろに配置するために、針用canvasよりも前に記述しています。

ページトップへ

サンプルスタイルシート
* {
   margin: 0px;
   padding: 0px;
   border: 0px;
}
body {
   width: 640px;
   height: 960px;
}
#clock {
   margin-top: 80px;
   position: relative;
}
#bg, #hour, #minute, #second {
   position: absolute;
}

サンプルスタイルシート7

次に、スタイルシート(style.css)を見ていきましょう。

文字盤用canvasの#bgを追加しただけです。

ページトップへ

サンプルJavaScript

では、次にJSファイルの追加分を見ていきましょう。
以下に示すのが、script.jsの中身(ソース)です。

var id_bg, ctx_bg;
var id_hour, ctx_hour;
var id_minute, ctx_minute;
var id_second, ctx_second;

function init() {
 id_bg = document.getElementById("bg");
 ctx_bg = id_hour.getContext("2d");
 id_hour = document.getElementById("hour");
 ctx_hour = id_hour.getContext("2d");
 id_minute = document.getElementById("minute");
 ctx_minute = id_minute.getContext("2d");
 id_second = document.getElementById("second");
 ctx_second = id_second.getContext("2d");
 // 短針
 ctx_hour.beginPath();
 ctx_hour.lineWidth = 30;
 ctx_hour.strokeStyle = "silver";
 ctx_hour.moveTo(320, 320);
 ctx_hour.lineTo(320, 160);
 ctx_hour.stroke();
 // 長針
 ctx_minute.beginPath();
 ctx_minute.lineWidth = 20;
 ctx_minute.strokeStyle = "silver";
 ctx_minute.moveTo(320, 320);
 ctx_minute.lineTo(320, 0);
 ctx_minute.stroke();
 // 秒針
 ctx_second.beginPath();
 ctx_second.lineWidth = 3;
 ctx_second.strokeStyle = "red";
 ctx_second.moveTo(320, 320);
 ctx_second.lineTo(320, 0);
 ctx_second.stroke();
 // 文字盤
 ctx_bg.beginPath();
 ctx_bg.fillStyle = "lightblue";
 ctx_bg.arc(320, 320, 320, 0, 2 * Math.PI, false);
 ctx_bg.fill();

 setTime();
}

サンプルJavaScript7

今回は文字盤のみの追加ですので、時計の動作に関する部分には触れません。
宣言的には、針の部分と同じです。
でも、描画は全く違います。
直線ではなく円を描いており、しかも塗りつぶしています。

arcの行が、円弧を描画する部分です。
記述方法は、以下の通りです。

コンテキスト(中心X座標,中心Y座標,半径,開始角,終了角,反時計回りかどうか)

サンプルは、中心(320,320)、半径320であり、開始角0(rad)、終了角2π(rad)なので、画面いっぱいの円が描画される訳です。
色は、水色のつもりで薄い青を指定しました。
文字盤が表示されればOKなので、このまま続けます。

ページトップへ

サンプル表示

サンプル表示7

基本サンプルファイルを実行すると、右のようになります。
形にはなりましたが、まだ役には立っていませんね。

もう少し、文字盤の色を考えた方が良かったかも・・・




今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

目盛りも導入する

目盛りを入れて、もっと時計らしくしましょう。

サンプルJavaScript

では、次にJSファイルの追加分を見ていきましょう。
以下に示すのが、script.jsの中身(ソース)です。

function init() {
 id_bg = document.getElementById("bg");
 ctx_bg = id_hour.getContext("2d");
 id_hour = document.getElementById("hour");
   ・
   ・
   ・
 // 文字盤
 ctx_bg.beginPath();
 ctx_bg.fillStyle = "lightblue";
 ctx_bg.arc(320, 320, 320, 0, 2 * Math.PI, false);
 ctx_bg.fill();

 // 目盛り
 for(i=1; i<=60; i++){
  ctx_bg.beginPath();
  ctx_bg.strokeStyle = "white";
  if(i%5 == 0){
   ctx_bg.lineWidth = 10;
   ctx_bg.moveTo(320+ 270*Math.cos(i*Math.PI/30),
                    320+ 270*Math.sin(i*Math.PI/30));
  }else{
   ctx_bg.lineWidth = 3;
   ctx_bg.moveTo(320+ 290*Math.cos(i*Math.PI/30),
                    320+ 290*Math.sin(i*Math.PI/30));
  }
  ctx_bg.lineTo(320+ 320*Math.cos(i*Math.PI/30),
                    320+ 320*Math.sin(i*Math.PI/30));
  ctx_bg.stroke();
 }

 setTime();
}

サンプルJavaScript8

今回も初期設定関数initのみの変更です。
1から60までループで回しています。
5の倍数かどうかで、線の太さと長さを切り替えています。
実際には、線を描き始める座標だけを切り替えています。
長さは、直接の長さではなく、半径の差で表現しています。

ページトップへ

サンプル表示

サンプル表示8

基本サンプルファイルを実行すると、右のようになります。


やはり、文字盤の色が引っかかります・・・




今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

数字も導入する

目盛りまで入ったので、後は数字を入れれば、もう立派な時計ですね。

サンプルJavaScript

では、次にJSファイルの追加分を見ていきましょう。
以下に示すのが、script.jsの中身(ソース)です。

function init() {
 id_bg = document.getElementById("bg");
 ctx_bg = id_hour.getContext("2d");
 id_hour = document.getElementById("hour");
   ・
   ・
   ・
 // 文字盤
 ctx_bg.beginPath();
 ctx_bg.fillStyle = "lightblue";
 ctx_bg.arc(320, 320, 320, 0, 2 * Math.PI, false);
 ctx_bg.fill();

 // 目盛り&数字
 for(i=1; i<=60; i++){
  ctx_bg.beginPath();
  ctx_bg.strokeStyle = "white";
  if(i%5 == 0){
   ctx_bg.lineWidth = 10;
   ctx_bg.moveTo(320+ 270*Math.cos(i*Math.PI/30),
                    320+ 270*Math.sin(i*Math.PI/30));
   ctx_bg.fillStyle = "white";
   ctx_bg.font = "bold 48px sans-serif";
   ctx_bg.textAlign = "center";
   ctx_bg.fillText(i/5, 320+ 240*Math.sin(i*Math.PI/30),
                    338- 240*Math.cos(i*Math.PI/30));
  }else{
   ctx_bg.lineWidth = 3;
   ctx_bg.moveTo(320+ 290*Math.cos(i*Math.PI/30),
                    320+ 290*Math.sin(i*Math.PI/30));
  }
  ctx_bg.lineTo(320+ 320*Math.cos(i*Math.PI/30),
                    320+ 320*Math.sin(i*Math.PI/30));
  ctx_bg.stroke();
 }

 setTime();
}

サンプルJavaScript9

目盛り表示でループも回しているし、5の倍数かどうかも判別しているので、5の倍数の時に数字を書き出します。
フォントの色や大きさなどを指定して、座標も計算しながら表示しています。
そのままでは全体的に上に寄っていたので、下へ移動し調整してあります

ここで注意しなければならないことは、角度です。
我々が求める角度は、12時(垂直上方向)を基準に考えたいところですが、プログラミング的には3時(水平右方向)が基準の0°線になるため、それを考慮した記述をしなければなりません。

ページトップへ

サンプル表示

サンプル表示9

基本サンプルファイルを実行すると、右のようになります。

形になってますね!!
でも、文字盤の色が引っかかります・・・




今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

文字盤の見た目を変更する

ずっと気になっていた文字盤を何とかしましょう。
と言っても、「この色にしたい」という色がある訳ではなく、単に「薄い青がダメ」だと私が勝手に思っていただけなので、こんな時は「黒」で行きましょう!!
ただ、背景も設定していない段階ですし、せっかく見た目を弄るのですから、白から黒へのグラデーションにしましょう

サンプルJavaScript

では、JSファイルの変更分を見ていきましょう。
以下に示すのが、script.jsの中身(ソース)です。

function init() {
 id_bg = document.getElementById("bg");
 ctx_bg = id_hour.getContext("2d");
 id_hour = document.getElementById("hour");
   ・
   ・
   ・
 // 文字盤
 ctx_bg.beginPath();
 var grad = ctx_bg.createRadialGradient(320,320,0,320,320,320);
 grad.addColorStop(0,"white");
 grad.addColorStop(1,"black");
 ctx_bg.fillStyle = grad;
 ctx_bg.arc(320, 320, 320, 0, 2 * Math.PI, false);
 ctx_bg.fill();

 // 目盛り&数字
 for(i=1; i<=60; i++){
  ctx_bg.beginPath();
   ・
   ・
   ・
  ctx_bg.stroke();
 }

 setTime();
}

サンプルJavaScript10

文字盤を円形グラデーションで塗りました。
グラデーションを指定し、fillstyleにぶち込むことで実現できます。
円形グラデーションの指定方法は、以下の通りです。

コンテキスト.createRadialGradient(開始円X,開始円Y,開始円r,終了円X,終了円Y,終了r)

まぁ、これで十分ではないので補足をします。
createRadialGradientは円形グラデーションを宣言するだけだと思って下さい。
円の中心や円の半径をズラすことも1つのテクニックですが、「色の配分」の方が重要です。
どの色をどのように配分するかなのですが、その指定方法は以下の通りです。

グラデーション.addColorStop(オフセット, 色)

オフセットは、0〜1の値を取ります。
サンプルでは、開始円が文字盤中央になっているので、中央から外に向かって、白から黒へと変化するグラデーションとなります。
addColorStopというだけあって、好きなように色を追加できますが、ほどほどにしておきましょう。

ページトップへ

サンプル表示

サンプル表示10

基本サンプルファイルを実行すると、右のようになります。

味気ないですが、このシンプルさが大好きなので、これでこのまま進んで行きそうですね・・・




今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

針の動きを見直す

気付いていた方がいらっしゃるかもしれませんが、針の動きが気になります。
確かに、取得した時間を針が指していますが、それでもデジタルの範囲を出ていないのです。
上のサンプル表示も分かりやすいのですが、きちんと5:44を指していますよね?
でも、実際のアナログ時計なら短針が6に近付いているはずなのです。
ここで、もう一度針の動きを見直しましょう。

サンプルJavaScript

では、JSファイルの変更分を見ていきましょう。
以下に示すのが、script.jsの中身(ソース)です。

function setTime() {
 get_date = new Date();
 cr_hours = get_date.getHours();
 cr_minutes = get_date.getMinutes();
 cr_seconds = get_date.getSeconds();

 h_angle = cr_hours*30 + cr_minutes/60*30;
 id_hour.style.webkitTransform = "rotate(" + h_angle + "deg)";
 m_angle = cr_minutes*6 + cr_seconds/60*6;
 id_minute.style.webkitTransform = "rotate(" + m_angle + "deg)";
 s_angle = cr_seconds*6;
 id_second.style.webkitTransform = "rotate(" + s_angle + "deg)";

 setTimeout("setTime()", 1000);
}

サンプルJavaScript11

角度に補正を加えるだけですね。
一般的にはもっとシンプルな記述にするのでしょうけど、まとまった数式は見やすいだけで分かりにくいので、数学ではなく算数レベルでやってます。

ページトップへ

サンプル表示

サンプル表示11

基本サンプルファイルを実行すると、右のようになります。

30秒付近なので、短針が目盛りの中央付近にあることで秒補正が確認できます。
同様に、長針は6付近まで来ているので、分補正が確認できます。

動きに関しては、もう大丈夫かな?


今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

針の見た目を変更する

針の動きを見直し、アナログ時計に近付いたところで、針の見た目も見直しましょう。

サンプルJavaScript

では、次にJSファイルの追加・変更を見ていきましょう。
以下に示すのが、script.jsの中身(ソース)です。

function init() {
   ・
   ・
   ・
 // 短針
 ctx_hour.beginPath();
 ctx_hour.lineWidth = 30;
 ctx_hour.lineCap = "round";
 ctx_hour.strokeStyle = "silver";
 ctx_hour.moveTo(320, 340);
 ctx_hour.lineTo(320, 160);
 ctx_hour.stroke();
 // 長針
 ctx_minute.beginPath();
 ctx_minute.lineWidth = 20;
 ctx_minute.lineCap = "round";
 ctx_minute.strokeStyle = "silver";
 ctx_minute.moveTo(320, 340);
 ctx_minute.lineTo(320, 20);
 ctx_minute.stroke();
 // 秒針
 ctx_second.beginPath();
 ctx_second.lineWidth = 3;
 ctx_second.strokeStyle = "red";
 ctx_second.moveTo(320, 340);
 ctx_second.lineTo(320, 0);
 ctx_second.stroke();
 // 文字盤
   ・
   ・
   ・

 setTime();
}

サンプルJavaScript12

針描画部分のみを掲載しています。
短針と長針の角を丸くしました。
丸くした際、丸みの部分が長くなってしまうので、長針元の長さを短くしました。
そして、すべての針を長くし、中心を通過するようにしました。
実際のアナログ時計は、そうでないと機械的に組み付けられません。
また、リアル感が増しましたでしょうか???

ページトップへ

サンプル表示

サンプル表示12

基本サンプルファイルを実行すると、右のようになります。

針の角が丸くなり、それぞれが中心部分で交差していることがお分かりいただけますでしょうか?




今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

壁紙を表示する

では、そろそろ壁紙を表示しましょう。
私が作るウィジェットは、「背景を活かす」という拘りがあるので、仕上げに向けてこの段階から壁紙を表示していきます。
例によって、当サイト脱獄アプリにある「Wallpaper JPEGifier」を導入しておいて下さい。

サンプルスタイルシート
* {
   margin: 0px;
   padding: 0px;
   border: 0px;
}
body {
   width: 640px;
   height: 960px;
   background-image:url("/private/var/
      mobile/Library/SpringBoard/
      Converted-LockBackground.jpg");
   background-repeat: no-repeat;
}
#clock {
   margin-top: 80px;
   position: relative;
}
#bg, #hour, #minute, #second {
   position: absolute;
}

サンプルスタイルシート13

今回は、スタイルシート(style.css)のみで済みます。

bodyに背景を設定しています。

ページトップへ

サンプル表示

サンプル表示13

基本サンプルファイルを実行すると、右のようになります。

私のiPhoneで設定しているロック画面の壁紙なのですが、できるだけ時計を大きくしただけあって、よく分からなくなってますね・・・




今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

文字盤を透過させる

壁紙を表示しましたが、時計の大きさが仇になってしまいましたね。
かと言って、時計を小さくしますか?
いえいえ、透かします!!

サンプルJavaScript

今回も、スタイルシートで文字盤だけ透過率を設定しようとしたのですが、文字盤には文字もあるため文字も薄くなってしまうことと、せっかくグラデーション設定してあるので、グラデーションの色として透過色を設定することにします。

function init() {
   ・
   ・
   ・
 // 文字盤
 ctx_bg.beginPath();
 var grad = ctx_bg.createRadialGradient(320,320,0,320,320,320);
 grad.addColorStop(0,"rgba(255,255,255,0)");
 grad.addColorStop(0.2,"rgba(255,255,255,0)");
 grad.addColorStop(1,"rgba(0,0,0,0.7)");
 ctx_bg.fillStyle = grad;
 ctx_bg.arc(320, 320, 320, 0, 2 * Math.PI, false);
 ctx_bg.fill();

   ・
   ・
   ・
 ctx_bg.stroke();

サンプルJavaScript14

透過色への変更は、rgbaを使うだけです。
そのまま置き換えれば良いのですが、3原色の数値に透過率が加わり、4つの数値で指定することになるます。
さらに、色を追加しています。
追加した色は白ですが、透過率が0のため、完全透明です。
これにより、サンプルでは、文字盤の中央付近が完全に透明となり、外側へ行くにしたがって、透明な白から7割透過の黒へと変化します。

ページトップへ

サンプル表示

サンプル表示14

基本サンプルファイルを実行すると、右のようになります。

やり過ぎた感じも残りますが、背景も時計もハッキリ見えますね。



今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

針も透過させる

ここまで来たら、針も透過させてしまいましょう。
単純な透過だと、背景に因っては針が見にくくなるかもしれないので、線と塗りで針を構成し、塗りを透過させることにします。

サンプルJavaScript

function init() {
   ・
   ・
   ・
 // 短針
 ctx_hour.beginPath();
 ctx_hour.lineWidth = 3;
 ctx_hour.lineCap = "round";
 ctx_hour.strokeStyle = "silver";
 ctx_hour.fillStyle = "rgba(0,0,0,0.2)";
 ctx_hour.moveTo(320+15, 340);
 ctx_hour.lineTo(320+15, 160);
 ctx_hour.arcTo(320, 160-200, 320-15, 160, 15);    <ーarcTo
 ctx_hour.lineTo(320-15, 340);
 ctx_hour.arc(320, 340, 15, Math.PI, 0, true);    <ーarc
 ctx_hour.stroke();
 ctx_hour.fill();
   ・
   ・
   ・

サンプルJavaScript15

ここでは短針のみの紹介ですが、長針でも同様の処理をしています。

針の外周を線引きしています。
これまでは、線の太さを30としていたので、今回は、中心に対して15離れたところに線を引いています。
moveToとlineToで線を描き始めるのですが、arcToにより先端を丸めています。
arcToの指定には仮想点が必要なのですが、針の両側の線は平行であり。交わることがないので、遠くで交わることにして、200離す程度で解決しました。
続けて線を引くのですが、もう一つの半円はarcを使っています。
arcToは、線分を曲線で繋げる時に使い、arcは、円弧を描く時に使うという感じです。
今回は半円を2つ描くので、2つのやり方を紹介しました。

stroke() で線を描くのですが、今回は塗りも必要なので、fill()を導入しています。
ついでに、中央に赤い○を描いておきました。
これで、またアナログ時計に近付きましたでしょうか???

ページトップへ

サンプル表示

サンプル表示15

基本サンプルファイルを実行すると、右のようになります。

やっぱりセンス無いですね・・・



今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

全体的に一回り小さくして仕上げる

背景を活かして終わろうと思ったのですが、画面いっぱい過ぎるのも逆効果かと思いますので、一回り小さくまとめてみましょう。
文字盤だけでなく、目盛りや針の長さも短くします。

サンプルJavaScript

function init() {
   ・
   ・
   ・
 // 短針
 ctx_hour.beginPath();
 ctx_hour.lineWidth = 3;
 ctx_hour.lineCap = "round";
 ctx_hour.strokeStyle = "silver";
 ctx_hour.fillStyle = "rgba(0,0,0,0.2)";
 ctx_hour.moveTo(320+15, 340);
 ctx_hour.lineTo(320+15, 140);
 ctx_hour.arc(320, 140, 15, 0, Math.PI, true);
 ctx_hour.lineTo(320-15, 340);
 ctx_hour.arc(320, 340, 15, Math.PI, 0, true);
 ctx_hour.stroke();
 ctx_hour.fill();
 // 長針
 ctx_minute.beginPath();
 ctx_minute.lineWidth = 3;
 ctx_minute.lineCap = "round"
 ctx_minute.strokeStyle = "silver";
 ctx_minute.fillStyle = "rgba(0,0,0,0.2)";
 ctx_minute.moveTo(320+10, 340);
 ctx_minute.lineTo(320+10, 40);
 ctx_minute.arc(320, 40, 10, 0, Math.PI, true);
 ctx_minute.lineTo(320-10, 340);
 ctx_minute.arc(320, 340, 10, Math.PI, 0, true);
 ctx_minute.stroke();
 ctx_minute.fill();
 // 秒針
 ctx_second.beginPath();
 ctx_second.lineWidth = 3;
 ctx_second.strokeStyle = "red";
 ctx_second.moveTo(320, 340);
 ctx_second.lineTo(320, 20);
 ctx_second.stroke();
 ctx_second.beginPath();
 ctx_second.fillStyle = "red";
 ctx_second.arc(320, 320, 5, 0, 2 * Math.PI, false);
 ctx_second.fill();

 // 文字盤
 ctx_bg.beginPath();
 var grad = ctx_bg.createRadialGradient(320,320,0,320,320,300);
 grad.addColorStop(0,"rgba(255,255,255,0)");
 grad.addColorStop(0.2,"rgba(255,255,255,0)");
 grad.addColorStop(1,"rgba(0,0,0,0.5)");
 ctx_bg.fillStyle = grad;
 ctx_bg.arc(320, 320, 300, 0, 2 * Math.PI, false);
 ctx_bg.fill();

 // 目盛り&数字
 for(i=1; i<=60; i++){
  ctx_bg.beginPath();
  ctx_bg.strokeStyle = "white";
  if(i%5 == 0){
   ctx_bg.lineWidth = 10;
   ctx_bg.moveTo(320+ 250*Math.cos(i*Math.PI/30),
                    320+ 250*Math.sin(i*Math.PI/30));
   ctx_bg.fillStyle = "white";
   ctx_bg.font = "bold 48px sans-serif";
   ctx_bg.textAlign = "center";
   ctx_bg.fillText(i/5, 320+ 220*Math.sin(i*Math.PI/30),
                    338- 220*Math.cos(i*Math.PI/30));
  }else{
   ctx_bg.lineWidth = 3;
   ctx_bg.moveTo(320+ 270*Math.cos(i*Math.PI/30),
                    320+ 270*Math.sin(i*Math.PI/30));
  }
  ctx_bg.lineTo(320+ 300*Math.cos(i*Math.PI/30),
                    320+ 300*Math.sin(i*Math.PI/30));
  ctx_bg.stroke();
 }
   ・
   ・
   ・

サンプルJavaScript16

外側の座標に当たる部分を変更しています。
単純に20引くだけで実現できましたね。
フォントサイズは変更していませんが、中央の赤丸は小さくしました。

ページトップへ

サンプル表示

サンプル表示16

基本サンプルファイルを実行すると、右のようになります。

やっぱセンス無ぇ〜


まだまだ不十分ですが、センス無いまま進めても、どんどん深みにハマっていくだけなので、ここでやめておきましょう。



今回のサンプルファイルのダウンロードは、こちらからどうぞーー>ダウンロード

ページトップへ

2013/01/14