script.aculo.usを読み解く

第7回 slider.js

この記事を読むのに必要な時間:およそ 12.5 分

0090:  dispose: function() {
0091:    var slider = this;    
0092:    Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
0093:    Event.stopObserving(document, "mouseup", this.eventMouseUp);
0094:    Event.stopObserving(document, "mousemove", this.eventMouseMove);
0095:    this.handles.each( function(h) {
0096:      Event.stopObserving(h, "mousedown", slider.eventMouseDown);
0097:    });
0098:  },

90~98行目の,disposeは,イベントリスナを解除する関数です。内部的には使われていません。ライブラリの利用者が,スライダーをページから消したいときに使います。

0099:  setDisabled: function(){
0100:    this.disabled = true;
0101:  },
0102:  setEnabled: function(){
0103:    this.disabled = false;
0104:  },  

99~104行目の,setDisabled, setEnabledは,disabledフラグをtrueやfalseにする関数です。ライブラリの利用者が,ハンドルのドラッグを不可能,または可能に切り替えるときに使います。

0105:  getNearestValue: function(value){
0106:    if (this.allowedValues){
0107:      if (value >= this.allowedValues.max()) return(this.allowedValues.max());
0108:      if (value <= this.allowedValues.min()) return(this.allowedValues.min());
0109:      
0110:      var offset = Math.abs(this.allowedValues[0] - value);
0111:      var newValue = this.allowedValues[0];
0112:      this.allowedValues.each( function(v) {
0113:        var currentOffset = Math.abs(v - value);
0114:        if (currentOffset <= offset){
0115:          newValue = v;
0116:          offset = currentOffset;
0117:        } 
0118:      });
0119:      return newValue;
0120:    }
0121:    if (value > this.range.end) return this.range.end;
0122:    if (value < this.range.start) return this.range.start;
0123:    return value;
0124:  },

105~124行目の,getNearestValueは,スライダーが取れる値の中から,引数の値に最も近いものを計算する関数です。

106行目で,allowedValuesの設定があるときは,以下の動作をします。

107行目で,引数の値がallowedValuesの最大値を越えている場合は,その最大値を返します。

108行目で,引数の値がallowedValuesの最小値を越えている場合は,その最小値を返します。いわゆるclampです。

110~119行目で,allowedValuesの中から引数の値との距離が最も小さくなる値を計算して返します。このコードはinjectメソッドを使って書いてもよいでしょう。

121~123行目で,allowedValuesの設定がないときは,レンジの最大値,最小値でclampします。

0125:  setValue: function(sliderValue, handleIdx){
0126:    if (!this.active) {
0127:      this.activeHandleIdx = handleIdx || 0;
0128:      this.activeHandle    = this.handles[this.activeHandleIdx];
0129:      this.updateStyles();
0130:    }
0131:    handleIdx = handleIdx || this.activeHandleIdx || 0;
0132:    if (this.initialized && this.restricted) {
0133:      if ((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
0134:        sliderValue = this.values[handleIdx-1];
0135:      if ((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
0136:        sliderValue = this.values[handleIdx+1];
0137:    }
0138:    sliderValue = this.getNearestValue(sliderValue);
0139:    this.values[handleIdx] = sliderValue;
0140:    this.value = this.values[0]; // assure backwards compat
0141:    
0142:    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = 
0143:      this.translateToPx(sliderValue);
0144:    
0145:    this.drawSpans();
0146:    if (!this.dragging || !this.event) this.updateFinished();
0147:  },

125~147行目の,setValueは,ハンドルの値を書き換える関数です。引数にスライダーの値とハンドルのインデックスを取ります。

126行目で,activeは,ハンドルのドラッグ中にtrueになるフラグなので,それがtrueでないときにこの関数が呼ばれたというのは,ドラッグ以外の手段でハンドルの値を書き換えようとしているとき,つまり初期化のときか,ライブラリの利用者が直接この関数を呼んだということです。そこで,127~129行目の処理で,'最近動かしたハンドル'としての情報を更新します。

127行目で,activeHandleIdxをhandleIdxにします。これは現在選択中のハンドルのインデックスを表します。引数の指定がなければ0になります。

128行目で,また,インデックスから現在選択中のハンドルを取得します。このハンドルはクラス名が'selected'になったり,ドラッグ時に位置が動いたりします。

129行目で,updateStylesを呼んで,現在選択中のハンドルのクラス名を'selected'にします。これによって,選択中のハンドルだけCSSで色を変えるといったことができます。

132~137行目で,restrictedが設定されているとき,隣のハンドルの値を越えないように制限します。インデックスの前後を見て,それらのハンドルの値を越えていたらsliderValueを直します。

138行目で,sliderValueを,スライダーの取れる値に直します。getNearestValueで,希望に最も近い値を選ぶようにします。

139行目で,引数で指定されたハンドルの値を更新します。

140行目で,後方互換性のために,valueの値も更新します。これはハンドルが1つしかなかったころの名残です。

142行目で,ハンドルの表示位置を更新します。スライダーが垂直ならCSSのtopプロパティを,水平ならleftプロパティを設定します。後述のtranslateToPxで,ハンドルの値から計算してCSSの値をpx単位で求めます。

145行目で,後述のdrawSpansでスパンを表示します。

146行目で,この関数がライブラリの利用者によって直接呼ばれたときは(これはドラッグ中でないことからわかります)updateFinishedフックを呼びます。

著者プロフィール

源馬照明(げんまてるあき)

名古屋大学大学院多元数理科学研究科1年。学部生のときにSchemeの素晴らしさを知ったのをきっかけに,関数型言語の世界へ。JavaScriptに,ブラウザからすぐに試せる関数型言語としての魅力と将来性を感じている。

ブログ:Gemmaの日記

コメント

コメントの記入