oirodolfo
8/28/2019 - 3:21 PM

SmoothScroll

// 10/31/2017
const SmoothScroll /** @class */ = (() => {
    class SmoothScroll {
        constructor({target, scrollEase, maxOffset}) {
            const _this = this;
            this.endThreshold = 0.05;
            this.requestId = null;
            this.maxDepth = 10;
            this.viewHeight = 0;
            this.halfViewHeight = 0;
            this.maxDistance = 0;
            this.scrollHeight = 0;
            this.endScroll = 0;
            this.currentScroll = 0;
            this.resizeRequest = 1;
            this.scrollRequest = 0;
            this.scrollItems = [];
            this.lastTime = -1;
            this.maxElapsedMS = 100;
            this.targetFPMS = 0.06;
            this._onResize = event => {
                _this.resizeRequest++;
                if (!_this.requestId) {
                    _this.lastTime = performance.now();
                    _this.requestId = requestAnimationFrame(_this._update);
                }
            };
            this._onScroll = event => {
                _this.scrollRequest++;
                if (!_this.requestId) {
                    _this.lastTime = performance.now();
                    _this.requestId = requestAnimationFrame(_this._update);
                }
            };
            this._update = currentTime => {
                if (currentTime === void 0) { currentTime = performance.now(); }
                let elapsedMS = currentTime - _this.lastTime;
                if (elapsedMS > _this.maxElapsedMS) {
                    elapsedMS = _this.maxElapsedMS;
                }
                const deltaTime = elapsedMS * _this.targetFPMS;
                const dt = 1 - (1 - _this.scrollEase) ** deltaTime;
                const resized = _this.resizeRequest > 0;
                const scrollY = window.pageYOffset;
                if (resized) {
                    const height = _this.target.clientHeight;
                    document.body.style.height = `${height}px`;
                    _this.scrollHeight = height;
                    _this.viewHeight = window.innerHeight;
                    _this.halfViewHeight = _this.viewHeight / 2;
                    _this.maxDistance = _this.viewHeight * 2;
                    _this.resizeRequest = 0;
                }
                _this.endScroll = scrollY;
                // this.currentScroll += (scrollY - this.currentScroll) * this.scrollEase;
                _this.currentScroll += (scrollY - _this.currentScroll) * dt;
                if (Math.abs(scrollY - _this.currentScroll) < _this.endThreshold || resized) {
                    _this.currentScroll = scrollY;
                    _this.scrollRequest = 0;
                }
                // const scrollOrigin = scrollY + this.halfViewHeight;
                const scrollOrigin = _this.currentScroll + _this.halfViewHeight;
                _this.target.style.transform = `translate3d(0px,-${_this.currentScroll}px,0px)`;
                for (let i = 0; i < _this.scrollItems.length; i++) {
                    const item = _this.scrollItems[i];
                    const distance = scrollOrigin - item.top;
                    const offsetRatio = distance / _this.maxDistance;
                    item.endOffset = Math.round(_this.maxOffset * item.depthRatio * offsetRatio);
                    if (Math.abs(item.endOffset - item.currentOffset < _this.endThreshold)) {
                        item.currentOffset = item.endOffset;
                    }
                    else {
                        // item.currentOffset += (item.endOffset - item.currentOffset) * this.scrollEase;
                        item.currentOffset += (item.endOffset - item.currentOffset) * dt;
                    }
                    item.target.style.transform = `translate3d(0px,-${item.currentOffset}px,0px)`;
                }
                _this.lastTime = currentTime;
                _this.requestId = _this.scrollRequest > 0 ? requestAnimationFrame(_this._update) : null;
            };
            this.target = target;
            this.scrollEase = scrollEase != null ? scrollEase : 0.1;
            this.maxOffset = maxOffset != null ? maxOffset : 500;
            this.addItems();
            window.addEventListener("resize", this._onResize);
            window.addEventListener("scroll", this._onScroll);
            this._update();
        }

        addItems() {
            this.scrollItems = [];
            const elements = document.querySelectorAll("*[data-depth]");
            for (let i = 0; i < elements.length; i++) {
                const element = elements[i];
                const depth = +element.getAttribute("data-depth");
                const rect = element.getBoundingClientRect();
                const item = {
                    target: element,
                    depth,
                    top: rect.top + window.pageYOffset,
                    depthRatio: depth / this.maxDepth,
                    currentOffset: 0,
                    endOffset: 0
                };
                this.scrollItems.push(item);
            }
            return this;
        }
    }

    return SmoothScroll;
})();