いきなりやってみよう3(JavaScript編)

ごあいさつ

「いきなりやってみようシリーズ」も、とうとう第3弾となりました。
皆様いかがお過ごしでしょうか?

これまでは、文字装飾に重点をおいてやってきましたが、これには意味があるのです。
この「ウィジェットを作る」を作成するに至った理由の1つでもあるのですが、世にあるウィジェットがどのように作られ、どのように動いているかいろいろ見てみたのです。
「どのように動いているか」というのは、自身のブログなどで紹介されている方が多くいらっしゃるので、「動き」に関しては特に自分で確認するまでもありません。
そこで、そのウィジェットがどのように作られているかを知るために、中身を見てみました。
未だ、「中身の美しいウィジェット」に出会っていませんが、とても気になった点があります。
それは、「画像が多すぎる」という点です。
おそらく、作者にとってみれば画像でしか表現できないウィジェットなのでしょうが、キャリア画像やテーマを作ってみて思うのですが、画像を作るのって結構面倒なんです。
画像が多いと変更も大変だし、それ以上にテーマファイルがとても重くなってしまいます。
画像でしかできないなら仕方がないのですが、「文字で代用できるならそうしませんか?」という問いかけを今までしてきたのです。

ここでは、ホーム画面に表示される「時計」を作ってみます。
時計はとてもオーソドックスなネタで、多くの方が作っています。
そして、「画像が多すぎる」と、とても気になったのも、「時計」なんです。
ですので、できるだけ画像を使わず、シンプルだけど何かデザイン的に魅かれるような時計を作ってみようと思います。今のところ「見切り発車」です。

ファイルを用意する

Fig.1 サンプルファイル構成

ここで使うファイルを紹介します。
基本構成は何も変わりません。
ここからJavaScriptを使うので、JSファイルが追加されています。加えて、背景画像用にimagesフォルダと、その中に画像を用意しました。

Fig.1は、ここで使用するサンプルの構成です。
ダウンロードはこちらからどうぞ。
こちらも、ダウンロードが嫌な方は、この図を参考にして自作して下さい。
それぞれの「サンプルHTMLソース」や「サンプルスタイルシート」の部分にダウンロードファイルのリンクを張っておきます。

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

ページトップへ

サンプルHTML

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

<?xml version="1.0" encoding="utf-8"?>
<html>
 <head>
  <meta name="viewport" content="width=device-width"/>
  <script src="./test.js" type="text/javascript"></script>
  <link href="./test.css" rel="stylesheet" type="text/css" />
 </head>
 <body onload="time_update()">
  <div id="wallpaper">
   <img src="./images/img_01.jpg" width="320" height="480">
  </div>
  <div id="container">
   <p id="time">12:00:00</p>
  </div>
 </body>
</html>

サンプルHTMLソース

基本的には変わっていません。
追加・変更された部分を説明します。
<head>内には、JSファイルが新たに追加されました。これは、ここで説明する「時計」の心臓部分です。
<body>にも追加があります。時計は表示しただけでは機能しません。時間が進む度に書き換えないと意味のない時計になってしまいます。 JSファイルの「時間を書き換える」という部分を呼び出します。
最後の<div>部分が、時計の表示部分です。この段階では、中にあるpタグだけでも表示できるのですが、この先日付なども一緒に表示しようとすると、それらをまとめておく必要があると判断したので、この段階からdivタグを使っておきます。

文字ばかりでは分かりにくいので、HTMLで構成される要素を視覚的に表現してみました。

HTMLイメージ1

奇抜なデザインで申し訳ございません。
container以下の要素でのイメージですので、背景画像を表示する要素は省いてあります。
<div id="container">から</div>の間に、pタグを記述することで、containerという土台の上にtimeという表示部分(pタグ)が乗っかるイメージです。
こうすることで、containerを移動すれば、その上に乗っているものはすべて移動することができるようになります。
HTMLの記述方法とHTML要素イメージを照らし合わせてみましょう。今はまだ分からなくても、そのうち分かるようになるはずです。

ページトップへ

サンプルスタイルシート
* {
   margin: 0;
   padding: 0;
   border: 0;
}

#wallpaper {
   position: absolute;
   top: 0px;
   left: 0px;
}
#container {
   width: 320px;
   height: 1em;
   position: relative;
   top: 300px;
   left: 0px;
   font-size: 48px;
   line-height: 1em;
   text-align: center;
}
p {
   width: 200px;
   margin-right: auto;
   margin-left: auto;
   color: black;
   font-weight: bold;
   text-shadow:0px 0px 1px white,
          0px 0px 1px white,
          0px 0px 1px white;
}

サンプルスタイルシート

次に、スタイルシート(test.css)の内容を紹介します。

「*」が出てきました。
世の中のほとんどのサイトで見られる設定なのですが、全ての要素に対する記述方法です。この書き方で、すべての余白や枠線などをリセットします。

#containerは時計を表示するpタグを乗せる「土台」と思って下さい。
今後、日付などを表示するときも、この「土台」に配置する形で進めます。
幅は横いっぱいの320px、高さは1文字分を指定します。表示される文字の高さも1文字分としましたが、その1文字分というのは、ここでは48pxとしたフォントサイズが基準です。
全体の位置を上から300pxの場所にしました。

pは実際に時計の文字が表示される部分です。このpタグはcontainerというidを持つdivタグの中にあるので、スタイルシートの#containerの内容が継承されます。
つまり、pの設定をしなくても、フォントサイズが48pxだったり、文字も中央寄せだったりする訳です。
継承される値を念頭に置いて、ここでは、幅を200pxにして、左右の余白を「auto」にすることで、中央寄せを実現しています。(パソコンでの表示とiPhone4での表示に差があったための措置です)
あとはフォントに関するプロパティですので省略します。
これまでサンプルをいくつか紹介しましたが、サンプルによってiPhoneが壊れることはありませんので、プロパティの値をいろいろ変えて試してみて下さい。

ページトップへ

サンプルJavaScript

では、お待ちかねのJSファイルを紹介します。
以下に示すのが、test.jsの中身(ソース)です。

function time_update() {
  setTimeout("time_update()",1000);
  setTime();
}

function setTime() {
  date = new Date().toString();
  document.getElementById("time").innerHTML = date.substr(16,8);
}

サンプルJavaScript

functionが関数の定義なのですが、この中にやりたいことを記述していきます。
ここには、time_update()と、setTime()という関数を定義しています。

では、time_update()から説明します。
HTMLファイルの<body>に、onload="time_update()"とありましたが、HTMLによるページが表示されると、onloadによってこの関数が呼び出される仕組みとなっています。
そして、time_update()でやりたいことが{}の間に書かれています。
SetTimeout()は、「指定した時間」後に、「指定した関数」を呼び出すタイマーの働きをします。
「指定した時間」というのが、ここでは1000となっていますが、単位はミリ秒なので、指定時間は1秒ということです。
そして、「指定した関数」というのが、time_update()です。
つまり、1秒おきに自分自身を呼び出すことで、毎秒同じ関数を実行することができます。
これだけでは、単なる無限ループを作っただけに過ぎません。
time_update()の中には、もう一つやりたいことが書かれています。
それが、setTime()です。
time_update()は、毎秒setTime()を呼び出す関数として定義されています。
そして、このsetTime()も関数であり、time_update()と同様に定義されています。

では、setTime()について説明します。
new Date()で日付情報を取得しますが、この日付情報は数値なので、扱いやすくするために、文字列に変換し、それをdateに格納するようにしています。
日付情報には、日付と時刻がありますが、文字列にしたdateから必要な部分だけ取り出します。
その必要な部分が時刻の部分であり、文字列の16番目から8文字が時刻を表しています。
date.substr(16,8)で、文字列の16番目から8文字抜き出しますが、その抜き出した文字を、id "time"で定義される要素に書き込みます。
つまり、このsetTime()は、呼び出される度に日付情報を取得し、その時刻部分のみを時刻表示部分に書き込みます。
HTMLに、<p id="time">12:00:00</p>とありますが、書き換えるべき時刻表示部分は、まさにこの「12:00:00」の部分を指します。

Fig.2 サンプル表示結果

では、サンプルを実行してみましょう。
Fig.2がサンプルを実行した画面のスクリーンショットです。
iPhone4の時刻とウィジェットの時刻を見比べてみて下さい。

もちろん違っている訳はないのですが、きちんと時刻が取得され、HTMLにあった「12:00:00」の部分が1秒おきに書き換えられていることが確認できればそれで結構です。

サンプルファイルが、それぞれの役割を果たすことで実現できるのですが、それぞれが上手く絡み合うことも重要です。
これからは、JavaScriptを中心に紹介していきますが、それに伴い、HTMLやスタイルシートの変更があることもご了承下さい。


それにしても、かなり長くなりましたね。
スタイルシートのように徐々に拡張していこうとおもったのですが、このペースだとものすごく長くなってしまうことが明らかなので、駆け足で進めていこうと思います。

ページトップへ

スタイルシートで装飾する
p {
   width: 240px;
   margin-right: auto;
   margin-left: auto;
   color: black;
   font-family: "DB LCD Temp";
   font-weight: bold;
   text-shadow:0px 0px 1px white,
          0px 0px 1px white,
          0px 0px 1px white;
   padding: 5px;
   border: 3px solid black;
   -webkit-border-radius: 10px;
   -webkit-box-shadow:
       0px 0px 10px 5px yellow,
       0px 0px 10px 5px yellow inset;
   background: transparent repeat;
   -webkit-background-size: 10px 10px;
   background-image:
    -webkit-gradient( linear,
     left top, left bottom,
     from(transparent),
     color-stop(0.5,transparent),
     color-stop(0.5,rgba(255,255,255,0.5)),
     to(rgba(255,255,255,0.5))
    ),
    -webkit-gradient( linear,
     left top, right top,
     from(transparent),
     color-stop(0.5,transparent),
     color-stop(0.5,rgba(255,255,255,0.5)),
     to(rgba(255,255,255,0.5))
    );
}

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

とりあえずサンプルでは、時刻表示したことで目的を達成したのですが、少し装飾してみましょう。

装飾するのは、pのみなので、pのみを紹介します。
手を加えたところは赤にしておきますが、説明は省きます。

今回の装飾ポイントは、グラデーションを縦と横で組み合わせることでチェック柄にしたことです。
色指定に「transparent」を使っていることもポイントです。
フォントは、デジタルはこうじゃなきゃ!ってことで、7セグのフォントにしました。

いろいろ試してみて下さい。


(HTMLとJavaScriptに変更はありません)

Fig.3 サンプル表示結果

簡単な装飾ですが、こんな感じでしょうか。

実行した方は、すぐお分かりになったと思いますが、等幅フォントではないため、毎回と言って良いほど表示位置が変わります。
「等幅フォントにする」という安易な解決方法は望まないので、ここでまた方向性を固めようと思います。
まぁ、フォントに左右されないレイアウトにするってだけの話なんですけどね。
という訳で、時刻表示部分を分割します。

ページトップへ

時刻表示部を分割する

では、時刻表示部を分割してみましょう。
ここまでは、コロンを含めた時間・分・秒を一塊で扱ったため、時間を表示するpタグも1つで済んでいました。
表示部分を分割するということは、表示部分が増えるので、HTMLが変わります。レイアウトも分割した表示部分への指定になるため、スタイルシートも変わります。
書き換えも分割した表示部分に対しての処理になるため、JavaScriptも変わります。

では、HTMLから紹介します。
以下に示すのが、Wallpaper.htmlの中身(ソース)です。

<?xml version="1.0" encoding="utf-8"?>
<html>
 <head>
  <meta name="viewport" content="width=device-width"/>
  <script src="./test.js" type="text/javascript"></script>
  <link href="./test.css" rel="stylesheet" type="text/css" />
 </head>
 <body onload="time_update()">
  <div id="wallpaper">
   <img src="./images/img_01.jpg" width="320" height="480">
  </div>
  <div id="container">
   <div id="clock">
    <p id="hour">12</p>
    <p id="colon1">:</p>
    <p id="minute">00</p>
    <p id="colon2">:</p>
    <p id="second">00</p>
   </div>
  </div>
 </body>
</html>

サンプルHTMLソース3

containerは、時計だけでなくいろいろなものを乗せるつもりなので、そのままにします。
そのため、時計部分のパーツを乗せる土台を新たに作りました。その土台のidを"clock"としました。その中で、時計を構成するパーツを5コに分け、それぞれにidを付けます。
このidは要素を特定するためのものなので、他のidと重複しないようにします。
特に、コロン(:)は2つありますが、表示位置が異なるため、違うidを振り分けます。
<追記>
「同じスタイルなら同じidで良いのか?」と思った方は、かなりセンスの良い方です。
でもその場合は、idではなく、classを使用します。(説明は省略)

では、こちらもイメージを紹介します。

HTMLイメージ3

これはイメージなので、高さもなければ奥行きもありません。
要素の包含関係が分かればそれで十分です。(だから画像もこの程度・・・)
clockを移動させると、すべての時間表示用パーツが移動しますが、それはcontainerの上で移動しているだけのことです。
containerを右に100px、clockを左に100px移動しても、結果的に時計表示は移動しないことが理解できれば、もう高校数学は卒業!ってくらいです。


ページトップへ

#clock {
  width: 240px;
  height: 1em;
  position: relative;
  margin-right: auto;
  margin-left: auto;
  padding: 5px;
  border: 3px solid black;
  -webkit-border-radius: 10px;
  -webkit-box-shadow:
    0px 0px 10px 5px yellow,
    0px 0px 10px 5px yellow inset;
  background: transparent repeat;
  -webkit-background-size: 10px 10px;
  background-image:
   -webkit-gradient( linear,
     left top, left bottom,
     from(transparent),
     color-stop(0.5,transparent),
     color-stop(0.5,rgba(255,255,255,0.5)),
     to(rgba(255,255,255,0.5))
  ),
  -webkit-gradient( linear,
    left top, right top,
    from(transparent),
    color-stop(0.5,transparent),
    color-stop(0.5,rgba(255,255,255,0.5)),
    to(rgba(255,255,255,0.5))
  );
}
p {
  color: black;
  font-family: "DB LCD Temp";
  font-weight: bold;
  text-align: center;
  text-shadow:0px 0px 1px white,
         0px 0px 1px white;
  position: absolute;
  top:10px;
}
p#hour { left: 20px; width: 60px; }
p#collon1 { top: 0px; left: 80px; width: 20px;}
p#minute { left: 100px; width: 60px; }
p#collon2 { top: 0px; left: 160px; width: 20px;}
p#second { left: 180px; width: 60px; }

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

では、スタイルシートの変更も見ていきましょう。

枠線などの装飾はclockに対しての指定になります。
文字に関するスタイルはpタグに対して指定しますが、その記述方法にちょっと工夫があります。
pタグのidそれぞれに共通するスタイルの指定をまとめてあるのです。

例えば、小学生1人1人に名札を付けながら、その子が6年生だったら教室へ、5年生だったら体育館へ、該当しなければ運動場へ行くように指示を出すとしましょう。
どうせ名札を付けるのですから、それぞれに指示を出せば良いように思えますが、工夫する方法もあるのです。
名札付けの作業は変わりません。ただ、指示を出さずに名札付けに集中します。
そして、「全員、運動場へ集合!!ただし、5年生は体育館へ、6年生は教室へ集合して下さい」とアナウンスすれば簡単だと思いませんか?
後から出された指示が有効になるというメリットを活かした工夫ですが、スタイルシートも同様に後からの指示が有効なので、共通するものは先に指定しておくと理解しやすく、記述量も減るので、できるだけこのようなやり方で記述するようにしましょう。

pの部分でフォントや色などを指定しているので、p#hourなど個別のp指定では、幅と位置の指定しかしていなくても文字の影まで継承されています。
(記述は横一列でもOKです)

次に、JSファイルを紹介します。
以下に示すのが、test.jsの中身(ソース)です。

function time_update() {
  setTimeout("time_update()",1000);
  setTime();
}

function setTime() {
  date = new Date().toString();
  document.getElementById("hour").innerHTML = date.substr(16,2);
  document.getElementById("minute").innerHTML = date.substr(19,2);
  document.getElementById("second").innerHTML = date.substr(22,2);
}

サンプルJavaScript3

変更部分は3行です。
これまでの流れだと、コロンの部分もここで書き換える形になるのでしょうが、HTMLで表示してあるので、ここでの書き換えは省略します。(これもテクニック!?)
「時間」、「分」、「秒」それぞれ取得して書き換えます。
人間の考え方なら、変更される部分だけ書き換えれば良いように思えますが、「どの部分が変更箇所なのか?」ということも記述しなければならないため、このようにすべて書き換えるのがシンプルなんですね。

Fig.4 サンプル表示結果

Respringして表示した結果です。
文字全体にスタイルが継承されていることを確認して下さい。

この表示を見てお気付きかと思いますが、やはり"1"の表示がネックになっているようです。
いくら等幅ではないといっても、これではセンスのない私でもダメ印を押してしまいます。
パーツではなく、文字で分ける必要が出てきてしまいました・・・

ページトップへ

時刻表示部を一文字ずつ分割する

では、時刻表示部を一文字ずつ分割してみましょう。
もうしばらくお付き合い下さい。
一文字ずつということは、時間・分・秒それぞれが2つに分割されることになり、2つのコロンを含めて8コのパーツになります。
したがって、HTMLもスタイルシートもJavaScriptも変わります。

では、HTMLから紹介します。
以下に示すのが、Wallpaper.htmlの中身(ソース)です。

<?xml version="1.0" encoding="utf-8"?>
<html>
 <head>
  <meta name="viewport" content="width=device-width"/>
  <script src="./test.js" type="text/javascript"></script>
  <link href="./test.css" rel="stylesheet" type="text/css" />
 </head>
 <body onload="time_update()">
  <div id="wallpaper">
   <img src="./images/img_01.jpg" width="320" height="480">
  </div>
  <div id="container">
   <div id="clock">
    <p id="hr1">1</p>
    <p id="hr2">2</p>
    <p id="cl1">:</p>
    <p id="mn1">0</p>
    <p id="mn2">0</p>
    <p id="cl2">:</p>
    <p id="sc1">0</p>
    <p id="sc2">0</p>
   </div>
  </div>
 </body>
</html>

サンプルHTMLソース4

今回は、パーツを一文字ずつで分けただけなので、containerもclockもそのままです。
それぞれにidを付けますが、今回は識別できる範囲で簡素化しました。
したがって、コロンのidも変わっているため、赤文字にしました。

では、こちらもイメージを紹介します。

HTMLイメージ4

くどいようですが、これはイメージです。
分かる方には、突っ込み所満載の図となっております。
スタイルシートでの指定がない段階では、横に並びませんから・・・残念!

ページトップへ

p {
  width: 30px;
  color: black;
  font-family: "DB LCD Temp";
  font-weight: bold;
  text-align: right;
  text-shadow:0px 0px 1px white,
         0px 0px 1px white;
  position: absolute;
  top: 10px;
}
p#hr1 { left: 10px; }
p#hr2 { left: 40px; }
p#cl1 { top: 0px; left: 70px; width: 20px; }
p#mn1 { left: 95px; }
p#mn2 { left: 125px; }
p#cl2 { top: 0px; left: 155px; width: 20px; }
p#sc1 { left: 180px; }
p#sc2 { left: 210px; }

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

では、スタイルシートの変更も見ていきましょう。

今回は、文字幅を先にpで指定しておきます。これにより、個別に幅を指定する必要がなくなります。
ただ、コロン(:)だけは後で狭くしてあります。これは縦位置"top"も同様です。
そして、今回の大きなポイントは「文字寄せ」です。
"text-align"を"right"にしました。
数字のほとんどに「横棒」が入っているため、中央寄せでも問題なかったのですが、この"1"の野郎のおかげでここまで問題が大きくなってしまったのです。
考えてみると、7セグデジタル表示の"1"って右側の縦線を使ってますよね?
という訳で、文字を全て「右寄せ」にしました。

次に、JSファイルを紹介します。
以下に示すのが、test.jsの中身(ソース)です。

function time_update() {
  setTimeout("time_update()",1000);
  setTime();
}

function setTime() {
  date = new Date().toString();
  document.getElementById("hr1").innerHTML = date.substr(16,1);
  document.getElementById("hr2").innerHTML = date.substr(17,1);
  document.getElementById("mn1").innerHTML = date.substr(19,1);
  document.getElementById("mn2").innerHTML = date.substr(20,1);
  document.getElementById("sc1").innerHTML = date.substr(22,1);
  document.getElementById("sc2").innerHTML = date.substr(23,1);
}

サンプルJavaScript4

変更部分は6行になりました。
一文字ずつ取り出して、一文字ずつ書き換えていることを確認して下さい。

Fig.5 サンプル表示結果

Respringして表示した結果です。
どの時間でも、「ズレ」がなくなりました。ミッションクリアです!

よ〜く見てみると、ドット単位のズレがありますが、これ以上はフォントを弄らないといけないので、これで勘弁して下さい。

それにしても長くなりましたね。
このフォントのおかげで・・・
一般的なフォントなら、一文字ずつ分割しなくてもできたと思います。
でも、これはこれで私自身が勉強になったので、結果的に良いフォントをサンプルで選んだなぁと思います。

ページトップへ

日付を表示する

時計表示の「ズレ」に惑わされてしまい、日付をすっかり忘れていました。
ここまででお疲れモードなので、説明は手抜きします!

デザインは、お得な「据え置き」です。
秒表示の部分を日付にしました。
ファイルを見て頂ければ分かるかと思いますが、"date"という土台を作り、そこで日付に関する表示をしています。
日付表示に関するウィジェットで、日本語表示は見たことがないので、あえて日本語表示にしてみました。ただそれだけなので、デザインには凝っていません。
さらに、あまり時間をかけたくなかったので、スタイルシートもスマートではありません。
「画像を使わずこれくらいはできますよ」というサンプルです。

Fig.6 サンプル表示結果

Respringして表示した結果です。
必要なパーツは揃っているので、スタイルシートをいろいろ弄ってみて下さい。

ダウンロードはこちら

ページトップへ

オマケ

ここまでの集大成として、サンプルを作ってみました。
時計には変わりないのですが、HTMLでホーム画面に表示する土台を作り、JavaScriptで動作を記述し、スタイルシートでレイアウト・装飾するという基本の上に成り立つウィジェットです。
説明は省略しますが、サンプルを実際に動かしてみて、ファイルの中身を覗いてみて下さい。
「ここを弄るとここが変わるんだろうなぁ〜」ぐらいで十分です。
すでに色んなものが出回っており、誰もやっていないものを作ろうとする方が至難の業なので、自分の個性に近いものを探して、それに手を加えることができるようになっていただければと思います。

HTC風時計ウィジェット

Fig.7 HTC風時計ウィジェット

せっかくなので、あの有名なHTC端末でよく見かける時計っぽくしてみました。
一度は見かけたことがあると思います。

本家では、時計の文字表示に画像を使っているため、フォントの変更などができず、敷かれたレールの上を歩くしかありません。
デザインが気に入っていればそれで良いのかもしれませんが・・・

という訳で、画像を一切使わず、右のようなウィジェットを作ってみました。
フォントサイズを基準にデザインしてあるので、フォントサイズを変更すれば、他のすべてがリサイズされます。
目的が時計なので、日付表示まではやっていません。(そのうちやります)
スタイルシートも、もっとシンプルにできるはずなのですが、これ以上はやっていません。
スタイルシートでアニメーションもできるので、パラパラめくれる表示にしようと思ったのですが、ここまでにかかった時間の何倍もかかりそうなので、ここで終了しておきます。

ダウンロードはこちら

ページトップへ

2011/04/04