Show:

File: libs/Scroller.js

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
/**
 * @module annieUI
 */
var annieUI;
(function (annieUI) {
    /**
     * 滚动视图,有些时候你的内容超过了一屏,需要上下或者左右滑动来查看内容,这个时候,你就应该用它了
     * @class annieUI.Scroller
     * @public
     * @extends annie.AObject
     * @since 3.1.0
     */
    var Scroller = /** @class */ (function (_super) {
        __extends(Scroller, _super);
        /**
         * 初始化
         * @method Scroller
         * @param {annie.DisplayObject} container
         * @param {number} viewWidth
         * @param {number} viewHeight
         * @param {number} scrollWidth
         * @param {number} scrollHeight
         */
        function Scroller(container, viewWidth, viewHeight, scrollWidth, scrollHeight) {
            var _this = _super.call(this) || this;
            /**
             * 是否纵向滚动
             * @property isScrollY
             * @type {boolean}
             * @public
             * @since 3.1.5
             * @default true;
             */
            _this.isScrollY = true;
            /**
             * 是否横向滚动
             * @property isScrollX
             * @type {boolean}
             * @since 3.1.5
             * @public
             * @default true;
             */
            _this.isScrollX = true;
            /**
             * 是否松开鼠标后让其自由缓冲滑动
             * @property isMomentum
             * @type {boolean}
             * @since 3.1.5
             * @public
             * @default true;
             */
            _this.isMomentum = true;
            /**
             * 是否滑到边界后有回弹效果
             * @property isBounce
             * @type {boolean}
             * @since 3.1.5
             * @public
             * @default true;
             */
            _this.isBounce = true;
            /**
             * 回弹的动效时长,单位:ms
             * @property bounceTime
             * @type {number}
             * @public
             * @since 3.1.5
             * @default 300
             */
            _this.bounceTime = 300;
            /**
             * 是否需要横向纵向保护,有些时候你想纵向滑动,但鼠标也轻微的左右飘了,如果不lock刚好左右滑动也被允许的话,则左右也会滑动,横向滑动则相反。
             * 如果想鼠标不那么灵敏的话,可以加上一把锁,这样左右滑的时候上下不会滑,上下滑的时候左右不会滑
             * @property isLocked
             * @type {boolean}
             * @public
             * @since 3.1.5
             * @default 300
             */
            _this.isLocked = true;
            /**
             * 锁的像素范围
             * @property lockDis
             * @type {number}
             * @since 3.1.5
             * @public
             * @default 5
             */
            _this.lockDis = 5;
            _this._curX = 0;
            _this._curY = 0;
            _this._viewWidth = 0;
            _this._viewHeight = 0;
            _this._scrollWidth = 0;
            _this._scrollHeight = 0;
            _this.startX = 0;
            _this.startY = 0;
            _this.maxScrollX = 0;
            _this.maxScrollY = 0;
            _this.endTime = 0;
            _this.mouseStatus = 0;
            _this.distX = 0;
            _this.distY = 0;
            _this.startTime = 0;
            _this.absStartX = 0;
            _this.absStartY = 0;
            _this.pointX = 0;
            _this.pointY = 0;
            _this.deceleration = 0.0006;
            _this.destTime = 0;
            _this.destX = 0;
            _this.destY = 0;
            _this.duration = 0;
            _this._mouseEvent = null;
            _this._enterFrame = null;
            var s = _this;
            s._instanceType = "annieUI.Scroller";
            s._mouseEvent = s.onMouseEvent.bind(s);
            s._enterFrame = s.onEnterFrame.bind(s);
            s.init(container, viewWidth, viewHeight, scrollWidth, scrollHeight);
            return _this;
        }
        Object.defineProperty(Scroller.prototype, "curX", {
            /**
             * 当前滑动的x坐标 更改此参数则需要调用resetPosition()方法生效
             * @property curX
             * @type {number}
             * @since 3.1.5
             * @default 0
             */
            get: function () {
                return this._curX;
            },
            enumerable: true,
            configurable: true
        });
        Object.defineProperty(Scroller.prototype, "curY", {
            /**
             * 当前滑动的y坐标 更改此参数则需要调用resetPosition()方法生效
             * @property curY
             * @type {number}
             * @since 3.1.5
             * @default 0
             */
            get: function () {
                return this._curY;
            },
            enumerable: true,
            configurable: true
        });
        Object.defineProperty(Scroller.prototype, "viewWidth", {
            /**
             * 当前显示范围的宽
             * @property viewWidth
             * @type {number}
             * @since 3.1.5
             * @default 0
             * @readonly
             */
            get: function () {
                return this._viewWidth;
            },
            enumerable: true,
            configurable: true
        });
        Object.defineProperty(Scroller.prototype, "viewHeight", {
            /**
             * 当前显示范围的高
             * @property viewHeight
             * @type {number}
             * @since 3.1.5
             * @default 0
             * @readonly
             */
            get: function () {
                return this._viewHeight;
            },
            enumerable: true,
            configurable: true
        });
        Object.defineProperty(Scroller.prototype, "scrollWidth", {
            /**
             * 当前横向的滑动范围
             * @property scrollWidth
             * @type {number}
             * @since 3.1.5
             * @default 0
             * @readonly
             */
            get: function () {
                return this._scrollWidth;
            },
            enumerable: true,
            configurable: true
        });
        Object.defineProperty(Scroller.prototype, "scrollHeight", {
            /**
             * 当前纵向的滑动范围
             * @property scrollHeight
             * @type {number}
             * @since 3.1.5
             * @default 0
             * @readonly
             */
            get: function () {
                return this._scrollHeight;
            },
            enumerable: true,
            configurable: true
        });
        /**
         * 初始化,也可以反复调用此方法重用scroller
         * @method init
         * @param {annie.DisplayObject} container
         * @param {number} viewWidth
         * @param {number} viewHeight
         * @param {number} scrollWidth
         * @param {number} scrollHeight
         * @public
         * @since 3.1.5
         */
        Scroller.prototype.init = function (container, viewWidth, viewHeight, scrollWidth, scrollHeight) {
            var s = this;
            if (s._container && s._container != container) {
                //移除
                s._container.removeEventListener(annie.MouseEvent.MOUSE_DOWN, s._mouseEvent, false);
                s._container.removeEventListener(annie.MouseEvent.MOUSE_MOVE, s._mouseEvent, false);
                s._container.removeEventListener(annie.MouseEvent.MOUSE_UP, s._mouseEvent, false);
                s._container.removeEventListener(annie.MouseEvent.MOUSE_OUT, s._mouseEvent);
                s._container.removeEventListener(annie.Event.ENTER_FRAME, s._enterFrame);
            }
            if (s._container != container) {
                s._container = container;
                container.addEventListener(annie.MouseEvent.MOUSE_DOWN, s._mouseEvent, false);
                container.addEventListener(annie.MouseEvent.MOUSE_MOVE, s._mouseEvent, false);
                container.addEventListener(annie.MouseEvent.MOUSE_UP, s._mouseEvent, false);
                container.addEventListener(annie.MouseEvent.MOUSE_OUT, s._mouseEvent);
                container.addEventListener(annie.Event.ENTER_FRAME, s._enterFrame);
            }
            s.isRunning = false;
            s.endTime = 0;
            s.setViewWHAndScrollWH(viewWidth, viewHeight, scrollWidth, scrollHeight);
        };
        /**
         * 当更改了viewWidth,viewHeight其中一个或两个同时也更改了scrollWidth,scrollHeight其中的一个或者两个
         * 需要调用此方法重置,如果只是单方面更改了viewWidth,viewHeight其中一个或两个,则可以调用setViewWH()
         * 如果只是更改了scrollWidth,scrollHeight其中的一个或者两个,则可以调用setScrollWH()
         * @method setViewWHAndScrollWH
         * @public
         * @since 3.1.5
         * @param {number} viewWidth
         * @param {number} viewHeight
         * @param {number} scrollWidth
         * @param {number} scrollHeight
         */
        Scroller.prototype.setViewWHAndScrollWH = function (viewWidth, viewHeight, scrollWidth, scrollHeight) {
            var s = this;
            s._viewHeight = viewHeight;
            s._viewWidth = viewWidth;
            s._scrollWidth = scrollWidth;
            s._scrollHeight = scrollHeight;
            s._updateViewAndScroll();
        };
        /**
         * 当更改了viewWidth,viewHeight其中一个或两个,需要调用此方法重置.
         * @method setViewWH
         * @public
         * @since 3.1.5
         * @param {number} viewWidth
         * @param {number} viewHeight
         */
        Scroller.prototype.setViewWH = function (viewWidth, viewHeight) {
            var s = this;
            s._viewHeight = viewHeight;
            s._viewWidth = viewWidth;
            s._updateViewAndScroll();
        };
        /**
         * 当更改了scrollWidth,scrollHeight其中的一个或者两个,需要调用此方法重置.
         * @method setScrollWH
         * @public
         * @since 3.1.5
         * @param {number} scrollWidth
         * @param {number} scrollHeight
         */
        Scroller.prototype.setScrollWH = function (scrollWidth, scrollHeight) {
            var s = this;
            s._scrollWidth = scrollWidth;
            s._scrollHeight = scrollHeight;
            s._updateViewAndScroll();
        };
        Scroller.prototype._updateViewAndScroll = function () {
            var s = this;
            s.maxScrollX = s.viewWidth - s.scrollWidth;
            s.maxScrollY = s.viewHeight - s.scrollHeight;
            if (s.maxScrollX > 0) {
                s.maxScrollX = 0;
            }
            if (s.maxScrollY > 0) {
                s.maxScrollY = 0;
            }
            if (!s.isScrollX) {
                s.maxScrollX = 0;
                s._scrollWidth = s.viewWidth;
            }
            if (!s.isScrollY) {
                s.maxScrollY = 0;
                s._scrollHeight = s.viewHeight;
            }
            s.resetPosition(200);
        };
        Scroller.prototype.onEnterFrame = function (e) {
            var s = this;
            if (s.isRunning) {
                var now = Date.now(), newX = void 0, newY = void 0, easing = void 0;
                if (now >= s.destTime) {
                    s.isRunning = false;
                    s._translate(s.destX, s.destY);
                    if (!s.resetPosition(s.bounceTime)) {
                        s.dispatchEvent(annie.Event.ON_SCROLL_STOP);
                        if (s._curX == 0 && s._curY == 0) {
                            s.dispatchEvent(annie.Event.ON_SCROLL_TO_HEAD);
                        }
                        else if (s._curX == s.maxScrollX && s._curY == s.maxScrollY) {
                            s.dispatchEvent(annie.Event.ON_SCROLL_TO_END);
                        }
                    }
                }
                else {
                    now = (now - s.startTime) / s.duration;
                    easing = s.easingFn(now);
                    newX = (s.destX - s.startX) * easing + s.startX;
                    newY = (s.destY - s.startY) * easing + s.startY;
                    s._translate(newX, newY);
                }
            }
        };
        Scroller.prototype.onMouseEvent = function (e) {
            var s = this;
            if (e.type == annie.MouseEvent.MOUSE_DOWN) {
                s.isRunning = false;
                s.mouseStatus = 1;
                s.distX = 0;
                s.distY = 0;
                s.startTime = Date.now();
                s.startX = s._curX;
                s.startY = s._curY;
                s.absStartX = s._curX;
                s.absStartY = s._curY;
                s.pointX = e.localX;
                s.pointY = e.localY;
            }
            else if (e.type == annie.MouseEvent.MOUSE_MOVE) {
                if (s.mouseStatus < 1) {
                    return;
                }
                var deltaX = e.localX - s.pointX, deltaY = e.localY - s.pointY, timestamp = Date.now(), newX = void 0, newY = void 0, absDistX = void 0, absDistY = void 0;
                s.pointX = e.localX;
                s.pointY = e.localY;
                s.distX += deltaX;
                s.distY += deltaY;
                absDistX = Math.abs(s.distX);
                absDistY = Math.abs(s.distY);
                if (timestamp - s.endTime > 300 && (absDistX < 10 && absDistY < 10)) {
                    return;
                }
                if (s.isLocked) {
                    if (absDistX > absDistY + s.lockDis) {
                        deltaY = 0;
                    }
                    else if (absDistY >= absDistX + s.lockDis) {
                        deltaX = 0;
                    }
                }
                deltaX = s.isScrollX ? deltaX : 0;
                deltaY = s.isScrollY ? deltaY : 0;
                newX = s._curX + deltaX;
                newY = s._curY + deltaY;
                if (newX > 0 || newX < s.maxScrollX) {
                    newX = s.isBounce ? s._curX + deltaX / 3 : newX > 0 ? 0 : s.maxScrollX;
                }
                if (newY > 0 || newY < s.maxScrollY) {
                    newY = s.isBounce ? s._curY + deltaY / 3 : newY > 0 ? 0 : s.maxScrollY;
                }
                if (s.mouseStatus == 1) {
                    s.dispatchEvent(annie.Event.ON_SCROLL_START);
                }
                s.mouseStatus = 2;
                s._translate(newX, newY);
                if (timestamp - s.startTime > 300) {
                    s.startTime = timestamp;
                    s.startX = s._curX;
                    s.startY = s._curY;
                }
            }
            else {
                s.endTime = Date.now();
                var momentumX = void 0, momentumY = void 0, duration = s.endTime - s.startTime, newX = s._curX, newY = s._curY, time = 0, easing = null;
                if (s.resetPosition(s.bounceTime)) {
                    s.mouseStatus = 0;
                    return;
                }
                if (s.mouseStatus != 2) {
                    s.mouseStatus = 0;
                    return;
                }
                s.mouseStatus = 0;
                s.scrollTo(newX, newY);
                if (s.isMomentum && duration < 300) {
                    momentumX = s.isScrollX ? Scroller.toMomentum(s._curX, s.startX, duration, s.maxScrollX, s.isBounce ? s.viewWidth / 2 : 0, s.deceleration) : {
                        destination: newX,
                        duration: 0
                    };
                    momentumY = s.isScrollY ? Scroller.toMomentum(s._curY, s.startY, duration, s.maxScrollY, s.isBounce ? s.viewHeight / 2 : 0, s.deceleration) : {
                        destination: newY,
                        duration: 0
                    };
                    newX = momentumX.destination;
                    newY = momentumY.destination;
                    time = Math.max(momentumX.duration, momentumY.duration);
                }
                if (newX != s._curX || newY != s._curY) {
                    if (newX > 0 || newX < s.maxScrollX || newY > 0 || newY < s.maxScrollY) {
                        easing = annie.Tween.quadraticOut;
                    }
                    s.scrollTo(newX, newY, time, easing);
                    return;
                }
                s.dispatchEvent(annie.Event.ON_SCROLL_STOP);
            }
        };
        Scroller.prototype.destroy = function () {
            var s = this;
            if (s._container) {
                s._container.removeEventListener(annie.MouseEvent.MOUSE_MOVE, s._mouseEvent, false);
                s._container.removeEventListener(annie.MouseEvent.MOUSE_DOWN, s._mouseEvent, false);
                s._container.removeEventListener(annie.MouseEvent.MOUSE_UP, s._mouseEvent, false);
                s._container.removeEventListener(annie.MouseEvent.MOUSE_OUT, s._mouseEvent);
                s._container.removeEventListener(annie.Event.ENTER_FRAME, s._enterFrame);
            }
            s._container = null;
            s.easingFn = null;
            _super.prototype.destroy.call(this);
        };
        Scroller.prototype.resetPosition = function (time) {
            if (time === void 0) { time = 0; }
            var s = this;
            var x = s._curX, y = s._curY;
            time = time || 0;
            if (!s.isScrollX || s._curX > 0) {
                x = 0;
            }
            else if (s._curX < s.maxScrollX) {
                x = s.maxScrollX;
            }
            if (!s.isScrollY || s._curY > 0) {
                y = 0;
            }
            else if (s._curY < s.maxScrollY) {
                y = s.maxScrollY;
            }
            if (x == s._curX && y == s._curY) {
                return false;
            }
            s.scrollTo(x, y, time, null);
            return true;
        };
        /**
         * 从设置的x,y坐标滑过来。 注意x y位置是负数,想想为什么
         * @method scrollBy
         * @param {number} x 从哪个x坐标滑过来
         * @param {number} y 从哪个y坐标滑过来
         * @param {number} time 滑动时长 ms,0的话没效果直接跳
         * @param {Function} easing annie.Tween中指定的缓存方法
         * @public
         * @since 3.1.5
         */
        Scroller.prototype.scrollBy = function (x, y, time, easing) {
            if (time === void 0) { time = 0; }
            if (easing === void 0) { easing = null; }
            var s = this;
            x = s._curX + x;
            y = s._curY + y;
            time = time || 0;
            s.scrollTo(x, y, time, easing);
        };
        /**
         * 滑动到设置的x,y坐标。 注意x y位置是负数,想想为什么
         * @method scrollTo
         * @param {number} x 要滑去的x坐标
         * @param {number} y 要滑去的y坐标
         * @param {number} time 滑动时长 ms,0的话没效果直接跳
         * @param {Function} easing annie.Tween中指定的缓存方法
         * @public
         * @since 3.1.5
         */
        Scroller.prototype.scrollTo = function (x, y, time, easing) {
            if (time === void 0) { time = 0; }
            if (easing === void 0) { easing = null; }
            var s = this;
            if (!time) {
                s._translate(x, y);
            }
            else {
                easing = easing || annie.Tween.circularOut;
                s.startX = s._curX;
                s.startY = s._curY;
                s.startTime = Date.now();
                s.destTime = s.startTime + time;
                s.destX = x;
                s.destY = y;
                s.duration = time;
                s.easingFn = easing;
                s.isRunning = true;
            }
        };
        Scroller.prototype._translate = function (x, y) {
            var s = this;
            s._curX = x;
            s._curY = y;
            s.dispatchEvent(annie.Event.ON_SCROLL_ING, { posX: x, posY: y });
        };
        Scroller.toMomentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
            var distance = current - start, speed = Math.abs(distance) / time, destination, duration;
            deceleration = deceleration === undefined ? 0.0006 : deceleration;
            destination = current + (speed * speed) / (2 * deceleration) * (distance < 0 ? -1 : 1);
            duration = speed / deceleration;
            if (destination < lowerMargin) {
                destination = wrapperSize ? lowerMargin - (wrapperSize / 2.5 * (speed / 8)) : lowerMargin;
                distance = Math.abs(destination - current);
                duration = distance / speed;
            }
            else if (destination > 0) {
                destination = wrapperSize ? wrapperSize / 2.5 * (speed / 8) : 0;
                distance = Math.abs(current) + destination;
                duration = distance / speed;
            }
            return {
                destination: destination,
                duration: duration
            };
        };
        ;
        return Scroller;
    }(annie.EventDispatcher));
    annieUI.Scroller = Scroller;
})(annieUI || (annieUI = {}));