seng-scroll-tracker
Version:
Class that keeps track of the vertical scroll position of an element.
186 lines (185 loc) • 7.71 kB
JavaScript
"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;