JavaScript での有限状態マシン: 第 1 回 ウィジェットを設計する

JavaScript と有限状態マシンを使用したブラウザー・アプリケーションの開発

有限状態マシンは、ネットワーク・アダプターやコンパイラーなどのイベント駆動型プログラムにおける複雑な振る舞いの、設計および実装を体系づける方式として長年使用されてきました。今ではプログラム可能な Web ブラウザーが、新世代のアプリケーションに新しいイベント駆動型環境を提供しています。このようなブラウザー・ベースのアプリケーションは Ajax によって普及し、ますます複雑になってきています。そこで設計者や実装者の助けとなるのが、有限状態マシンが提供する規則と構造です。この記事では、有限状態マシンを使用して単純な Web ウィジェット (ビューでフェードイン、フェードアウトする動画化されたツールチップ) の複雑な振る舞いを設計する方法を説明します。

この連載の第 2 回では、第 1 回で設計したウィジェットを JavaScript で実装し、連想配列や関数クロージャーをはじめとした JavaScript 言語独特の機能を最大限活用する方法について説明します。さらに第 3 回では、この実装をよく使われているすべての Web ブラウザーで動作させるようにする上での実際的問題を取り上げる予定です。作成されるコードはコンパクトかつ簡潔でロジックもわかりやすく、その動画は負荷の高いプロセッサーでも滑らかに動作するものとなります。

Edward J Pring (pring@us.ibm.com), Senior Software Engineer, IBM 

Photo of Edward PringEdward Pring は、ニューヨーク大学でコンピューター・サイエンスの理学修士号を、スタンフォード大学で数学の理学士号を取得しています。IBM Research の一員として、オペレーティング・システム、パブリッシング・アプリケーション、メインフレーム用端末エミュレーター、パーソナル・コンピューター向けウィルス監視機能、Digital Immune System 対応のネットワーク・オートメーション、そして Web サービスの視覚化およびパフォーマンス分析など、広範な IBM 製品および技術に貢献しています。彼の特許ポートフォリオは、これらの分野すべてにまたがります。



2007年 1月 09日

この記事では、JavaScript をある程度使い慣れていて、JavaScript のより高度な機能をもっと深く理解したいという読者を対象としています。

長年の間、Web 設計者たちはよく使われている Web ブラウザーで JavaScript インタープリターをひそかに活用し、Web サイトの見映えをよくしてきました。その方法は主に、短いコード・スニペットを HTML ページにコピーするというものです。最近では Ajax の流行により、ソフトウェア・エンジニアもブラウザー内で実行する新世代のアプリケーションの開発に JavaScript を使用するようになってきています。ブラウザー・ベースのアプリケーションのサイズが大きくなるにつれ、他の実行環境を対象に発展した設計パターンと開発規則と同じものが必要になってくるはずです。

ブラウザー・ベースのアプリケーションは、マウス、キーボード、タイマー、ネットワーク、そしてプログラムのイベントが時を選ばずに発生するリアルタイム環境で実行されます。イベント駆動型アプリケーションの振る舞いがイベントの発生順によって異なる場合、プログラミングは非常に複雑になるため、デバッグするのも変更するのも難しくなります。ソフトウェア・エンジニアは、イベント駆動型プログラムの開発を体系づける方式として長いこと、有限状態マシンを使ってきました。これは学界では、離散的または決定性有限オートマトンと呼ばれることもあります。

有限状態マシンが課す規則は、複雑なロジックをわかりやすい表に置き換えて、設計に厳密さを加えます。その結果、実装は単純化され、テストするのも簡単になります。従来から、有限状態マシンはネットワーク・ドライバーとコンパイラーのような多様なプログラムを開発するのに有益であることが証明されています。ブラウザー・ベースのアプリケーションを開発する際にも、同じように有限状態マシンが役立つことになります。

この連載では、JavaScript 言語独特の以下の機能を調べるための演習として、サンプル有限状態マシン・アプリケーションを開発します。

  • 関数はファーストクラス・オブジェクトです。つまり、他のオブジェクトとまったく同じように、作成して、変数に割り当て、そして引数として渡すことができます。関数を別の関数内に定義してグローバル変数に割り当てることや、結果として返すことも可能です。このような関数は、その関数を定義する関数から処理が戻された後も存続します。
  • 関数は、その関数を定義する関数のローカル変数など、レキシカル・スコープ (関数の定義を囲む、ネストされた中括弧) 内の変数であればどれでも参照できます。このような変数は関数クロージャーの一部 (関数、関数独自の変数、関数が使用する (レキシカル・スコープ内の別の場所で定義される) 任意の変数) になり、こうした変数を定義する関数から処理が戻された後も存続します。
  • 関数は連想配列 (番号ではなく名前でインデックスが付けられた配列) に保管できます。

以上の言語特性は、イベントに対応したアクションと状態遷移を単純明快に体系づける手段となると同時に、ブラウザーのイベント・モデル間の違いに簡潔に対処する手段にもなります。

FadingTooltip というサンプル・アプリケーションは、たいていのブラウザーに組み込まれているデフォルトのツールチップよりも手の込んだツールチップです。FadingTooltip ウィジェットで作成されたツールチップは、ポップアップ表示されて唐突に消えるのではなく、ビュー上で動画を使ってフェードイン、フェードアウトし、さらにカーソルと連動します。この振る舞いの設計に有限状態マシンのパターンを用いると、ロジックがわかりやすいものとなり、また実装には JavaScript 言語の機能を使用すると、簡潔で効率的なソース・コードにすることができます。

この記事では、有限状態マシンの図による表現と表による表現を使用して、動画化されたウィジェットの振る舞いを設計する方法を紹介します。有限状態マシンの表による表現を JavaScript で実装する方法、そしてよく使われているブラウザーで実装をテストする上での実際的問題に対処する方法については、今後の記事で説明します。

基本的なツールチップ

最新のほとんどのグラフィカル・アプリケーションでは、ボタン、セレクター、入力フィールドなどの表示コントロールにカーソルを重ねると、定義、説明、あるいは推奨の使い方といった有用な情報を記載した小さなテキスト・ボックスが一時的に表示されます。このようなヘルプ・テキスト・ボックスは、初期の Apple システムでは「バルーン・ヘルプ (balloon help)」と呼ばれていました。一方、一部の IBM 製品では infopops と呼ばれ、一部の Microsoft 製品ではヒント (ScreenTips) と呼ばれることもあります。この記事ではもっと一般的な用語として、ツールチップと呼ぶことにします。

Netscape Navigator、Microsoft Internet Explorer、Opera、Mozilla Firefox などのよく使われている Web ブラウザーでは、title 属性を持つ HTML 要素に対してツールチップが表示されます。例えば、リスト 1 には title 属性を持つ 3 つの HTML 要素があります。

リスト 1. ブラウザーのツールチップの HTML コード
Here are some 
<span title='Move your cursor a bit to the right, please.'>
fields with built-in tooltips
</span>: 
<input type='text' 
       title='Type your bank account and PIN numbers here, please ...' 
       size=25>
<input type='button' 
       title='Go ahead. Press it. What's the harm? Trust me.' 
       value='Press this button'>

サンプル・ページに、title 属性を持つ HTML 要素をブラウザーがどのようにレンダリングするかを示します。カーソルを要素の上に重ねると、どのようにツールチップが表れて消えるかに注目してください。テキスト・ボックスに含まれているのは、フォーマットやスタイルが設定されていない単純なテキストです。テキスト・ボックスは、カーソルの動きが短時間止まった後にポップアップ表示され、ある一定の時間が経った後、あるいはカーソルがその HTML 要素から離れたり、キーが押されるとすぐに消えます。ブラウザーが一度に複数のテキスト・ボックスを表示することはありません。これらのツールチップの外観と振る舞いは元々ブラウザーに組み込まれているため、変更はできません。

より手の込んだツールチップ

組み込みツールチップには改善の余地が大いにあります。よく使われているブラウザーの最新バージョンでは、より手の込んだツールチップを作成するために必要なすべての素材を提供しています。HTML Division 要素は、ブラウザー・ウィンドウのどこにでも配置できるボックスを作成します。ボックスの外観については、ほとんどすべての点をカスケーディング・スタイル・シート (CSS) で決定できます。JavaScript でプログラミングしたカーソルの動きにより、ブラウザー・ウィンドウ内に表示されるどの要素に対しても特定のアクションを起動できます。また、タイマーをプログラミングしてアクションを順番に並べることもできます。

サンプル・ページには、より手の込んだツールチップを持つ HTML 要素もいくつかあります。よく使われているブラウザーの最新バージョンを実行すると、より手の込んだツールチップには組み込みのツールチップと比べて以下の違いがあります。

古いバージョンのブラウザーでは、この振る舞いをすべて見ることができない場合があります。例えばバージョン 9 より前の Opera ブラウザーでは、ツールチップはフェードイン、フェードアウトされずに、ポップアップ表示され、瞬時に消えます。これは、Opera では opacity スタイル・プロパティーの実装が比較的遅かったためです。よく使われているブラウザーの現行バージョンをダウンロードするには、「参考文献」を参照してください。

  • ツールチップは、ポップアップ表示され、瞬時に消えるのではなく、ビューにフェードインし、後にフェードアウトします。
  • ツールチップには、テキストだけでなく画像も含まれていて、フォーマットとスタイルが設定されています。
  • ツールチップが表示されている間はカーソルと連動します。
  • HTML 要素からカーソルを離すとツールチップがフェードアウトし、カーソルを戻すとフェードインします。
  • 複数のツールチップが同時に表示されることもあります。この場合、一方のツールチップがフェードアウトすると、もう一方がフェードインします。

このように拡張された振る舞いと外観は、体裁だけでなく使いやすさも改善します。例えば、ユーザーが数十、数百の要素であふれたページを見ていると、ビューに瞬時にポップアップ表示されるツールチップを見逃してしまうことがあります。とりわけ動きに敏感な人間の視覚システムにとっては、ユーザーの注意がページの他の部分に向けられているとしても、ビューにフェードインしてカーソルと連動するツールチップのほうが目に入りやすいものです。また、画像、フォーマット、そしてスタイルは、フォーマットされていないテキストよりも効果的に情報を伝えます。さらに、このような、より手の込んだツールチップでは、すべてのパラメーターが設定可能です。

この記事ではこの後、有限状態マシンとしての FadingTooltip ウィジェットの設計に焦点を絞ります。コードの実装とテスト方法については今後の記事で説明しますが、上記の例を今すぐ作成したいという方のために、「参考文献」に JavaScript ソースへのリンク、そしてそのソースを使用した HTML Web ページへのリンクを記載しています。

有限状態マシン

有限状態マシンがモデル化する振る舞いでは、将来のイベントに対する応答は以前のイベントに依存します。この分野には多数の学術的文献 (「参考文献」を参照) がありますが、実用されている定義は単純明快です。有限状態マシンは、以下のもので構成されるコンピューター・プログラムです。

  • プログラムが応答するイベント
  • イベント間でのプログラムの待機状態
  • イベントに対応した状態遷移
  • 状態遷移中に行われるアクション
  • イベント間のアクションに必要な値を保持する変数

有限状態マシンは、振る舞いが多種多様なイベントによって駆動される場合には非常に有益で、特定のイベントに対する応答は以前のイベントのシーケンスに依存します。有限状態マシンを駆動するイベントは、キーボード、マウス、タイマー、あるいはネットワークの動作によって発生するコンピューター外部のイベントであっても、アプリケーション・プログラムの別のパーツ、あるいは他のアプリケーションによって発生するコンピューター内部のイベントであっても構いません。

状態とは以前のイベントを記憶する手段で、状態遷移とは将来のイベントに対する応答を体系づける手段です。状態のうちの 1 つが初期状態として指定される必要があります。最終状態がある場合もありますが、これはオプションです。ちなみに、FadingTooltip ウィジェットには最終状態はありません。

有限状態マシンに共通の表現方法として、以下の 2 つがあります。

有向グラフ
バルーンが状態を表し、バルーン間の矢印が状態の遷移を表します。それぞれ、イベントおよびアクションのラベルが付けられます。
2 次元表
行と列がそれぞれイベントと状態を表し、各セルにアクションと状態遷移が示されます。

上記の 2 つの表現は等しいものですが、重点とする設計の側面が異なります。どちらも役に立つので、この記事ではこの後、両方の表現を使います。

有限状態マシンでイベント駆動型プログラムを開発するのは、通常の手続き型プログラミングより少々複雑で、一般的に必要となる規則が多くなり、特に設計作業が増えることになります。有効に開発すれば、コードの単純化、テストの迅速化、そしてメンテナンスの容易化を実現できますが、そうは言っても、有限状態マシンの複雑さがすべてのイベント駆動型プログラムで生かされるというわけではありません。例えばイベントの種類が少なかったり、イベントによって起動されるアクションが常に同じであれば、余分な開発作業は正当化されないでしょう。


有限状態マシンとランタイム環境

有限状態マシンはイベント駆動型なので、ラインタイム環境で有限状態マシン自体を対象イベントにフックするための方法が必要となります。これらのフックはイベント・ハンドラーと呼ばれる非常に小さなコード・フラグメントで、特定のイベントが発生すると常に実行するようにランタイム環境に挿入されます。イベント・ハンドラーが実行時に取得する必要がある基本情報は、以下のとおりです。

  • 発生したイベントのタイプ (カーソルが動いた、タイマーが満了したなど)
  • イベントのコンテキスト (カーソルが重ねられた HTML 要素、完了したネットワーク要求など)
  • 有限状態マシン独自の変数とメソッドの場所

イベント駆動型有限状態マシンを作成するには、JavaScript が適切です。実際に JavaScript はむしろ適切すぎるほどで、イベントをフックするのに 3 通りの方法を使えます。このそれぞれのイベント・モデルは複雑なものではありませんが、よく使われているすべてのブラウザーで確実に実行されるようにするには、プログラムがこの 3 つのイベント・モデルすべてを実装しなければなりません。そのうち 2 つのイベント・モデルでは、イベントのコンテキストがイベント・ハンドラーに直接渡されます。残りの 1 つでは、JavaScript 関数クロージャーによって、イベントのコンテキストをイベント・ハンドラーで囲むことができます。

JavaScript は Java プログラマーや C++ プログラマーにとっては多少奇異に見えるかもしないオブジェクト・モデルを提供しますが、それでも有限状態マシンの変数およびメソッドのコーディングには完全に適合します。さらに、JavaScript 連想配列を使えば、2 次元表による有限状態マシンの表現を直接コーディングすることも可能です。


振る舞いの系統的設計

有限状態マシンの根本材料は、応答対象のイベント、そしてイベント間での待機状態です。設計では以下のように、考えられる状態ごとに可能なイベントそれぞれについて検討しなければなりません。

  • 該当する状態で対象のイベントが発生する可能性があるかどうか
  • 対象のイベントを処理するために行うアクションは何か
  • イベントの後にどの状態に遷移するか
  • イベント間で記憶されなければならない変数は何か

まず初めに取り掛かるのは、図 1 に示す図です。この図では状態をバルーンで示し、状態遷移はバルーンを結ぶ矢印で示します。最後は図 4 に示す表で締めくくります。この表にはイベントと状態をそれぞれ行と列の見出しとしてリストします。表の各セルには、特定の状態で特定のイベントが発生したときに実行されるアクションをリストします。空白のセルは、該当する状態ではイベントが発生しないことを示します。

正確な図と表にするには、この設計手順を何回か繰り返さなければならないのが通常です。イベントと状態がたくさんある有限状態マシンの場合は、かなり面倒な手順になり、手順を繰り返す際に表内の各セルで系統的に作業するための規則も必要になります。こうしたことにより、考えられるあらゆる状況でどのような振る舞いが必要なのかを考慮することになり、振る舞いをさらに詳細に記述したり、あるいは絞り込んだりする機会があるかもしれません。または、最初に考えたよりも多くの (あるいは少ない) 状態が必要であることがわかったりすることがあります。すべての状況で正しい振る舞いを指定するには、セル間のアクションを入れ替えなければならない場合もあります。

有限状態マシンを設計するためのこの系統的手順は面倒なものですが、それだけの価値はあります。図 4 の完成した表では、振る舞いのロジックがすべて明らかになっているので、ロジックを直接コードに変換することができます (actionTransitionFunctions ソース・コードを参照)。


JavaScript の機能について

FadingTooltip ウィジェットを設計するには、JavaScript の機能をある程度知っていなければなりません。ここではトップダウン設計の姿勢で基本概念をスケッチし、実装の詳細についてはこの連載の次回の記事に回すことにします。

よく使われているブラウザーでは共通して、カーソルがページ上の HTML 要素を通過したときにイベントを JavaScript コードに渡すことができます。これらのイベントは、mouseover、mousemove、mouseout と呼ばれ、それぞれカーソルが HTML 要素上に重なったこと、要素上で動いたこと、そして要素から離れたことを示します。ブラウザーはこれらのイベントでカーソルの現在位置を渡します。JavaScript をプログラミングすれば、イベントが発生したときに動的に HTML Division 要素を作成してテキスト、画像、マークアップを入力し、この要素をカーソル近辺に配置できます。

ブラウザーには固有のフェードイン関数またはフェードアウト関数はありませんが、Division 要素の透明度 (実際には、透明度の反対の不透明度) を時間とともに変化させることで、フェードインやフェードアウトを行うことができます。

JavaScript には、2 種類のタイマーがあります。1 つは満了時に timeout イベントを生成するワンショット・タイマー、もう 1 つは timetick イベントを定期的に生成する繰り返しのティッカーです。FadingTooltip ウィジェットにはその両方が必要になります。


状態図のスケッチ

設計はまず、FadingTooltip ウィジェットに必要な基本的振る舞いを検討するところから始めます。カーソルが特定の HTML 要素上に重なったら、その要素上でカーソルが止まるまでウィジェットを待機させます。カーソルが止まったら、ウィジェットにツールチップをビューにフェードインさせ、しばらく表示した後にフェードアウトさせます。

この有限状態マシンに応答させるイベントには、以下があります。

  • カーソルが特定の HTML 要素上に重なったとき、その要素内で移動したとき、そしてその要素から離れたときにブラウザーが JavaScript に渡す mouseover、mousemove、mouseout の各イベント。
  • JavaScript によってプログラミングされた timeout イベントと timetick イベント。timeout イベントは、カーソルが一定時間停止したこと、またはツールチップの表示が一定時間に達したことを示します。timetick イベントは、フェードインあるいはフェードアウトを行うツールチップの不透明度の増減を動画で表します。

次に、マシンがイベント間で待機する状態を考案します。ここでは、ウィジェットの初期状態を Inactive と呼ぶことにします。Inactive 状態のウィジェットは、mouseover イベントによってアクティブにされるのを待ちます。アクティブにされたウィジェットは、timeout イベントによってカーソルが HTML 要素上で十分な時間停止したことが示されるまで Pause 状態で待機します。timeout イベントが発生すると、timetick イベントでフェードインが動画で表されている間、FadeIn 状態で待機し、その後 Display 状態で別の timeout イベントを待機します。timeout イベントが発生すると、さらに timetick イベントが発生してフェードアウトが動画で表されている間、FadeOut 状態で待機します。ウィジェットは最終的に、Inactive 状態に戻り、別の mouseover イベントを待機します。

図 1 に、この進行状態を図の形でスケッチします。状態はバルーン、状態遷移は状態を結ぶ矢印、そしてイベントは矢印のラベルで示します。初期状態を示すのは、二重線で囲まれたバルーンです。

図 1. 状態図の最初のスケッチ
図 1. 状態図の最初のスケッチ

FadingTooltip ウィジェットは、処理対象のイベントごとに以下のアクションを行うことになります。

  • Inactive 状態で mouseover イベントが発生すると、ワンショット・タイマーを起動し、それから Pause 状態で待機します。
  • timeout イベントが発生すると、ツールチップを作成し (初期不透明度はゼロに設定)、繰り返しのティッカーを起動してから FadeIn 状態で待機します。
  • timetick イベントが発生するごとに、ツールチップの不透明度を少しずつ増やしていきます。ツールチップが最大の不透明度に達したら、ティッカーをキャンセルして別のタイマーを起動し、Display 状態で待機します。
  • timeout イベントが発生すると、別のティッカーを起動し、その後 FadeOut 状態で待機します。
  • FadeOut 状態で timetick イベントが発生するごとに、ツールチップの不透明度を少しずつ減らしていきます。ツールチップの不透明度がゼロになったら、ティッカーをキャンセルし、ツールチップを削除して Inactive 状態に戻ります。この状態で、別の mouseover イベントによって再びアクティブにされるまで待機します。

図 2 のスケッチには、上記のアクションが対応する起動イベントの下に記入されています。

図 2. アクションをイベントに追加した状態図の初期スケッチ
図 2. アクションをイベントに追加した状態図の初期スケッチ

状態図から状態表への変換

上記の図による表現は、有限状態マシン設計の手始めとしてはふさわしい方法ですが、設計を完成させるには表による表現のほうが適しています。なぜなら、表による表現では検討対象のイベントと状態のあらゆる組み合わせが一目瞭然だからです。

状態図を状態表に変換するには、行にイベント名、列に状態名のラベルを付けます。名前の順序は任意なので、ここでは初期状態を最初の列に配置し、開始イベントを最初の行に配置します。次に、各イベントのアクションと次の状態を表内の該当するセルにコピーします。すると、図 3 のようになります。

図 3. 初期状態図に対応した初期状態表
図 3. 初期状態図に対応した初期状態表

状態表の仕上げ

有限状態マシンの設計を完成させるには、表内の空のセルそれぞれについて検討する必要があります。つまりセルごとに、該当する状態で該当イベントが発生する可能性があるかどうか、もしそうであれば、その状況でウィジェットはどんなアクションを行うべきなのか、そして次の状態は何になるべきかを検討します。これは単調でうんざりするような作業ですが、設計プロセスに必要不可欠の部分です。

セルを検討する順序は関係ありません。一般的な方法としては、設計プロセス中に毎回違った順序でこの手順を何度も繰り返し、各セルを再三にわたって検討してセルのコンテンツの修正をたびたび重ねることです。また、設計の進化に従って状態を追加 (または除去) し、それに応じてさらに修正を加えることも珍しくありません。この繰り返しの手順は省略しますが、状態とイベントごとの結果を以下に概説して、この設計を要約します。

Inactive 状態

この状態で発生するのは、図による表現ですでに検討済みの開始イベント、mouseover だけです。mousemove および mouseout イベントが発生するのは mouseover イベントの後で、Inactive 状態で作動中のタイマーは 1 つもないからです。したがって、最初の列の残りのセルには「発生しない」というマークを付けられます。

ただし、次に進む前に Inactive 状態での mouseover イベントについてもう少し詳しく検討しましょう。最終的にツールチップの HTML Division 要素を作成するときには、この要素をカーソルの近くに配置することになるため、カーソルの現在位置を保存すれば、ブラウザーがこのイベントでカーソルの現在位置を渡せるようになります。また、作動中のタイマーをキャンセルしてから新しいタイマーを起動するのも良い慣例です。そのため、mouseover セルにはこれらのアクションを追加してください。

Pause 状態

タイマーの満了を待機している間に、カーソルが HTML 要素内で移動したり、HTML 要素から離れたりする可能性があります。そのため、そのようなイベントが発生した場合に行うアクションと、その次の状態を決定します。この状態で mouseout イベントが発生した場合には、カーソルが HTML 要素上にまったく重ならなかったかのように FadingTooltip ウィジェットを Inactive 状態に戻すことができますが、タイマーはキャンセルする必要があります。mouseout セルには、このアクションと状態遷移を記入します。

一方、mousemove イベントの場合には、ウィジェットが引き続きカーソルの停止を待機するようにできますが、それにはタイマーをキャンセルして再スタートする必要があります。また、ツールチップはカーソルの近くに表示させるので、保存されたカーソル位置の更新も必要になります。検討時に、Pause 状態での mousemove イベントに対するアクションと状態遷移が、Inactive 状態での mouseover イベントの場合と同じだということに気付くと思いますが、両方のセルにすべての内容を繰り返し記入するのではなく、mousemove セルにこれが重複であることを直接示してください。この列の残りのセルには、「発生しない」というマークを付けます。

FadeIn 状態

この状態では、timetick イベントによってフェードインが行われている間、カーソルを引き続き動かせます。mousemove イベントが発生した場合、ツールチップを連動させて現行状態を維持します。mouseout イベントが発生した場合には、ティッカーが実行されたまま FadeOut 状態に遷移するので、以降の timetick イベントではツールチップの不透明度は現在の値から次第に減少することになります。これらのイベントに対するアクションと状態遷移を該当するセルに記入し、この列の残りのセルにはすべて「発生しない」というマークを付けてください。

Display 状態

カーソルはもちろん、引き続き移動できます。カーソルが HTML 要素内で移動した場合には、FadeIn 状態の場合と同じアクションを取ることができます。つまり、ツールチップをカーソルに連動させるということです。HTML 要素から離れた場合には、Display 状態での timeout イベントと同じアクションと状態遷移を適用します。これらの重複はそのまま、mousemove セルと mouseout セルにそれぞれ示し、残りのセルにはすべて「発生しない」というマークを付けます。

FadeOut 状態

この状態では、timetick イベントによってフェードアウトが行われている間、カーソルが引き続き移動できます。カーソルが HTML 要素内で移動した場合、FadeIn および Display 状態の場合と同じアクションを取ります。HTML 要素から離れた場合には何のアクションも必要ありません。ティッカーは実行し続けるため、以降の timetick イベントによってツールチップの不透明度は現在の値からゼロになるまで減少することになります。

このセルには「発生しない」というマークを付ける代わりに、必要なアクションはないことを示します。また、カーソルが HTML 要素に戻った場合には、ツールチップをカーソルに戻して FadeIn 状態に戻ります。

図 4 に、上記の追加アクションと状態遷移をすべて示します。空のセルは「発生しない」ことを示します。

図 4. FadingTooltip ウィジェットの設計に従った状態表
図 4. FadingTooltip ウィジェットの設計に従った状態表

表による表現と図による表現は同等であるため、有限状態マシンの表による表現は常に図による表現に戻すことができます。図 5 は、完成した表を図による表現にしたものです。

図 5. FadingTooltip ウィジェットの設計に従った状態図
図 5. FadingTooltip ウィジェットの設計に従った状態図

状態変数リストの作成

状態表および状態図が完成したら、それをもう一度検討して、マシンがイベント間で記憶しておかなければならない変数のリストを作成し、異なるセルで該当アクションを実行できるようにすると便利です。この有限状態マシンには、リスト 2 に記載した項目の状態変数が必要になります。

リスト 2. 状態変数の初期リスト
currentState         string value equal to one of the state names
currentTimer         pointer to timer object, obtained when set, used to cancel
currentTicker        pointer to ticker object, obtained when started, used to cancel
currentOpacity       float that varies from 0.0 (invisible) to 1.0 (fully visible)
lastCursorPosition   floats obtained from cursor events, used when an HTML Division 
                       element is created
tooltipDivision      pointer to HTML Division element, set when created, used when 
                       faded, moved, or deleted

JavaScript 変数には型がありませんが、変数に含まれるのは型付きの値です (つまり、あらゆる型の値を任意の変数に割り当てられます)。そのため状態変数の名前は自由に選んで、注釈に、それぞれの変数に割り当てられることになる型を示しました。


実装の準備ができました

状態表と状態変数のリストが完成した今、有限状態マシンを実装する準備は万端です。実装については次回の記事で取り上げますのでお楽しみに。ひとつここで忘れてはならないのは、開発とは繰り返しのプロセスだということです。つまり、この設計段階にまた戻らなければならないことは大いに考えられます。

ダウンロード

デモ: ブラウザーのツールチップと FadingTooltip ウィジェットの例

コード・サンプル: ブラウザーのツールチップと FadingTooltip ウィジェットの例に対応する HTML ソース・コード

コード・サンプル: FadingTooltip ウィジェットの JavaScript ソース・コード

参考文献

学ぶために

製品や技術を入手するために

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development
ArticleID=254481
ArticleTitle=JavaScript での有限状態マシン: 第 1 回 ウィジェットを設計する
publish-date=01092007