スリップ スライディング
Michael Wallent
Lead Program Manager
Microsoft Corporation
August 28, 2000
日本語版最終更新日 2000年10月10日
先週 Dynamic HTML (DHTML) を使用してスライダを作成する方法について議論する機会がありました。そこで、ある問題が投げかけられました。それは、Win32 コードだけを使用して作成されたスライダと同じくらい高速なスライダを作成できるか、というものでした。DHTML Dude として、わたしはこのような問題を放っておくことはできませんでした。私はコードを書き始めました。
基本設計
私はこのスライダを使いやすく、しかも柔軟性のあるものにしたいと考えました。優れた機能をあらかじめ持たせる必要がありますが、大量のスクリプトを書かなくてもカスタマイズできるようにしたいとも考えました。これらの理由から、また、わかりやすく、シンプルに作成したいので、DHTML ビヘイビアを使うことにしました。
問題のビヘイビアは、複数の HTML コンポーネントで構成されることになります。すなわち、背景のための <DIV>、中央のバーのためのもう 1 つの <DIV>、そして "つまみ" のための第 3 の <DIV> です。効率的なカプセル化のために、また、これらをわかりやすく作成できるように、ViewLink 形式の要素ビヘイビアを作成することにしました。要素ビヘイビアと ViewLink 機能のサポートは、Internet Explorer 5.5 で追加されました。
水平方向と垂直方向の両方のスライダを作成しようと思い、レイアウトを指定する 2 つのプロパティ、movelr と moveud を作成しました。
また、スライダとつまみの背景色のプロパティと背景画像のプロパティを作成して、将来の作成者がそれらをカスタマイズできるようにしました。
このスライダは、スライダが実際に動くたびにイベントが発生するようになっています。スライダのプロパティが変化する際の onpropertychange 通知を使用することもできましたが、単純にするために、新しいイベント onslide も作成することにしました。
スライダは現在の位置を value プロパティによって公開します。これは読み取り/書き込み可能なプロパティであり、値の範囲は 0〜100 です。
実装
以下に、HTML ページでのスライダ ビヘイビアのためのタグを示します。
<ie:slider id=Slider1
movelr=true backgroundColor="red" thumbColor="blue" thumbSize="20px"
backgroundImage="url(triangle.gif)" backgroundRepeat="no-repeat"
style="height: 68px; width: 150px"
onslide="Slider1Output.value = window.event.sliderValue;"/>
上記で指定されているプロパティ、すなわち、movelr、 backgroundColor、 thumbColor、 thumbSize、 backgroundImage、 backgroundRepeat のすべてに注目してください。また、スライダのための新しいイベント、onslide がタグで設定されています。
Internet Explorer 5.5 を使用している人は、サンプルを表示することができます(Internet Explorer 5.5 は、Microsoft Windows Web サイトからダウンロード することができます)。 サンプル ページには、一般的な垂直のスライダとカスタムの水平のスライダが表示されます。つまみを動かして、入力ボックスの値が変化することを確認してください。また、入力ボックスに値を入力して、[Change] ボタンをクリックすると、スライダが指定された位置に移動します。
以下に、スライダ タグが定義されている .htc ファイルのヘッダーを示します。
<public:component tagname=slider>
<public:property name=movelr />
<public:property name=moveud />
<public:property name=backgroundColor />
<public:property name=backgroundImage />
<public:property name=backgroundRepeat />
<public:property name=thumbColor />
<public:property name=thumbSize />
<public:property name=value id=propValue put="setValue" get="getValue" />
<public:attach event="oncontentready" onevent="initialize()" />
<public:defaults viewLinkContent />
<public:event name="onslide" id="eSlide" />
これは要素ビヘイビアなので、最初の行 -- public:component の宣言 -- が必要です。
それぞれのプロパティが <public:property> タグで定義されていますが、 value プロパティだけが取得関数と設定関数を定義しています。このプロパティが取得関数と設定関数を必要とするのは、スライダの動きによってプロパティが内部でリセットされるからであり、ユーザーが外部から設定できるようにするためです。設定関数によって、ビヘイビアはユーザーが値を変更したことをキャッチすることができます。
oncontentready イベントの明確なキャッチによって、 initialization メソッドの適切なタイミングが確保されます。このタグはスコープが設定されていないので、それほど重要ではありません。このタグが内部に内容を持つ場合は、oncontentready 通知の使用が不可欠になります。インライン スクリプトだけを使用して初期化した場合、このタグは完全に解析された状態にならないおそれがあります。oncontentready イベントは、タグの内容のすべてが解析されて、アクセスに使用可能になったときに発生します。
viewLinkContent ディレクティブは、<ie:slider> タグによって定義された矩形の内容が、該当する .htc ファイルの本体から得られることをブラウザに知らせます。スライダになる内容の宣言を見てみましょう。
<div id=theParent style="background-color: scrollbar;
position: relative; width: 100%; height: 100%;">
<div id=theDiv style="border: outset 2px;
background-color: scrollbar; cursor: hand;
position: absolute; top: 10px; left: 0px;
width: 15px; height: 50px;
z-index: 5; font-size: 1px">
</div>
<div id=theMiddle style="font-size:1px; background-color: black;
position: absolute;">
</div>
</div>
"theParent" <DIV> は、スライダの背景になります。これは、<ie:slider> タグを含んでいるユーザーの HTML ページによって指定されたサイズいっぱいに表示されるように、100 パーセントの高さと幅に設定されています。<DIV> サイズをパーセンテージで指定することによって、あとでつまみのサイズと位置を導出する際に、興味深い問題が生じます。
"theDiv" <DIV> は、スライダのつまみになります。デフォルトではスクロールバーの色に設定されます。Positioning プロパティは一部だけが指定されています。最終的な値は、スライダが左から右へ動くのか、それとも上から下へ動くのかによって異なるからです。残りの Positioning の値は、 initialization メソッドの際に指定されます。
"theMiddle" <DIV> は、中央の目盛です。つまみと同様、位置指定 Positioning プロパティの大部分は initialization メソッドで設定されます。
スライドさせる
ドラッグを正しく実装するには、以下のステップに従います。
- onselectstart="return false" を使用して、要素の選択をキャンセルします。このようにしないと、ドラッグという行為はテキスト選択、画像選択、または OLE のドラッグ アンド ドロップ操作として誤って解釈されてしまいます。
- 対象とする要素の onmousedown イベントについて、マウスをキャプチャします。次に、ドラッグ モードに入って、 onmousemove および onmouseup イベントをトラップします。
- onmousemove イベントに対して、ドラッグされた要素の位置を適切に決めます。オブジェクトをどのくらい動かすかを決める最良の方法は、前回のドラッグのマウス座標を "記憶" しておいて、現在のマウス位置に基づいてデルタ (増分) を計算する方法です。この方法だと、不自然な動きを少なくすることができます。
- onmouseup イベントを受け取ったら、ドラッグを中止して、onmousemove および onmouseup イベントを解放し、マウス キャプチャをキャンセルします。結果として、ドラッグ モードを終了します。
onmousemove イベントが処理されるたびに、スライダは event オブジェクトに特殊な値を設定して onslide イベントを生成します。
if (!noResetX && !noResetY) {
event = createEventObject();
event.sliderValue = dragPosition;
realValue = dragPosition;
eSlide.fire(event);
}
このコードは、onmousemove イベントのイベント ハンドラとして設定された doDrag() メソッドの中にあります。
上記のコードの if 文によって、"オーバードラッグ"、すなわち範囲外へのドラッグが防止されます。オーバードラッグを検出しても、同じ値を持つ複数の onslide イベントをスローすることはありません。
このビヘイビアは sliderValue という新しいプロパティをイベント オブジェクトに追加するので、カスタムのイベント オブジェクトを作成する必要があります。イベント オブジェクトを設定したら、新しいイベント オブジェクトをパラメータとして指定して fire メソッドを呼び出すだけです。fire メソッドは、ヘッダーでの宣言に従って、イベント オブジェクトに対して呼び出されます。
つまみを計算する
先ほど、スライダの背景サイズをパーセントで定義した場合の複雑さについてお話しました。これは、ほとんどの人が要素の位置決めに使用している方法、つまり、 style.posLeft および style.posTop プロパティは、うまく行くとは限らないことを意味します。これらのプロパティは値をピクセル単位ではなく、指定された単位で返します。しかし、style.pixelLeft、style.pixelTop、style.pixelWidth、および style.pixelHeight プロパティを使用すれば、左/上/幅/高さのピクセル値に必ずアクセスすることができます。その部分のコードを以下に示します。
if (dragElement.style.posTop + dragElement.style.posHeight >
dragParent.style.pixelHeight) {
dragElement.style.posTop = dragParent.style.pixelHeight
dragElement.style.posHeight - 1 ;
noResetY = true;
}
このコードは、つまみの移動が大きすぎないかどうかを検出します。dragElement プロパティは、つまみを表します。dragParent プロパティは、スライダの背景です。当然のことですが、ピクセル単位で指定される dragElement の posTop プロパティと posHeight プロパティは、これもピクセル単位である dragParent の pixelHeight プロパティと比較されていることに注目してください。
正しい方法で変更する
プロパティ 設定関数による値の変更を可能にした場合は、親ドキュメントで onpropertychange イベントが正しく機能するように、プロパティに対して fireChange() メソッドを呼び出す必要があります。慎重にコーディングすれば、システムのユーザー定義プロパティと組み込みプロパティの一貫性を確保することができます。
function setValue(newValue) {
if ((newValue < 0) || (newValue > 100)) {
return;
}
if (element.movelr) {
ppV = dragParent.style.pixelWidth / 100;
dragElement.style.posLeft = ppV * newValue;
}
if (element.moveud) {
ppV = dragParent.style.pixelHeight / 100;
dragElement.style.posTop = ppV * (100 - newValue);
}
realValue = newValue;
propValue.fireChange();
}
まとめ
これででき上がりです。完全に機能するスライダ コントロールが DHTML だけでできました。おそらく、Win32 で作成するよりも時間がかからなかったはずですし、コンパイルの必要はまったくありませんでした。
|