/** * タッチスクローラを使ったスクロールの際に、スクロール位置を示す視覚的なインジケータを提供します * * @private */ Ext.define('Ext.scroll.Indicator', { config: { /** * @cfg {String} axis ('x' or 'y') */ axis: null, /** * @cfg {Ext.dom.Element} containerEl インジケータを中に描画する要素。 */ containerEl: null, /** * @cfg {Ext.scroll.Scroller} scroller スクローラインスタンス */ scroller: null, /** * @cfg {Number} minLength インジケータの最小の長さ。デフォルトは、インジケータの「サイズ」(垂直インジケータなら幅、水平インジケータなら高さ)になります。 */ minLength: null, /** * @cfg {Number} scrollSize 設定された{@link #axis}上のスクローラのサイズ。 */ scrollSize: null, /** * @cfg {Number} maxScrollPosition 設定された{@link #axis}上のスクローラの最大スクロール位置。 */ maxScrollPosition: null, /** * @cfg {Boolean} hasOpposite インジケータが反対の軸上に第二のインジケータの場所を残す必要がある場合には`true` */ hasOpposite: null }, hideAnimConfig: { to: { opacity: 0 }, duration: 300 }, names: { x: { side: 'l', getSize: 'getHeight', clientSize: 'clientWidth', setLength: 'setWidth', setPosition: 'setLocalX' }, y: { side: 't', getSize: 'getWidth', clientSize: 'clientHeight', setLength: 'setHeight', setPosition: 'setLocalY' } }, cls: Ext.baseCSSPrefix + 'scroll-indicator', constructor: function(config) { var me = this, minLength, size, axis; me.initConfig(config); axis = me.getAxis(); me.names = me.names[axis]; me.el = me.getContainerEl().createChild({ cls: me.cls + ' ' + me.cls + '-' + axis }); if (!me.size) { me.cacheStyles(); } minLength = me.getMinLength(); size = me.size; if (!minLength || minLength < size) { me.setMinLength(size); } }, cacheStyles: function() { var me = this, proto = me.self.prototype, el = me.el, axis = me.getAxis(), names = me.names; /** * @property {Number} size * インジケータのサイズ(垂直なら幅、水平なら高さ) */ proto.size = el[names.getSize](); /** * @property {Number} margin * インジケータのマージン(インジケータの端とコンテナの端の間の余白) */ proto.margin = el.getMargin(names.side); }, hide: function() { this.el.animate(this.hideAnimConfig); }, refreshLength: function() { var me = this, names = me.names, scrollSize = me.getScrollSize(), containerSize = me.getContainerEl().dom[names.clientSize], ratio = containerSize / scrollSize, hasOpposite = me.getHasOpposite(), baseSizeAdjust = me.margin * 2, sizeAdjust = hasOpposite ? (baseSizeAdjust + me.size) : baseSizeAdjust, length = Math.max(Math.round((containerSize - sizeAdjust) * ratio), me.getMinLength()); me.sizeAdjust = sizeAdjust; /** * @property {Number} length * インジケータの「長さ」(垂直インジケータなら高さ、水平インジケータなら幅) */ me.length = length; me.el[names.setLength](length); }, /** * このスクロールインジケータの値を設定します。 * @param {Number} value 設定された{@link #axis}上のスクロール位置。 */ setValue: function(value) { var me = this, el = me.el, names = me.names, maxScrollPosition = me.getMaxScrollPosition(), containerSize = me.getContainerEl().dom[names.clientSize], baseLength = me.length, minLength = me.getMinLength(), length = baseLength, maxPosition = containerSize - baseLength - me.sizeAdjust, round = Math.round, max = Math.max, position; if (value < 0) { length = round(max( baseLength + (baseLength * value / containerSize), minLength )); position = 0; } else if (value > maxScrollPosition) { length = round(max( baseLength - (baseLength * (value - maxScrollPosition) / containerSize), minLength )); position = maxPosition + baseLength - length; } else { position = round(value / maxScrollPosition * maxPosition); } el[names.setPosition](position); el[names.setLength](length); }, show: function() { var me = this, el = me.el, anim = el.getActiveAnimation(); if (anim) { anim.end(); } me.refreshLength(); el.setStyle('opacity', ''); }, destroy: function() { this.el.destroy(); } });