script.aculo.usを読み解く

第7回 slider.js

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

0148:  setValueBy: function(delta, handleIdx) {
0149:    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, 
0150:      handleIdx || this.activeHandleIdx || 0);
0151:  },

148~151行目の,setValueByは,変化量でハンドルの値を指定する関数です。引数に変化量とハンドルのインデックスを取ります。内部的には使われていません。キーボードからハンドルの値を変えられるようにしたいときなどに便利です。

149行目で,setValueに,ハンドルの現在値と変化量を足した値を渡します。引数でハンドルのインデックスが与えられなかったときはactiveHandleIdxを,あるいは0を,指定するようになっています。例えばドラッグ&ドロップの直後にこの関数を,インデックスを指定せずに呼ぶと,さっきまで動かしていたハンドルが動きます。

0152:  translateToPx: function(value) {
0153:    return Math.round(
0154:      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) *
0155:      (value - this.range.start)) + "px";
0156:  },

152~156行目の,translateToPxは,引数のハンドルの値を,CSSのtopやleftプロパティのために使うpx単位の値に変換する関数です。

154行目の,トラックの長さ-ハンドルの幅)/レンジの幅)は,ハンドルの値とピクセルの換算率です。

155行目で,それを引数のハンドルの値の始点からの距離にかけて,Math.roundで丸めたものに,単位の'px'を付けて返します。

0157:  translateToValue: function(offset) {
0158:    return ((offset/(this.trackLength-this.handleLength) * 
0159:      (this.range.end-this.range.start)) + this.range.start);
0160:  },

157~160行目の,translateToValueは,引数で与えるオフセット位置から,ハンドルの値に変換する関数です。ドラッグ&ドロップのときにマウスポインタの位置からスライダーの値を求めるのに使います。

158行目の,(レンジの幅/(トラックの長さ-ハンドルの幅)⁠は,ハンドルの値とピクセルの換算率です。これはtranslateToPxのときの逆数です。

159行目で,それを引数の値にかけて,始点の値を足したものを返します。

0161:  getRange: function(range) {
0162:    var v = this.values.sortBy(Prototype.K); 
0163:    range = range || 0;
0164:    return $R(v[range],v[range+1]);
0165:  },

161~165行目の,getRangeは,ハンドル同士の間にできる区間から,小さいほうから数えてrange番めの区間を返す関数です。

162行目で,ハンドルの値の配列をsortByメソッドでソートします。Prototype.Kは,Prototype.jsで定義されている恒等関数です。これは単にsort()と呼んだほうがよいと私は思います。

164行目で,ハンドルのrange番めの区間を$R関数で作って返します。

0166:  minimumOffset: function(){
0167:    return(this.isVertical() ? this.alignY : this.alignX);
0168:  },

166~168行目の,minimumOffsetは,トラックの0点位置を返す関数です。スライダーの向きが垂直ならalignYを,水平ならalignXを返します。

0169:  maximumOffset: function(){
0170:    return(this.isVertical() ? 
0171:      (this.track.offsetHeight != 0 ? this.track.offsetHeight :
0172:        this.track.style.height.replace(/px$/,"")) - this.alignY : 
0173:      (this.track.offsetWidth != 0 ? this.track.offsetWidth : 
0174:        this.track.style.width.replace(/px$/,"")) - this.alignX);
0175:  },  

169~175行目の,maximumOffsetは,トラックの最大位置を返す関数です。

170行目で,スライダーの向きが垂直なら,トラックのoffsetHeightを返します。しかし,スライダーがブラウザに表示されていないときにoffsetHeightが取得できないことがありますticket4011)⁠このときは,172行目にあるように,CSSのheightプロパティの数値部分からトラックの0点位置であるalignYを引いた値を返します。

173行目で,スライダーの向きが水平なら,トラックのoffsetWidthを返すか,あるいは同様に,CSSのwidthプロパティの数値部分からトラックの0点位置であるalignXを引いた値を返します。

0176:  isVertical:  function(){
0177:    return (this.axis == 'vertical');
0178:  },

176~178行目の,isVerticalは,スライダーの向きが垂直かどうかを返す関数です。

0179:  drawSpans: function() {
0180:    var slider = this;
0181:    if (this.spans)
0182:      $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
0183:    if (this.options.startSpan)
0184:      this.setSpan(this.options.startSpan,
0185:        $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
0186:    if (this.options.endSpan)
0187:      this.setSpan(this.options.endSpan, 
0188:        $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
0189:  },

179~189行目の,drawSpansは,スパンたちの位置をそれぞれ計算して描画する関数です。

182行目で,spans配列にあるスパンたちに,順番にgetRangeとsetSpanをかけていきます。getRangeは前述の,r番めの区間の範囲を計算する関数で,setSpanは後述のとおり,実際にCSSを書き換えて描画する関数です。ちなみに,$R(0,this.spans.length-1).eachは,this.spans.eachを使ったほうがきれいだと思います。

183行目で,options.startSpanは,先頭のスパンだけ特別に扱うオプションです。

184行目で,先頭のスパンを扱うために,setSpanに渡す区間の範囲は,始点が0です。これはthis.minimumでなければおかしいので,バグです。そして終点は,ハンドルが1つより多ければ,getRangeで先頭の区間を求めてその始点の値を使い,そうでなければ,ハンドルの値(this.value)を使います。this.valueは,setValueの140行めで常に1番めのハンドルの値になるようになっています。

186行目で,options.endSpanは,最後尾のスパンだけ特別に扱うオプションです。

187行目で,最後尾のスパンを扱うために,setSpanに渡す区間の範囲は,始点は,ハンドルが1つより多ければ,getRangeで最後尾の区間を求めてその終点を使い,そうでなければ,ハンドルの値(this.value)を使います。終点は,スライダーが取りうる最大値を使います。

著者プロフィール

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

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

ブログ:Gemmaの日記

コメント

コメントの記入