define(function(require, exports, module) { "use strict"; var Util = require('../util'); var Animate = require('../animate'); var MAX_BOUNCE_DISTANCE = 40; var MIN_BAR_SCROLLED_SIZE = 10; var MIN_BAR_SIZE = 50; var transform = Util.prefixStyle("transform"); var transformStr = Util.vendor ? ["-", Util.vendor, "-transform"].join("") : "transform"; var transition = Util.prefixStyle("transition"); var borderRadius = Util.prefixStyle("borderRadius"); var transitionDuration = Util.prefixStyle("transitionDuration"); var ScrollBar = function(cfg) { this.userConfig = Util.mix({ MIN_BAR_SCROLLED_SIZE:MIN_BAR_SCROLLED_SIZE, MIN_BAR_SIZE:MIN_BAR_SIZE, MAX_BOUNCE_DISTANCE:MAX_BOUNCE_DISTANCE, spacing:5 }, cfg); this.init(cfg.xscroll); } Util.mix(ScrollBar.prototype, { init: function(xscroll) { var self = this; self.xscroll = xscroll; self.type = self.userConfig.type; self.isY = self.type == "y" ? true : false; self.scrollTopOrLeft = self.isY ? "scrollTop" : "scrollLeft"; }, destroy: function() { var self = this; Util.remove(self.scrollbar); self.xscroll.off("scroll", self._scrollHandler, self); self.xscroll.off("scrollend", self._scrollEndHandler, self); }, render: function() { var self = this; var xscroll = self.xscroll; var boundry = xscroll.boundry; var indicatorInsets = self.xscroll.userConfig.indicatorInsets; var translateZ = xscroll.userConfig.gpuAcceleration ? " translateZ(0) " : ""; var transform = translateZ ? transformStr + ":" + translateZ + ";" : ""; var commonCss = "opacity:0;position:absolute;z-index:999;overflow:hidden;-webkit-border-radius:3px;-moz-border-radius:3px;-o-border-radius:3px;" + transform; indicatorInsets._xright = indicatorInsets.right + indicatorInsets.spacing; indicatorInsets._xbottom = indicatorInsets.bottom + indicatorInsets.spacing; var css = self.isY ? Util.substitute("width:{width}px;bottom:{_xbottom}px;top:{top}px;right:{right}px;", indicatorInsets) + commonCss : Util.substitute("height:{width}px;left:{left}px;right:{_xright}px;bottom:{bottom}px;",indicatorInsets) + commonCss; if(!self.scrollbar){ self.scrollbar = document.createElement("div"); self.indicate = document.createElement("div"); xscroll.renderTo.appendChild(self.scrollbar); self.scrollbar.appendChild(self.indicate); } self.scrollbar.style.cssText = css; var size = self.isY ? "width:100%;" : "height:100%;"; self.indicate.style.cssText = size + "position:absolute;background:rgba(0,0,0,0.3);-webkit-border-radius:3px;-moz-border-radius:3px;-o-border-radius:3px;" self._update(); self.hide(0); self._bindEvt(); }, _update: function(pos, duration, easing, callback) { var self = this; var pos = undefined === pos ? (self.isY ? self.xscroll.getScrollTop() : self.xscroll.getScrollLeft()) : pos; var barInfo = self.computeScrollBar(pos); var size = self.isY ? "height" : "width"; self.indicate.style[size] = Math.round(barInfo.size) + "px"; if (duration && easing) { self.scrollTo(barInfo.pos, duration, easing, callback); } else { self.moveTo(barInfo.pos); } }, //compute the position and size of the scrollbar computeScrollBar: function(pos) { var self = this; var type = self.isY ? "y" : "x"; var spacing = self.userConfig.spacing; var xscroll = self.xscroll; var boundry = xscroll.boundry; var userConfig = self.userConfig; var pos = self.isY ? Math.round(pos) + boundry._xtop : Math.round(pos) + boundry._xleft; var MIN_BAR_SCROLLED_SIZE = userConfig.MIN_BAR_SCROLLED_SIZE; var MIN_BAR_SIZE = userConfig.MIN_BAR_SIZE; var MAX_BOUNCE_DISTANCE = userConfig.MAX_BOUNCE_DISTANCE; self.containerSize = self.isY ? xscroll.containerHeight + boundry._xtop + boundry._xbottom : self.xscroll.containerWidth + boundry._xright + boundry._xleft; self.size = self.isY ? boundry.cfg.height : boundry.cfg.width; self.indicateSize = self.isY ? boundry.cfg.height - spacing * 2 : boundry.cfg.width - spacing * 2; var indicateSize = self.indicateSize; var containerSize = self.containerSize; var barPos = indicateSize * pos / containerSize; var barSize = Math.round(indicateSize * self.size / containerSize); var overTop = self.isY ? xscroll.getBoundryOutTop() : xscroll.getBoundryOutLeft(); var overBottom = self.isY ? xscroll.getBoundryOutBottom() : xscroll.getBoundryOutRight(); var barShiftSize = MIN_BAR_SIZE - barSize > 0 ? MIN_BAR_SIZE - barSize : 0; barSize = barSize < MIN_BAR_SIZE ? MIN_BAR_SIZE : barSize; barPos = (indicateSize - barShiftSize) * pos / containerSize; if (overTop >= 0) { var pct = overTop / MAX_BOUNCE_DISTANCE; pct = pct > 1 ? 1 : pct; barPos = - pct * (barSize - MIN_BAR_SCROLLED_SIZE) } if (overBottom >= 0) { var pct = overBottom / MAX_BOUNCE_DISTANCE; pct = pct > 1 ? 1 : pct; barPos = pct * (barSize - MIN_BAR_SCROLLED_SIZE) + indicateSize - barSize; } self.barPos = Math.round(barPos); return { size: Math.round(barSize), pos: self.barPos }; }, scrollTo: function(pos, duration, easing, callback) { var self = this; self.show(); var translateZ = self.xscroll.userConfig.gpuAcceleration ? " translateZ(0) " : ""; var config = { css: { transform: self.isY ? "translateY(" + pos + "px)" + translateZ : "translateX(" + pos + "px)" + translateZ }, duration: duration, easing: easing, useTransition: self.xscroll.userConfig.useTransition, end: callback }; self.__timer = self.__timer || new Animate(self.indicate, config); //run self.__timer.stop(); self.__timer.reset(config); self.__timer.run(); }, moveTo: function(pos) { var self = this; self.show(); var translateZ = self.xscroll.userConfig.gpuAcceleration ? " translateZ(0) " : ""; self.isY ? self.indicate.style[transform] = "translateY(" + pos + "px) " + translateZ : self.indicate.style[transform] = "translateX(" + pos + "px) " + translateZ self.indicate.style[transition] = ""; }, _scrollHandler: function(e) { var self = this; self._update(e[self.scrollTopOrLeft]); return self; }, isBoundryOut: function() { var self = this; return !self.isY ? (self.xscroll.isBoundryOutLeft() || self.xscroll.isBoundryOutRight()) : (self.xscroll.isBoundryOutTop() || self.xscroll.isBoundryOutBottom()); }, _scrollEndHandler: function(e) { var self = this; if (!self.isBoundryOut()) { self._update(e[self.scrollTopOrLeft]); self.hide(); } return self; }, _bindEvt: function() { var self = this; if (self.__isEvtBind) return; self.__isEvtBind = true; self.xscroll.on("scroll", self._scrollHandler, self); self.xscroll.on("scrollend", self._scrollEndHandler, self); }, reset: function() { var self = this; self.pos = 0; self._update(); }, hide: function(duration, easing, delay) { var self = this; var duration = duration >= 0 ? duration : 300; var easing = easing || "ease-out"; var delay = delay >= 0 ? delay : 100; self.scrollbar.style.opacity = 0; self.scrollbar.style[transition] = ["opacity ", duration, "ms ", " ease-out ", delay, "ms"].join(""); }, show: function() { var self = this; self.scrollbar.style.opacity = 1; self.scrollbar.style[transition] = ""; } }); if (typeof module == 'object' && module.exports) { module.exports = ScrollBar; } /** ignored by jsdoc **/ else { return ScrollBar; } });