UNPKG

zero-g

Version:

A utility library for efficiently adding panning and zooming capabilities to any DOM element. Comes with out-of-the-box TypeScript typings!

246 lines (245 loc) 10.5 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); var util_1 = require("./util"); var Orientation; (function (Orientation) { Orientation[Orientation["Landscape"] = 0] = "Landscape"; Orientation[Orientation["Portrait"] = 1] = "Portrait"; Orientation[Orientation["Square"] = 2] = "Square"; })(Orientation || (Orientation = {})); var defaultPannerOptions = { changeCursorOnPan: true, disabled: false, refitOnResize: true, onScaleChange: function (currentScale) { return undefined; }, onPanEnd: function (panEvent, instance) { return undefined; }, onPanMove: function (panEvent, instance) { return undefined; }, onPanStart: function (panEvent, instance) { return undefined; }, }; var allowedPannerOptionKeys = Object.keys(defaultPannerOptions); var ZeroGInstance = (function () { function ZeroGInstance(element, options, controlledByDockingProcedure) { var _this = this; if (options === void 0) { options = defaultPannerOptions; } if (controlledByDockingProcedure === void 0) { controlledByDockingProcedure = false; } this.element = element; this.options = options; this.controlledByDockingProcedure = controlledByDockingProcedure; this.lastX = null; this.lastY = null; this.zoom = null; this.mousedown = false; this.hasLoadHandler = false; this.preventDrag = function (e) { e.preventDefault(); }; this.handleMouseDown = function (e) { _this.mousedown = true; if (_this.options.changeCursorOnPan) _this.swapMouseCursor(); if (_this.options.onPanStart) _this.options.onPanStart({ lastX: null, lastY: null, x: e.pageX, y: e.pageY }, _this); }; this.handleMouseUp = function (e) { if (_this.options.onPanEnd) _this.options.onPanEnd({ lastX: _this.lastX, lastY: _this.lastY, x: e.pageX, y: e.pageY }, _this); _this.clearLast(); _this.mousedown = false; if (_this.options.changeCursorOnPan) _this.swapMouseCursor(); }; this.handleMouseMove = function (e) { if (_this.mousedown) { if (_this.options.onPanMove) _this.options.onPanMove({ lastX: _this.lastX, lastY: _this.lastY, x: e.pageX, y: e.pageY }, _this); if (!_this.controlledByDockingProcedure) _this.doPan(e.pageX, e.pageY); } }; this.handleWindowResize = function () { if (_this.windowResizeTimeout) _this.windowResizeTimeout = clearTimeout(_this.windowResizeTimeout); _this.windowResizeTimeout = setTimeout(function () { return _this.zoomFit(); }, 1); }; this.handleInitialLoad = function () { _this.computeNaturalDimensions(); _this.fit(); }; this.options = __assign(__assign({}, defaultPannerOptions), options); this.init(); } Object.defineProperty(ZeroGInstance.prototype, "currentScale", { get: function () { return Math.min(this.element.clientHeight / this.naturalHeight, this.element.clientWidth / this.naturalWidth); }, enumerable: true, configurable: true }); ZeroGInstance.prototype.bindHandlers = function () { if (this.element instanceof HTMLImageElement || this.element instanceof HTMLVideoElement) { this.hasLoadHandler = true; this.element.addEventListener('load', this.handleInitialLoad); } this.element.addEventListener('mousedown', this.handleMouseDown); this.element.addEventListener('dragstart', this.preventDrag); document.addEventListener('mouseup', this.handleMouseUp); document.addEventListener('mousemove', this.handleMouseMove); if (this.options.refitOnResize) window.addEventListener('resize', this.handleWindowResize); }; ZeroGInstance.prototype.unbindHandlers = function () { if (this.hasLoadHandler) { this.hasLoadHandler = false; this.element.removeEventListener('load', this.handleInitialLoad); } this.element.removeEventListener('mousedown', this.handleMouseDown); document.removeEventListener('mouseup', this.handleMouseUp); document.removeEventListener('mousemove', this.handleMouseMove); }; ZeroGInstance.prototype.computeNaturalDimensions = function () { if (this.element instanceof HTMLImageElement) { this.naturalHeight = this.element.naturalHeight; this.naturalWidth = this.element.naturalWidth; } else if (this.element instanceof HTMLVideoElement) { this.naturalHeight = this.element.videoHeight; this.naturalWidth = this.element.videoWidth; } else { this.naturalHeight = this.element.clientHeight; this.naturalWidth = this.element.clientWidth; } }; ZeroGInstance.prototype.init = function () { this.parent = this.element.parentElement; this.computeNaturalDimensions(); if (this.naturalWidth > this.naturalHeight) this.orientation = Orientation.Landscape; else if (this.naturalHeight > this.naturalWidth) this.orientation = Orientation.Portrait; else this.orientation = Orientation.Square; this.element.style.position = 'absolute'; this.element.style.willChange = 'top, left, width, height'; if (this.options.changeCursorOnPan) this.swapMouseCursor(); this.bindHandlers(); this.queueInitialFit(); }; ZeroGInstance.prototype.fitLandscape = function () { this.element.style.width = '100%'; this.element.style.height = 'auto'; this.element.style.left = util_1.toPx(0); this.element.style.top = util_1.toPx((this.parent.clientHeight - this.element.clientHeight) / 2); }; ZeroGInstance.prototype.fitPortrait = function () { this.element.style.width = 'auto'; this.element.style.height = '100%'; this.element.style.left = util_1.toPx((this.parent.clientWidth - this.element.clientWidth) / 2); this.element.style.top = util_1.toPx(0); }; ZeroGInstance.prototype.adjustIfOverflown = function () { if (this.element.clientHeight > this.parent.clientHeight) return this.fitPortrait(); if (this.element.clientWidth > this.parent.clientWidth) return this.fitLandscape(); }; ZeroGInstance.prototype.swapMouseCursor = function () { if (this.mousedown) this.element.style.cursor = 'grabbing'; else this.element.style.cursor = 'grab'; }; ZeroGInstance.prototype.doPan = function (pageX, pageY, lastX, lastY) { if (lastX === void 0) { lastX = this.lastX; } if (lastY === void 0) { lastY = this.lastY; } var deltaX = lastX !== null ? pageX - lastX : 0; var deltaY = lastY !== null ? pageY - lastY : 0; this.element.style.top = util_1.toPx(this.element.offsetTop + deltaY); this.element.style.left = util_1.toPx(this.element.offsetLeft + deltaX); this.lastX = pageX; this.lastY = pageY; }; ZeroGInstance.prototype.fit = function () { switch (this.orientation) { case Orientation.Landscape: this.fitLandscape(); break; case Orientation.Portrait: this.fitPortrait(); break; case Orientation.Square: this.fitLandscape(); break; default: break; } this.adjustIfOverflown(); if (this.options.onScaleChange) this.options.onScaleChange(this.currentScale); }; ZeroGInstance.prototype.queueInitialFit = function () { if (this.element instanceof HTMLImageElement || this.element instanceof HTMLVideoElement) { this.element.addEventListener('load', this.handleInitialLoad); } }; ZeroGInstance.prototype.destroy = function () { this.unbindHandlers(); }; ZeroGInstance.prototype.controlledPan = function (panEvent) { this.pan(panEvent.x, panEvent.y, panEvent.lastX, panEvent.lastY); }; ZeroGInstance.prototype.set = function (prop, val, reinit) { if (reinit === void 0) { reinit = false; } if (allowedPannerOptionKeys.indexOf(prop) > -1) { this.options[prop] = val; if (reinit) { this.unbindHandlers(); this.init(); } } }; ZeroGInstance.prototype.zoomFit = function () { this.zoom = null; this.fit(); }; ZeroGInstance.prototype.zoomInOut = function (level) { this.zoom = level; var newHeight = this.naturalHeight * this.zoom; var newWidth = this.naturalWidth * this.zoom; this.element.style.height = util_1.toPx(newHeight); this.element.style.width = util_1.toPx(newWidth); if (this.options.onScaleChange) this.options.onScaleChange(this.currentScale); }; ZeroGInstance.prototype.pan = function (x, y, lastX, lastY) { this.doPan(x, y, lastX, lastY); }; ZeroGInstance.prototype.clearLast = function () { this.lastX = this.lastY = null; }; return ZeroGInstance; }()); exports.ZeroGInstance = ZeroGInstance; function createZeroG(element, options) { if (options === void 0) { options = defaultPannerOptions; } if (!element) throw new Error('Unable to initialize zero-g because no DOM element was provided'); if (!element.parentElement) throw new Error('Unable to initialize zero-g because DOM element provided has no parent'); var instance = new ZeroGInstance(element, options); instance.zoomFit(); return instance; } exports.default = createZeroG;