
Adobe
Spry周期表(図1)は、Spryのテクニックを駆使した実験サンプルです。Spryコミュニティの方なら、ここで使っているテクニックには興味を持っていただけると思います。この記事では、Spry周期表で使用しているコードの考え方や手法を段階に分けて解説しています。
実際に Spry周期表を見て触ってみてください。

図1:Spry周期表。ページの上部には、元素の特性などを記したリングボタンがあり、クリックすると該当する元素がハイライト表示されます。また、ツールチップを使って、元素へマウスオーバーした際に、その元素の詳細情報を表示するようにしています
Spry周期表では、各元素のデータはHTMLテーブルで用意し、それをも元にSpryのHTML Data Set を使って、各元素データを周期表にレイアウトしています。元素のHTMLテーブルは、このSpry周期表と同じページに記述しいているので、ページのローディングも速いですし、コンテンツを検索エンジンにインデックスしてもらえます。また、元素のデータをHTMLテーブルにしておけば、作成するのが簡単だし、XML形式で用意する場合に比べてデータ編集も楽に行えます。しかもDreamweaverなどのツールを使ってデザインビューで編集することも可能です。
このHTMLテーブルで用意した元素データをもとに、周期表のレイアウトへと仕上げるには、「Spry:repeats」と「Spry:regions」、そしてCSSのclass属性を活用します。このCSSのclass属性はハイライト機能にも利用します。ページの上部には、元素の特性などを記したリンクボタンがあり、クリックすると該当する元素がハイライト表示されます。
また、ツールチップを使って、元素へマウスオーバーした際に、その元素の詳細情報を表示するようにしています。
各元素のデータは、以下のようなHTMLテーブルで用意しています。
| No | Atomicweight | Name | Symbol | MP | BP | Density |
|---|---|---|---|---|---|---|
| 1 | 1.0079 | Hydrogen | H | -259 | -253 | 0.09 |
| 2 | 4.0026 | Helium | He | -272 | -269 |
テーブルの全体像は、「元素のHTMLテーブル」を見てください。
ヘッダの行にはデータ参照時の名称を入れています。「No」(原子番号)はユニークIDとして利用しますし、他の「Group」「Period」「Element_Type」もハイライト機能に利用します。詳細は後ほど。
このようにHTMLテーブルで用意すれば、列を追加したり、元素を探したりすることが簡単に行えます。
pryを利用する際には、必ずSpryのJavaScriptファイルを読み込まなければなりません。このサンプルでは、head要素内に以下のように記述します。
<link href="SpryAssets/atom.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="SpryAssets//SpryData.js"></script> <script type="text/javascript" src="SpryAssets//SpryHTMLDataSet.js"></script> <script type="text/javascript" src="SpryAssets//SpryTooltip.js"></script> <script type="text/javascript" src="SpryAssets/atom_functions.js"></script>
このSpry周期表では、class属性が大きな役割を担っています。
atom.cssファイルを開いてください。セレクタの部分には、テーブルの「Element_Type」フィールドにもとづいたclass属性名が並んでいます(NonMetal、Inert、AlkaliMetalsなど)。Spryでデータ参照して得る値とこれらのclass属性名が同じにしています。これらのclass属性を利用して、元素ボックスの背景色を指定しています。他のclass属性は、element DIV内でのコンテンツの配置に使用します。element DIVとは、一つの元素データを格納しているdiv要素です。
Spry周期表では、4つのデータセットを使用し、以下のように定義します。
<script type="text/javascript" language="javascript">
var ds1 = new Spry.Data.HTMLDataSet(null,"atoms");
var types = new Spry.Data.HTMLDataSet(null,"atoms",{distinctOnLoad:true, distinctFieldsOnLoad:['Element_Type']});
var periods = new Spry.Data.HTMLDataSet(null,"atoms",{distinctOnLoad:true, distinctFieldsOnLoad:['Period']});
var groups = new Spry.Data.HTMLDataSet(null,"atoms",{distinctOnLoad:true, distinctFieldsOnLoad:['Group'],sortOnLoad:"Group",sortOrderOnLoad:"ascending"});
groups.setColumnType("Group","number");
...
</script>
var ds1 = new
Spry.Data.HTMLDataSet(null,"atoms"); var types = new
Spry.Data.HTMLDataSet(null,"atoms",{distinctOnLoad:true,
distinctFieldsOnLoad:['Element_Type']}); var periods = new
Spry.Data.HTMLDataSet(null,"atoms",{distinctOnLoad:true,
distinctFieldsOnLoad:['Period']});var groups = new
Spry.Data.HTMLDataSet(null,"atoms",{distinctOnLoad:true,
distinctFieldsOnLoad:['Group'],sortOnLoad:"Group",
sortOrderOnLoad:"ascending"});groups.setColumnType("Group","number");」と1行追加して、Spryに値が数字であることを伝えます。もしこのコードがなければ、Spryは「Group」列の値をテキストと解釈し、適切に並べることができないかもしれません。sortOnLoadとsortOrderOnLoadは、数値を順番に並べるための設定です。もしこの設定がなければ、ドキュメント内に記述されている順番で表示されてしまいます。 <script>タグ内には、もう一つ関数があります。
ds1.addObserver({onPostLoad: function(ds, data) {
Spry.Utils.removeClassName("wholeContainer", "SpryHiddenClass");
}});
class属性「SpryHiddenClass」には、「display:none; 」だけ記述しています。
「wholeContainer」は、周期表全体(元素のHTMLテーブルは除く)を囲むdiv要素で、class属性「SpryHiddenClass 」を指定しています。このようにしている理由は、
Spry.Utils.removeClassName」を実行するのです。そして、div要素「wholeContainer」のclass属性「SpryHiddenClass」が取り除かれ、周期表が表示されるようになっています。周期表のHTMLマークアップはそれほど複雑ではありませんが、レイアウトやハイライト機能(リンクボタン)に関するロジックがたくさんあります。まずは、周期表のメインブロックから解説して、その後にハイライト機能について解説します。
周期表は、基本的に1つ種類のdiv要素で構成されているといってもいいほどです。このdiv要素の中に1つの元素の情報を入れ込むので、「element DIV(元素ブロック)」と名付けます。
元素はたくさんあるのにマークアップはelement DIVが1つ分しかありませんが、Spryを使ってデータテーブルにある元素の数の分だけ、このdiv要素を繰り返します。後は、それらのelement DIVを周期表のように整列させます。
以下は、element DIV部分のマークアップです。このelement DIVには、たくさんのclass属性を指定しています。これらのclass属性を利用して、各元素を特定したり、ハイライト効果を適用させているのです。
<div tabindex="{No}" id="div_{No}" class="elementBlock {Element_Type} {Period} {Name} {Group}"
spry:if="({No} < 58 || ({No} > 71 && {No} < 90) || {No} > 103)" onmouseover="ds1.setCurrentRow('{ds_RowID}');" spry:hover="hover">
<span class="number">{No}</span> <span class="group"> {Group} </span>
<p align="center">{Symbol}</p>
<span class="weight">{Atomicweight}</span> </div>
</div>
spanタグとpタグの間にある{No}、{Group}、{Symbol}、{Atomicweight}は、データセットの各フィールドを参照するSpryコードです。number、group、weightといったclass属性は、element DIV内で参照した値を配置するために利用するもので、そのCSSルールはatom.cssに記述されています。
div要素の各属性の役割は以下の通りです。
tabIndex="{No}" :tabキー操作に対応し、アクセシビリティを確保するために使用します。tabindex属性に原子番号に基づいた固有の番号が振られるので、原子番号順にタブ操作で移動できるようになります。id="div_{no}" :各element DIVに固有のIDを割り振るためのものです。この属性は、ハイライト機能で該当元素以外をグレーアウト処理する際に使用します。class="elementBlock {Element_Type} {Period} {Name}
{Group}"
elementBlock :これをフックとしてelement DIVのサイズ、ボーダー、パディング、フォントサイズを指定します。詳細は、atom.cssを見てください。ちなみに、element DIVを水平に並べるために「float:left」を指定してるところがポイントです。{Element_Type}:「Element_Type」でデータ参照されるclass属性値を使って、背景色を指定しています。詳細は、atom.cssを見てください。{Period}と{Group}:「Period」と「Group」でデータ参照されるclass属性値はハイライト機能に使用します。atoms.cssには、このclass属性値を使った記述はありません。ハイライト機能のロジックだけで使用します。{Name}:「Name」でデータ参照されるclass属性値は、特定の元素をターゲットとする際に使用します。たとえば、class属性「.Hydrogen」を使って、Hydrogen(水素)とHelium(ヘリウム)の間のギャップをレイアウトしています。onmouseover="ds1.setCurrentRow('{ds_RowID}');" :この属性は、ツールチップの「spry:detailregion」を更新するために使用します。ツールチップに表示されている情報が、マウスオーバーしている元素の情報であることを確保するためのものです。spry:hover="hover":マウスオーバー時のテキストカラーを変更するために使用します。 「spry:if」の部分については、詳しく解説しましょう。Spry周期表は、2つのパートから構成されています。メインのテーブルと、下側にある2つの青い行です。この青い行は、Lanthanide(ランタノイド)とActinide(アクチニド)の元素です。これらのシリーズの元素は、常に別カラムとしてメインテーブルの下に置かれます。そして、この配置のために原子番号の並びが崩れてしまいます。元素ボックスの左上にある数字を見てください。Lanthanideは 58~71、Actinideは90~103となっています。メインテーブルの第6周期を見ると、57からいきなり72へとジャンプしています。第7周期でも同じように89から104へとジャンプしています。このようにLanthanideとActinideの元素は、メインテーブルの下に分けて表示しなければなりません。
メインテーブルとLanthanide/Actinide行は別々のdiv要素で囲まれており、メインテーブル内のelement DIVにある「spry:if」の部分を抜き出すと以下のようになっています。
spry:if="({No} < 58 || ({No} > 71 &&
{No} < 90) || {No} > 103)"
このロジックを説明すると、「No(原子番号)の値が58より小さい元素、71より大きくて90より小さい元素、103より大きい元素は、ここにプリント出力する」という内容です。これでメインテーブルのelement DIVが出力されます。別カラムとして置くLanthanide/Actinide行については、これと逆の条件を設定すればいいわけです。
まず、「spry:region」と「spry:repeatchildren」を使って、先ほどのHTMLマークアップの「spry:if」の条件を以下のようにします。
spry:if="({No} >= 58 && {No} <= 71) || ({No} >= 90 && {No} <= 103)"
この「spry:if」条件部分以外は、メインテーブルとLanthanide/Actinide行では同じマークアップとなります。ただ、Lanthanide/Actinide行には、各元素が水平方向にしっかりと並ぶようにCSSで調整しています。また、メインテーブルとLanthanide/Actinide行との間に「<br style="clear:both;" /> 」を差し込み、Lanthanide/Actinideの元素が新しい行となるように改行しています。
element DIVを囲んでいるdiv要素「mainRegion」は、メインの「spry:region」として使用するほか、CSSを適用させる際のフックとして利用します。また、このdiv要素内のbrタグは周期表レイアウトを実現する上で重要な役割を担っています。
<div spry:region="ds1" spry:repeatchildren="ds1" class="SpryHiddenRegion" id="mainRegion">
<br spry:if="({No} == 3) || ({No} == 11) || ({No} == 19) || ({No} == 37) || ({No} == 55) || ({No} == 87)" style="clear:both;" />
このdiv要素は、メインデータセット「ds1」の「spry:region」です。また、このデータセットには「spry: repeatchildren」を設定しています。spry:repeatchildren属性によって、必要な分だけelement DIVとbr要素が繰り返されます。class属性「SpryHiddenRegion」は、ページのロードが完了されるまで、このdiv要素を隠しておくために使用します。id属性は、先ほど「データセット」項目で解説したオブザーバーで使用します。
このコードによって、element DIVが繰り返されます。さらにそのelement DIVには「float:left:」されているので、element DIVが水平方向に並んでいきます。これを周期表のように並べるには、適切なところで改行しなければなりません。HeliumやNeonなどの背景色が緑色の元素のところで改行します。改行する箇所の元素の原子番号が分かっているので、これを利用します。
<br>タグには「spry:if」属性と「"clear:both;"」スタイルを指定しています。このclearでfloatを解除して改行しているのです。
「spry:if」属性では、どのelement DIVの後に<br>タグを挿入するかの条件を記述しています。その条件とは、「No(原子番号)の値が3、19、37、55、87のいずれかの場合にbrタグを挿入する」です。この原子番号を注意して見てください。背景色が緑色の元素の原子番号ではなく、その次ぎにくる元素、つまり各行の先頭にくる元素の原子番号です。
このbrタグによる改行とclass属性「elementBlock」に指定したfloatプロパティが、この周期表レイアウトの重要な役割を担っているのです。ただ、行の並びは整いましたが、最初の3つの行(第1周期~第3周期)にあるギャップの部分が残っています。このギャップを形成するには、各 element DIVに指定してあるclass属性「{Name}」を使用します。
通常、周期表では、最初の3行(第1 周期~第3周期)にギャップがあります。このレイアウトを実現するには固有の元素名を用いたclass属性を利用して、CSSで制御します。具体的には、該当する元素に大きなマージンを指定して、右側に押しやるだけです。このように移動させても、floatが指定してあるので、水平方向の並びは保たれたままです。
atoms.cssには、以下のように「.Hydrogen」「.Beryllium」「.Magnesium」の記述があります。
.Hydrogen {
margin-right:928px;
}
.Beryllium, .Magnesium {
margin-right:580px;
}
この記述だけで、3行のギャップを実現しています。元素のHTMLテーブルの「{Name}」列のデータをclass属性に渡しているのは、このためなのです。
用意した元素のHTMLテーブルには、先ほどのelement DIV内に入れた元素の情報量よりも多くの情報があります。Spry周期表では、「Spry Tooltip widget」を使って、元素の詳細情報がツールチップに表示されるようにしています。Spry Tooltip widgetは、ツールチップのコンテンツを格納するdiv要素「tooltip」と、ツールチップをオンにするトリガーを用意することで動作します。ツールチップに表示する内容は、元素に合わせて変更しなければなりません。そのために「spry:detailregion」を使っていて、これは element DIVの属性「onmouseover="ds1.setCurrentRow('{ds_RowID}');"」と連動しています。マウスオーバするごとに、「spry:detailregion」を更新しているのです。
このTooltip widgetは、「spry:detailregion」として定義しているので、それが適切に機能するようにしておかなければなりません。通常、 widgetとSpryデータを扱う場合には、データを更新するたびに消去したwidgetを復活させる必要があります。Spry周期表では、「spry:detailregion」が更新された際に、オブザーバーを使ってwidgetコンストラクタを誘発するようにしています。
<div spry:detailregion="ds1" id="tooltip" class="SpryHiddenRegion"> Name:<strong>{Name}</strong><br />
Type:<strong>{Element_Type}</strong><br />
Group:<strong>{Group}</strong><br />
Symbol:<strong>{Symbol}</strong><br />
Period:<strong>{Period}</strong><br />
Boiling Point:<strong>{BP}</strong><br />
Melting Point:<strong>{MP}</strong><br />
Density:<strong>{Density}</strong><br />
Atomic Weight:<strong>{Atomicweight}</strong><br />
Electron Config:<strong>{Electron_configuration}</strong><br />
Year Discovered:<strong>{DiscoveryYear}</strong> </div>
<script type="text/javascript">
Spry.Data.Region.addObserver('mainRegion',{onPostUpdate:function(){var tt1 = new Spry.Widget.Tooltip('tooltip','.elementBlock',{showDelay:750, hideDelay:500});}});
Spry.Data.Region.addObserver('Lanthanide',{onPostUpdate:function(){var tt2 = new Spry.Widget.Tooltip('tooltip','.elementBlock',{showDelay:750, hideDelay:500});}});
</script>
</div>
このdiv要素は、メインデータセット「ds1」と連動させた「spry:detailregion」です。
id="tooltip"は、widget用のコンテンツであることを示すフックです。
class属性「SpryHiddenRegion」は、ページのローディング中にこのマークアップを隠しておくためのものです。なお、ページのローディングが完了すると、Spryによってこのclass属性は取り除かれます。
div要素内に"script"があります。Spryでは、「spry:detailregion」内に"script"があると、データのローディングが完了してからそのスクリプトを実行するようになっています。
上記コードのハイライト部分はオブザーバーです。「spry:detailregion」が更新されるたびに、ツールチップを再構築します。通常、オブザーバーを追加する要素はid属性で指定します。Spry周期表の場合、2つの「spry:region」があり、それぞれ「mainRegion」と「Lanthanide」というid属性を割り振っています。これらの「spry:region」でデータの更新が完了すると、onPostUpdate 通知がTooltipコンストラクタ関数を実行します。Tooltipコンストラクタ関数内の「tooltip」は、ツールチップコンテンツ(「spry:detailregion」)のid属性です。
「.elementBlock」は、トリガーを定義しているclass属性です。このclass属性を持つ要素にマースオーバするごとにツールチップが表示されます。Spry周期表では、すべての element DIVにこのclass属性「elementBlock」を割り振っています。class属性「elementBlock」はelement DIVのサイズやボーダーを指定する際のフックとしても使用しています。element DIVにマウスオーバーするたびにツールチップが誘発されるのです。onmouseover属性が、現在の元素情報を更新して、オブザーバーが瞬時に新しいツールチップを構築するのです。
ページの上部には、「Element Types」「Groups」「Periods」という赤字項目の横にリンクテキストが並んでいます。これらは、周期表内の特定の領域をハイライト表示するためのリンクボタンです。このハイライト機能は、条件に該当しない元素をグレーアウトすることで、該当する元素が強調されるようにしています。つまり逆ハイライトです。
逆ハイライト機能では、複数のカスタム関数を使用していて、そのうち2つの関数はatom_functions.jsに記述しています。1つはハイライト用のGrayOutTable関数、もう1つは現在のハイライト表示を消去するためのclearGray関数です。なお、hasClassNameは次回のSpryバージョンで実装される予定のユーティリティ関数です。
function GrayOutTable(activeClass)
{
var rows = ds1.getData(true);
var numRows = rows.length;
for (var i = 1; i <= numRows; i++)
{
var ele = Spry.$("div_" + i);
if (ele)
{
if (!Spry.Utils.hasClassName(ele, activeClass))
Spry.Utils.addClassName(ele,"grayOut");
else
Spry.Utils.removeClassName(ele,"grayOut");
}
}
}
atom.cssには、class属性「grayout」に関する記述があり、不透明度を30%に指定しています。
ハイライトする元素かどうかは、element DIVのclass属性「{Name} 」を利用します。ハイライトさせたい元素のclass属性「{Name} 」を受け取り、データセットをチェックしながらそられのclass属性値が含まれていないelement DIVにはclass属性「grayout」を追加するようにするのです。データセットのデータをチェックする際は、element DIVの「 id="ds_{No}"」をもとに一つずつ調べて行きます。
GrayOutTable関数では、まずds1データセットのデータを調べて、HTMLテーブルの行数(numRows)を取得します。
Spry.Utilsを使って、すべてのelement DIVを走査し、該当するclass属性「{Name} 」があるかどうかをチェックします。そのclass属性値がない場合は、class属性「grayout」を追加します。該当するclass属性値がある場合は、そのままにしておきます。これで逆ハイライトとなります。もし、すでにclass属性「grayout」がある場合には、前回のハイライト時に追加されたものだと判断して、取り除きます。
clearGray関数では、同じようにすべてのelement DIVを走査し、すべてのclass属性「grayout」を取り除きます。
これらの関数は、ページ上部のリンクボタンがクリックされと実行されます。「Element Types」「Groups」「Periods」という3種類のハイライト項目とのそれぞれのリンクボタンは、Spryを使って生成しています。以下は、「Element Types」項目のマークアップです。
<div>
<span class="redText">Element Types: </span> <span spry:region="types" spry:repeat="types" class="SpryHiddenRegion"> <a href="#" onclick="GrayOutTable('{Element_Type}');">{Element_Type}</a> </span></div>
) を使用しています。このようにしてハイライト項目のリンクボタンを生成しています。このリンクボタンをクリックすると、{Element_Type}を引数として GrayOutTable関数が実行され、引数として渡された値とelement DIVのclass属性値を比較して、ハイライトする元素を判別しているのです。「Periods」や「Groups」の項目についても同じようなコードを使用しています。
Spryを使って複雑なWebレイアウトを構築する方法としてのサンプルとして、Spry周期表を紹介しました。わずかなHTMLマークアップとCSS、そしてカスタム関数を使うことで、機能的でインタラクティブなツールができました。なかかいい実験サンプルだったと思います。
これに興味を持って、みなさん自身でSpryを使っていろいろとアイデアを試してもらえるとうれしいです。
Donaldは、MacromediaでAuthorwareのサポート技術者としてキャリアをスタートしました。その後、AuthorwareからDreamweaverチームへ移り、チームリーダーを務めました。現在は、Contributeテクニカルサポートのプロダクトチームリーダーです。最近、New Riders Publishingから、『Inside Dreamweaver MX*』を共著で出版しました。Donaldの写真は、www.dbooth.netで見られます。