UNPKG

seng-scroll-tracker

Version:

Class that keeps track of the vertical scroll position of an element.

186 lines (185 loc) 7.71 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var seng_event_1 = require("seng-event"); var ScrollTrackerPoint_1 = require("./ScrollTrackerPoint"); var Axis_1 = require("./enum/Axis"); var ScrollTrackerEvent_1 = require("./event/ScrollTrackerEvent"); var Side_1 = require("./enum/Side"); var throttle = require('lodash/throttle'); var size = require('element-size'); /** * Class that keeps track of the vertical scroll position of an element. */ var ScrollTracker = /** @class */ (function (_super) { tslib_1.__extends(ScrollTracker, _super); function ScrollTracker(element, targetAxis) { if (element === void 0) { element = window; } if (targetAxis === void 0) { targetAxis = Axis_1.default.Y; } var _this = _super.call(this) || this; _this.element = element; _this.targetAxis = targetAxis; _this.trackingPoints = []; _this.viewSize = 0; _this.scrollSize = 0; _this.viewStart = 0; _this.viewEnd = 0; _this.lastScrollPosition = 0; /** * Handles events thrown by ScrollTrackerPoint instances and bubbles them up to this * ScrollTracker instance. * @param event The event thrown. */ _this.pointEventHandler = function (event) { _this.dispatchEvent(event); }; /** * Event handler called when the target element is scrolled. Will detect the new scroll * position and call checkInView() on all tracking points. */ _this.scrollHandler = function () { _this.updateScrollPosition(); var scrollingBack = _this.viewStart < _this.lastScrollPosition; for (var i = 0; i < _this.trackingPoints.length; i += 1) { _this.trackingPoints[i].checkInView(scrollingBack); } }; /** * Event handler called when the window resizes. Only used when the target of this ScrollTracker * instance is the window object. */ _this.windowResizeHandler = function () { _this.updateSize(); }; setTimeout(function () { if (_this.isDisposed()) { return; } _this.updateSize(); _this.initEvents(); }, 0); return _this; } Object.defineProperty(ScrollTracker.prototype, "axis", { /** * Returns which axis this ScrollTracker instance is tracking. */ get: function () { return this.targetAxis; }, enumerable: true, configurable: true }); Object.defineProperty(ScrollTracker.prototype, "targetElement", { /** * Returns the target element this ScrollTracker instance is tracking. */ get: function () { return this.element; }, enumerable: true, configurable: true }); /** * Updates the size of the viewport of the target element. */ ScrollTracker.prototype.updateSize = function () { var isX = this.axis === Axis_1.default.X; var dimensions = size(this.targetElement); this.viewSize = isX ? dimensions[0] : dimensions[1]; if (this.targetElement === window) { var dimensions_1 = size(document.body); this.scrollSize = isX ? dimensions_1[0] : dimensions_1[1]; } else { var target = this.targetElement; this.scrollSize = isX ? target.scrollWidth : target.scrollHeight; } this.updateScrollPosition(); }; /** * Adds a new point of which we will detect when it enters and leaves the view. * @param position The position of this points in pixels. This is the distance from the start * or end of the target element depending on the 'side' parameter, measured horizontally or * vertically depending on the axis of this ScrollTracker instance. * @param side The side from which the 'position' parameter is defined. Side.START measures the * position from the top or left edge and Side.END will measure the position from the bottom * or right edge. * @returns {ScrollTrackerPoint} A reference to a ScrollTrackerPoint instance that can be * used to bind events, remove or update the point added. */ ScrollTracker.prototype.addPoint = function (position, height, side) { if (height === void 0) { height = 1; } if (side === void 0) { side = Side_1.default.START; } var point = new ScrollTrackerPoint_1.default(position, height, side, this); this.trackingPoints.push(point); point.addEventListener(ScrollTrackerEvent_1.default.types.ENTER_VIEW, this.pointEventHandler); point.addEventListener(ScrollTrackerEvent_1.default.types.LEAVE_VIEW, this.pointEventHandler); return point; }; /** * Removes an existing point from this ScrollTracker. This point will be destructed and will * no longer throw events. * @param point The ScrollTrackerPoint instance to remove. * @returns {boolean} Boolean indicating if the point was found and removed successfully. */ ScrollTracker.prototype.removePoint = function (point) { var index = this.trackingPoints.indexOf(point); if (index >= 0) { this.trackingPoints[index].dispose(); this.trackingPoints.splice(index, 1); return true; } return false; }; /** * Removes all points from this ScrollTracker instance. They will be destructed and will * no longer throw events. */ ScrollTracker.prototype.removeAllPoints = function () { for (var i = 0; i < this.trackingPoints.length; i += 1) { this.trackingPoints[i].dispose(); } this.trackingPoints.length = 0; }; /** * Initialize scroll and resize events using jQuery. Resize events will only be used when * the target of ScrollTracker is 'window'. If the target is not window, updateSize() has * to be called manually to update the view size. */ ScrollTracker.prototype.initEvents = function () { if (this.targetElement === window) { window.addEventListener('resize', throttle(this.windowResizeHandler, ScrollTracker._DEFAULT_THROTTLE_RESIZE)); this.windowResizeHandler(); } else { this.updateSize(); } this.targetElement.addEventListener('scroll', throttle(this.scrollHandler, ScrollTracker._DEFAULT_THROTTLE_SCROLL)); }; ScrollTracker.prototype.updateScrollPosition = function () { var isX = this.axis === Axis_1.default.X; if (this.targetElement === window) { this.viewStart = isX ? window.pageXOffset : window.pageYOffset; } else { var target = this.targetElement; this.viewStart = isX ? target.scrollLeft : target.scrollTop; } this.viewEnd = this.viewStart + this.viewSize; this.lastScrollPosition = this.viewStart; }; /** * Disposes this ScrollTracker and all points created on it. Removes all event handlers. */ ScrollTracker.prototype.dispose = function () { window.removeEventListener('resize', this.windowResizeHandler); this.targetElement.removeEventListener('scroll', this.scrollHandler); this.removeAllPoints(); _super.prototype.dispose.call(this); }; ScrollTracker._DEFAULT_THROTTLE_SCROLL = 1000 / 60; ScrollTracker._DEFAULT_THROTTLE_RESIZE = 200; return ScrollTracker; }(seng_event_1.default)); exports.default = ScrollTracker;