This commit is contained in:
Bellord
2026-06-11 20:07:42 +03:00
parent 4a87dfe2a2
commit 2fcea871be
171 changed files with 20476 additions and 2780 deletions
+51
View File
@@ -0,0 +1,51 @@
export interface ActualSizeIcons {
zoomIn: 'lg-zoom-in' | 'lg-actual-size';
zoomOut: 'lg-zoom-out' | 'lg-actual-size';
}
export interface ZoomStrings {
zoomIn: string;
zoomOut: string;
viewActualSize: string;
}
export interface ZoomSettings {
/**
* Value of zoom should be incremented/decremented
*/
scale: number;
/**
* Enable/Disable zoom option
*/
zoom: boolean;
/**
* Enable/Disable infinite zoom
* @description If you set this to true, you can zoom in more than the original size of the image.
*/
infiniteZoom: boolean;
/**
* Enable actual size icon.
*/
actualSize: boolean;
/**
* Once the slide transition is completed, how much time should take zoom plugin to activate
* @description Some css styles will be added to the images if zoom is enabled.
* So it might conflict if you add any custom styles to the images such as the initial transition while opening the gallery.
* So you can delay adding zoom related styles to the images by changing the value of enableZoomAfter.
*/
enableZoomAfter: number;
/**
* Show zoom in, zoom out icons
*/
showZoomInOutIcons: boolean;
/**
* Actual size icons classnames.
* Specify classnames for both ZoomIn and ZoomOut states
* You can use `actualSizeIcons: { zoomIn: 'lg-actual-size', zoomOut: 'lg-zoom-out' }`
* to show actual size icons instead of zoom in and zoom out icons.
*/
actualSizeIcons: ActualSizeIcons;
/**
* Custom translation strings for aria-labels
*/
zoomPluginStrings: ZoomStrings;
}
export declare const zoomSettings: ZoomSettings;
+108
View File
@@ -0,0 +1,108 @@
import { LgQuery, lgQuery } from '../../lgQuery';
import { LightGallery } from '../../lightgallery';
interface Coords {
x: number;
y: number;
}
interface DragAllowedAxises {
allowX: boolean;
allowY: boolean;
}
interface ZoomTouchEvent {
pageX: number;
touches: {
pageY: number;
pageX: number;
}[];
pageY: number;
}
interface PossibleCords {
minX: number;
minY: number;
maxX: number;
maxY: number;
}
export default class Zoom {
private core;
private settings;
private $LG;
private imageReset;
zoomableTimeout: any;
positionChanged: boolean;
zoomInProgress: boolean;
pageX: number;
pageY: number;
scale: number;
containerRect: ClientRect;
dragAllowedAxises: DragAllowedAxises;
top: number;
left: number;
scrollTop: number;
constructor(instance: LightGallery, $LG: LgQuery);
buildTemplates(): void;
/**
* @desc Enable zoom option only once the image is completely loaded
* If zoomFromOrigin is true, Zoom is enabled once the dummy image has been inserted
*
* Zoom styles are defined under lg-zoomable CSS class.
*/
enableZoom(event: CustomEvent): void;
enableZoomOnSlideItemLoad(): void;
getDragCords(e: MouseEvent): Coords;
getSwipeCords(e: TouchEvent): Coords;
getDragAllowedAxises(scale: number, scaleDiff?: number): DragAllowedAxises;
setZoomEssentials(): void;
/**
* @desc Image zoom
* Translate the wrap and scale the image to get better user experience
*
* @param {String} scale - Zoom decrement/increment value
*/
zoomImage(scale: number, scaleDiff: number, reposition: boolean, resetToMax: boolean): void;
resetImageTranslate(index: number): void;
setZoomImageSize(): void;
/**
* @desc apply scale3d to image and translate to image wrap
* @param {style} X,Y and scale
*/
setZoomStyles(style: {
x: number;
y: number;
scale: number;
}): void;
/**
* @param index - Index of the current slide
* @param event - event will be available only if the function is called on clicking/taping the imags
*/
setActualSize(index: number, event?: ZoomTouchEvent): void;
getNaturalWidth(index: number): number;
getActualSizeScale(naturalWidth: number, width: number): number;
getCurrentImageActualSizeScale(): number;
getPageCords(event?: ZoomTouchEvent): Coords;
setPageCords(event?: ZoomTouchEvent): void;
manageActualPixelClassNames(): void;
beginZoom(scale: number): boolean;
getScale(scale: number): number;
init(): void;
zoomIn(): void;
resetZoom(index?: number): void;
getTouchDistance(e: TouchEvent): number;
pinchZoom(): void;
touchendZoom(startCoords: Coords, endCoords: Coords, allowX: boolean, allowY: boolean, touchDuration: number): void;
getZoomSwipeCords(startCoords: Coords, endCoords: Coords, allowX: boolean, allowY: boolean, possibleSwipeCords: PossibleCords): Coords;
private isBeyondPossibleLeft;
private isBeyondPossibleRight;
private isBeyondPossibleTop;
private isBeyondPossibleBottom;
isImageSlide(index: number): boolean;
getPossibleSwipeDragCords(scale?: number): PossibleCords;
setZoomSwipeStyles(LGel: lgQuery, distance: {
x: number;
y: number;
}): void;
zoomSwipe(): void;
zoomDrag(): void;
closeGallery(): void;
destroy(): void;
}
export {};
@@ -0,0 +1,980 @@
/*!
* lightgallery | 2.9.0 | October 1st 2025
* http://www.lightgalleryjs.com/
* Copyright (c) 2020 Sachin Neravath;
* @license GPLv3
*/
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
var __assign = function() {
__assign = Object.assign || function __assign(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);
};
var zoomSettings = {
scale: 1,
zoom: true,
infiniteZoom: true,
actualSize: true,
showZoomInOutIcons: false,
actualSizeIcons: {
zoomIn: 'lg-zoom-in',
zoomOut: 'lg-zoom-out',
},
enableZoomAfter: 300,
zoomPluginStrings: {
zoomIn: 'Zoom in',
zoomOut: 'Zoom out',
viewActualSize: 'View actual size',
},
};
/**
* List of lightGallery events
* All events should be documented here
* Below interfaces are used to build the website documentations
* */
var lGEvents = {
afterAppendSlide: 'lgAfterAppendSlide',
init: 'lgInit',
hasVideo: 'lgHasVideo',
containerResize: 'lgContainerResize',
updateSlides: 'lgUpdateSlides',
afterAppendSubHtml: 'lgAfterAppendSubHtml',
beforeOpen: 'lgBeforeOpen',
afterOpen: 'lgAfterOpen',
slideItemLoad: 'lgSlideItemLoad',
beforeSlide: 'lgBeforeSlide',
afterSlide: 'lgAfterSlide',
posterClick: 'lgPosterClick',
dragStart: 'lgDragStart',
dragMove: 'lgDragMove',
dragEnd: 'lgDragEnd',
beforeNextSlide: 'lgBeforeNextSlide',
beforePrevSlide: 'lgBeforePrevSlide',
beforeClose: 'lgBeforeClose',
afterClose: 'lgAfterClose',
rotateLeft: 'lgRotateLeft',
rotateRight: 'lgRotateRight',
flipHorizontal: 'lgFlipHorizontal',
flipVertical: 'lgFlipVertical',
autoplay: 'lgAutoplay',
autoplayStart: 'lgAutoplayStart',
autoplayStop: 'lgAutoplayStop',
};
var ZOOM_TRANSITION_DURATION = 500;
var Zoom = /** @class */ (function () {
function Zoom(instance, $LG) {
// get lightGallery core plugin instance
this.core = instance;
this.$LG = $LG;
this.settings = __assign(__assign({}, zoomSettings), this.core.settings);
return this;
}
// Append Zoom controls. Actual size, Zoom-in, Zoom-out
Zoom.prototype.buildTemplates = function () {
var zoomIcons = this.settings.showZoomInOutIcons
? "<button id=\"" + this.core.getIdName('lg-zoom-in') + "\" type=\"button\" aria-label=\"" + this.settings.zoomPluginStrings['zoomIn'] + "\" class=\"lg-zoom-in lg-icon\"></button><button id=\"" + this.core.getIdName('lg-zoom-out') + "\" type=\"button\" aria-label=\"" + this.settings.zoomPluginStrings['zoomOut'] + "\" class=\"lg-zoom-out lg-icon\"></button>"
: '';
if (this.settings.actualSize) {
zoomIcons += "<button id=\"" + this.core.getIdName('lg-actual-size') + "\" type=\"button\" aria-label=\"" + this.settings.zoomPluginStrings['viewActualSize'] + "\" class=\"" + this.settings.actualSizeIcons.zoomIn + " lg-icon\"></button>";
}
this.core.outer.addClass('lg-use-transition-for-zoom');
this.core.$toolbar.first().append(zoomIcons);
};
/**
* @desc Enable zoom option only once the image is completely loaded
* If zoomFromOrigin is true, Zoom is enabled once the dummy image has been inserted
*
* Zoom styles are defined under lg-zoomable CSS class.
*/
Zoom.prototype.enableZoom = function (event) {
var _this = this;
// delay will be 0 except first time
var _speed = this.settings.enableZoomAfter + event.detail.delay;
// set _speed value 0 if gallery opened from direct url and if it is first slide
if (this.$LG('body').first().hasClass('lg-from-hash') &&
event.detail.delay) {
// will execute only once
_speed = 0;
}
else {
// Remove lg-from-hash to enable starting animation.
this.$LG('body').first().removeClass('lg-from-hash');
}
this.zoomableTimeout = setTimeout(function () {
if (!_this.isImageSlide(_this.core.index)) {
return;
}
_this.core.getSlideItem(event.detail.index).addClass('lg-zoomable');
if (event.detail.index === _this.core.index) {
_this.setZoomEssentials();
}
}, _speed + 30);
};
Zoom.prototype.enableZoomOnSlideItemLoad = function () {
// Add zoomable class
this.core.LGel.on(lGEvents.slideItemLoad + ".zoom", this.enableZoom.bind(this));
};
Zoom.prototype.getDragCords = function (e) {
return {
x: e.pageX,
y: e.pageY,
};
};
Zoom.prototype.getSwipeCords = function (e) {
var x = e.touches[0].pageX;
var y = e.touches[0].pageY;
return {
x: x,
y: y,
};
};
Zoom.prototype.getDragAllowedAxises = function (scale, scaleDiff) {
if (!this.containerRect) {
return {
allowX: false,
allowY: false,
};
}
var $image = this.core
.getSlideItem(this.core.index)
.find('.lg-image')
.first()
.get();
var height = 0;
var width = 0;
var rect = $image.getBoundingClientRect();
if (scale) {
height = $image.offsetHeight * scale;
width = $image.offsetWidth * scale;
}
else if (scaleDiff) {
height = rect.height + scaleDiff * rect.height;
width = rect.width + scaleDiff * rect.width;
}
else {
height = rect.height;
width = rect.width;
}
var allowY = height > this.containerRect.height;
var allowX = width > this.containerRect.width;
return {
allowX: allowX,
allowY: allowY,
};
};
Zoom.prototype.setZoomEssentials = function () {
this.containerRect = this.core.$content.get().getBoundingClientRect();
};
/**
* @desc Image zoom
* Translate the wrap and scale the image to get better user experience
*
* @param {String} scale - Zoom decrement/increment value
*/
Zoom.prototype.zoomImage = function (scale, scaleDiff, reposition, resetToMax) {
if (!this.containerRect || Math.abs(scaleDiff) <= 0)
return;
var offsetX = this.containerRect.width / 2 + this.containerRect.left;
var offsetY = this.containerRect.height / 2 +
this.containerRect.top +
this.scrollTop;
var originalX;
var originalY;
if (scale === 1) {
this.positionChanged = false;
}
var dragAllowedAxises = this.getDragAllowedAxises(0, scaleDiff);
var allowY = dragAllowedAxises.allowY, allowX = dragAllowedAxises.allowX;
if (this.positionChanged) {
originalX = this.left / (this.scale - scaleDiff);
originalY = this.top / (this.scale - scaleDiff);
this.pageX = offsetX - originalX;
this.pageY = offsetY - originalY;
this.positionChanged = false;
}
var possibleSwipeCords = this.getPossibleSwipeDragCords(scaleDiff);
var x;
var y;
var _x = offsetX - this.pageX;
var _y = offsetY - this.pageY;
if (scale - scaleDiff > 1) {
var scaleVal = (scale - scaleDiff) / Math.abs(scaleDiff);
_x =
(scaleDiff < 0 ? -_x : _x) +
this.left * (scaleVal + (scaleDiff < 0 ? -1 : 1));
_y =
(scaleDiff < 0 ? -_y : _y) +
this.top * (scaleVal + (scaleDiff < 0 ? -1 : 1));
x = _x / scaleVal;
y = _y / scaleVal;
}
else {
var scaleVal = (scale - scaleDiff) * scaleDiff;
x = _x * scaleVal;
y = _y * scaleVal;
}
if (reposition) {
if (allowX) {
if (this.isBeyondPossibleLeft(x, possibleSwipeCords.minX)) {
x = possibleSwipeCords.minX;
}
else if (this.isBeyondPossibleRight(x, possibleSwipeCords.maxX)) {
x = possibleSwipeCords.maxX;
}
}
else {
if (scale > 1) {
if (x < possibleSwipeCords.minX) {
x = possibleSwipeCords.minX;
}
else if (x > possibleSwipeCords.maxX) {
x = possibleSwipeCords.maxX;
}
}
}
// @todo fix this
if (allowY) {
if (this.isBeyondPossibleTop(y, possibleSwipeCords.minY)) {
y = possibleSwipeCords.minY;
}
else if (this.isBeyondPossibleBottom(y, possibleSwipeCords.maxY)) {
y = possibleSwipeCords.maxY;
}
}
else {
// If the translate value based on index of beyond the viewport, utilize the available space to prevent image being cut out
if (scale > 1) {
//If image goes beyond viewport top, use the minim possible translate value
if (y < possibleSwipeCords.minY) {
y = possibleSwipeCords.minY;
}
else if (y > possibleSwipeCords.maxY) {
y = possibleSwipeCords.maxY;
}
}
}
}
this.setZoomStyles({
x: x,
y: y,
scale: scale,
});
this.left = x;
this.top = y;
if (resetToMax) {
this.setZoomImageSize();
}
};
Zoom.prototype.resetImageTranslate = function (index) {
if (!this.isImageSlide(index)) {
return;
}
var $image = this.core.getSlideItem(index).find('.lg-image').first();
this.imageReset = false;
$image.removeClass('reset-transition reset-transition-y reset-transition-x');
this.core.outer.removeClass('lg-actual-size');
$image.css('width', 'auto').css('height', 'auto');
setTimeout(function () {
$image.removeClass('no-transition');
}, 10);
};
Zoom.prototype.setZoomImageSize = function () {
var _this = this;
var $image = this.core
.getSlideItem(this.core.index)
.find('.lg-image')
.first();
setTimeout(function () {
var actualSizeScale = _this.getCurrentImageActualSizeScale();
if (_this.scale >= actualSizeScale) {
$image.addClass('no-transition');
_this.imageReset = true;
}
}, ZOOM_TRANSITION_DURATION);
setTimeout(function () {
var actualSizeScale = _this.getCurrentImageActualSizeScale();
if (_this.scale >= actualSizeScale) {
var dragAllowedAxises = _this.getDragAllowedAxises(_this.scale);
$image
.css('width', $image.get().naturalWidth + 'px')
.css('height', $image.get().naturalHeight + 'px');
_this.core.outer.addClass('lg-actual-size');
if (dragAllowedAxises.allowX && dragAllowedAxises.allowY) {
$image.addClass('reset-transition');
}
else if (dragAllowedAxises.allowX &&
!dragAllowedAxises.allowY) {
$image.addClass('reset-transition-x');
}
else if (!dragAllowedAxises.allowX &&
dragAllowedAxises.allowY) {
$image.addClass('reset-transition-y');
}
}
}, ZOOM_TRANSITION_DURATION + 50);
};
/**
* @desc apply scale3d to image and translate to image wrap
* @param {style} X,Y and scale
*/
Zoom.prototype.setZoomStyles = function (style) {
var $imageWrap = this.core
.getSlideItem(this.core.index)
.find('.lg-img-wrap')
.first();
var $image = this.core
.getSlideItem(this.core.index)
.find('.lg-image')
.first();
var $dummyImage = this.core.outer
.find('.lg-current .lg-dummy-img')
.first();
this.scale = style.scale;
$image.css('transform', 'scale3d(' + style.scale + ', ' + style.scale + ', 1)');
$dummyImage.css('transform', 'scale3d(' + style.scale + ', ' + style.scale + ', 1)');
var transform = 'translate3d(' + style.x + 'px, ' + style.y + 'px, 0)';
$imageWrap.css('transform', transform);
};
/**
* @param index - Index of the current slide
* @param event - event will be available only if the function is called on clicking/taping the imags
*/
Zoom.prototype.setActualSize = function (index, event) {
var _this = this;
if (this.zoomInProgress) {
return;
}
this.zoomInProgress = true;
var currentItem = this.core.galleryItems[this.core.index];
this.resetImageTranslate(index);
setTimeout(function () {
// Allow zoom only on image
if (!currentItem.src ||
_this.core.outer.hasClass('lg-first-slide-loading')) {
return;
}
var scale = _this.getCurrentImageActualSizeScale();
var prevScale = _this.scale;
if (_this.core.outer.hasClass('lg-zoomed')) {
_this.scale = 1;
}
else {
_this.scale = _this.getScale(scale);
}
_this.setPageCords(event);
_this.beginZoom(_this.scale);
_this.zoomImage(_this.scale, _this.scale - prevScale, true, true);
}, 50);
setTimeout(function () {
_this.core.outer.removeClass('lg-grabbing').addClass('lg-grab');
}, 60);
setTimeout(function () {
_this.zoomInProgress = false;
}, ZOOM_TRANSITION_DURATION + 110);
};
Zoom.prototype.getNaturalWidth = function (index) {
var $image = this.core.getSlideItem(index).find('.lg-image').first();
var naturalWidth = this.core.galleryItems[index].width;
return naturalWidth
? parseFloat(naturalWidth)
: $image.get().naturalWidth;
};
Zoom.prototype.getActualSizeScale = function (naturalWidth, width) {
var _scale;
var scale;
if (naturalWidth >= width) {
_scale = naturalWidth / width;
scale = _scale || 2;
}
else {
scale = 1;
}
return scale;
};
Zoom.prototype.getCurrentImageActualSizeScale = function () {
var $image = this.core
.getSlideItem(this.core.index)
.find('.lg-image')
.first();
var width = $image.get().offsetWidth;
var naturalWidth = this.getNaturalWidth(this.core.index) || width;
return this.getActualSizeScale(naturalWidth, width);
};
Zoom.prototype.getPageCords = function (event) {
var cords = {};
if (event) {
cords.x = event.pageX || event.touches[0].pageX;
cords.y = event.pageY || event.touches[0].pageY;
}
else {
var containerRect = this.core.$content
.get()
.getBoundingClientRect();
cords.x = containerRect.width / 2 + containerRect.left;
cords.y =
containerRect.height / 2 + this.scrollTop + containerRect.top;
}
return cords;
};
Zoom.prototype.setPageCords = function (event) {
var pageCords = this.getPageCords(event);
this.pageX = pageCords.x;
this.pageY = pageCords.y;
};
Zoom.prototype.manageActualPixelClassNames = function () {
var $actualSize = this.core.getElementById('lg-actual-size');
$actualSize
.removeClass(this.settings.actualSizeIcons.zoomIn)
.addClass(this.settings.actualSizeIcons.zoomOut);
};
// If true, zoomed - in else zoomed out
Zoom.prototype.beginZoom = function (scale) {
this.core.outer.removeClass('lg-zoom-drag-transition lg-zoom-dragging');
if (scale > 1) {
this.core.outer.addClass('lg-zoomed');
this.manageActualPixelClassNames();
}
else {
this.resetZoom();
}
return scale > 1;
};
Zoom.prototype.getScale = function (scale) {
var actualSizeScale = this.getCurrentImageActualSizeScale();
if (scale < 1) {
scale = 1;
}
else if (scale > actualSizeScale) {
scale = actualSizeScale;
}
return scale;
};
Zoom.prototype.init = function () {
var _this = this;
if (!this.settings.zoom) {
return;
}
this.buildTemplates();
this.enableZoomOnSlideItemLoad();
var tapped = null;
this.core.outer.on('dblclick.lg', function (event) {
if (!_this.$LG(event.target).hasClass('lg-image')) {
return;
}
_this.setActualSize(_this.core.index, event);
});
this.core.outer.on('touchstart.lg', function (event) {
var $target = _this.$LG(event.target);
if (event.touches.length === 1 && $target.hasClass('lg-image')) {
if (!tapped) {
tapped = setTimeout(function () {
tapped = null;
}, 300);
}
else {
clearTimeout(tapped);
tapped = null;
event.preventDefault();
_this.setActualSize(_this.core.index, event);
}
}
});
this.core.LGel.on(lGEvents.containerResize + ".zoom " + lGEvents.rotateRight + ".zoom " + lGEvents.rotateLeft + ".zoom " + lGEvents.flipHorizontal + ".zoom " + lGEvents.flipVertical + ".zoom", function () {
if (!_this.core.lgOpened ||
!_this.isImageSlide(_this.core.index) ||
_this.core.touchAction) {
return;
}
var _LGel = _this.core
.getSlideItem(_this.core.index)
.find('.lg-img-wrap')
.first();
_this.top = 0;
_this.left = 0;
_this.setZoomEssentials();
_this.setZoomSwipeStyles(_LGel, { x: 0, y: 0 });
_this.positionChanged = true;
});
// Update zoom on resize and orientationchange
this.$LG(window).on("scroll.lg.zoom.global" + this.core.lgId, function () {
if (!_this.core.lgOpened)
return;
_this.scrollTop = _this.$LG(window).scrollTop();
});
this.core.getElementById('lg-zoom-out').on('click.lg', function () {
// Allow zoom only on image
if (!_this.isImageSlide(_this.core.index)) {
return;
}
var timeout = 0;
if (_this.imageReset) {
_this.resetImageTranslate(_this.core.index);
timeout = 50;
}
setTimeout(function () {
var scale = _this.scale - _this.settings.scale;
if (scale < 1) {
scale = 1;
}
_this.beginZoom(scale);
_this.zoomImage(scale, -_this.settings.scale, true, !_this.settings.infiniteZoom);
}, timeout);
});
this.core.getElementById('lg-zoom-in').on('click.lg', function () {
_this.zoomIn();
});
this.core.getElementById('lg-actual-size').on('click.lg', function () {
_this.setActualSize(_this.core.index);
});
this.core.LGel.on(lGEvents.beforeOpen + ".zoom", function () {
_this.core.outer.find('.lg-item').removeClass('lg-zoomable');
});
this.core.LGel.on(lGEvents.afterOpen + ".zoom", function () {
_this.scrollTop = _this.$LG(window).scrollTop();
// Set the initial value center
_this.pageX = _this.core.outer.width() / 2;
_this.pageY = _this.core.outer.height() / 2 + _this.scrollTop;
_this.scale = 1;
});
// Reset zoom on slide change
this.core.LGel.on(lGEvents.afterSlide + ".zoom", function (event) {
var prevIndex = event.detail.prevIndex;
_this.scale = 1;
_this.positionChanged = false;
_this.zoomInProgress = false;
_this.resetZoom(prevIndex);
_this.resetImageTranslate(prevIndex);
if (_this.isImageSlide(_this.core.index)) {
_this.setZoomEssentials();
}
});
// Drag option after zoom
this.zoomDrag();
this.pinchZoom();
this.zoomSwipe();
// Store the zoomable timeout value just to clear it while closing
this.zoomableTimeout = false;
this.positionChanged = false;
this.zoomInProgress = false;
};
Zoom.prototype.zoomIn = function () {
// Allow zoom only on image
if (!this.isImageSlide(this.core.index)) {
return;
}
var scale = this.scale + this.settings.scale;
if (!this.settings.infiniteZoom) {
scale = this.getScale(scale);
}
this.beginZoom(scale);
this.zoomImage(scale, Math.min(this.settings.scale, scale - this.scale), true, !this.settings.infiniteZoom);
};
// Reset zoom effect
Zoom.prototype.resetZoom = function (index) {
this.core.outer.removeClass('lg-zoomed lg-zoom-drag-transition');
var $actualSize = this.core.getElementById('lg-actual-size');
var $item = this.core.getSlideItem(index !== undefined ? index : this.core.index);
$actualSize
.removeClass(this.settings.actualSizeIcons.zoomOut)
.addClass(this.settings.actualSizeIcons.zoomIn);
$item.find('.lg-img-wrap').first().removeAttr('style');
$item.find('.lg-image').first().removeAttr('style');
this.scale = 1;
this.left = 0;
this.top = 0;
// Reset pagx pagy values to center
this.setPageCords();
};
Zoom.prototype.getTouchDistance = function (e) {
return Math.sqrt((e.touches[0].pageX - e.touches[1].pageX) *
(e.touches[0].pageX - e.touches[1].pageX) +
(e.touches[0].pageY - e.touches[1].pageY) *
(e.touches[0].pageY - e.touches[1].pageY));
};
Zoom.prototype.pinchZoom = function () {
var _this = this;
var startDist = 0;
var pinchStarted = false;
var initScale = 1;
var prevScale = 0;
var $item = this.core.getSlideItem(this.core.index);
this.core.outer.on('touchstart.lg', function (e) {
$item = _this.core.getSlideItem(_this.core.index);
if (!_this.isImageSlide(_this.core.index)) {
return;
}
if (e.touches.length === 2) {
e.preventDefault();
if (_this.core.outer.hasClass('lg-first-slide-loading')) {
return;
}
initScale = _this.scale || 1;
_this.core.outer.removeClass('lg-zoom-drag-transition lg-zoom-dragging');
_this.setPageCords(e);
_this.resetImageTranslate(_this.core.index);
_this.core.touchAction = 'pinch';
startDist = _this.getTouchDistance(e);
}
});
this.core.$inner.on('touchmove.lg', function (e) {
if (e.touches.length === 2 &&
_this.core.touchAction === 'pinch' &&
(_this.$LG(e.target).hasClass('lg-item') ||
$item.get().contains(e.target))) {
e.preventDefault();
var endDist = _this.getTouchDistance(e);
var distance = startDist - endDist;
if (!pinchStarted && Math.abs(distance) > 5) {
pinchStarted = true;
}
if (pinchStarted) {
prevScale = _this.scale;
var _scale = Math.max(1, initScale + -distance * 0.02);
_this.scale =
Math.round((_scale + Number.EPSILON) * 100) / 100;
var diff = _this.scale - prevScale;
_this.zoomImage(_this.scale, Math.round((diff + Number.EPSILON) * 100) / 100, false, false);
}
}
});
this.core.$inner.on('touchend.lg', function (e) {
if (_this.core.touchAction === 'pinch' &&
(_this.$LG(e.target).hasClass('lg-item') ||
$item.get().contains(e.target))) {
pinchStarted = false;
startDist = 0;
if (_this.scale <= 1) {
_this.resetZoom();
}
else {
var actualSizeScale = _this.getCurrentImageActualSizeScale();
if (_this.scale >= actualSizeScale) {
var scaleDiff = actualSizeScale - _this.scale;
if (scaleDiff === 0) {
scaleDiff = 0.01;
}
_this.zoomImage(actualSizeScale, scaleDiff, false, true);
}
_this.manageActualPixelClassNames();
_this.core.outer.addClass('lg-zoomed');
}
_this.core.touchAction = undefined;
}
});
};
Zoom.prototype.touchendZoom = function (startCoords, endCoords, allowX, allowY, touchDuration) {
var distanceXnew = endCoords.x - startCoords.x;
var distanceYnew = endCoords.y - startCoords.y;
var speedX = Math.abs(distanceXnew) / touchDuration + 1;
var speedY = Math.abs(distanceYnew) / touchDuration + 1;
if (speedX > 2) {
speedX += 1;
}
if (speedY > 2) {
speedY += 1;
}
distanceXnew = distanceXnew * speedX;
distanceYnew = distanceYnew * speedY;
var _LGel = this.core
.getSlideItem(this.core.index)
.find('.lg-img-wrap')
.first();
var distance = {};
distance.x = this.left + distanceXnew;
distance.y = this.top + distanceYnew;
var possibleSwipeCords = this.getPossibleSwipeDragCords();
if (Math.abs(distanceXnew) > 15 || Math.abs(distanceYnew) > 15) {
if (allowY) {
if (this.isBeyondPossibleTop(distance.y, possibleSwipeCords.minY)) {
distance.y = possibleSwipeCords.minY;
}
else if (this.isBeyondPossibleBottom(distance.y, possibleSwipeCords.maxY)) {
distance.y = possibleSwipeCords.maxY;
}
}
if (allowX) {
if (this.isBeyondPossibleLeft(distance.x, possibleSwipeCords.minX)) {
distance.x = possibleSwipeCords.minX;
}
else if (this.isBeyondPossibleRight(distance.x, possibleSwipeCords.maxX)) {
distance.x = possibleSwipeCords.maxX;
}
}
if (allowY) {
this.top = distance.y;
}
else {
distance.y = this.top;
}
if (allowX) {
this.left = distance.x;
}
else {
distance.x = this.left;
}
this.setZoomSwipeStyles(_LGel, distance);
this.positionChanged = true;
}
};
Zoom.prototype.getZoomSwipeCords = function (startCoords, endCoords, allowX, allowY, possibleSwipeCords) {
var distance = {};
if (allowY) {
distance.y = this.top + (endCoords.y - startCoords.y);
if (this.isBeyondPossibleTop(distance.y, possibleSwipeCords.minY)) {
var diffMinY = possibleSwipeCords.minY - distance.y;
distance.y = possibleSwipeCords.minY - diffMinY / 6;
}
else if (this.isBeyondPossibleBottom(distance.y, possibleSwipeCords.maxY)) {
var diffMaxY = distance.y - possibleSwipeCords.maxY;
distance.y = possibleSwipeCords.maxY + diffMaxY / 6;
}
}
else {
distance.y = this.top;
}
if (allowX) {
distance.x = this.left + (endCoords.x - startCoords.x);
if (this.isBeyondPossibleLeft(distance.x, possibleSwipeCords.minX)) {
var diffMinX = possibleSwipeCords.minX - distance.x;
distance.x = possibleSwipeCords.minX - diffMinX / 6;
}
else if (this.isBeyondPossibleRight(distance.x, possibleSwipeCords.maxX)) {
var difMaxX = distance.x - possibleSwipeCords.maxX;
distance.x = possibleSwipeCords.maxX + difMaxX / 6;
}
}
else {
distance.x = this.left;
}
return distance;
};
Zoom.prototype.isBeyondPossibleLeft = function (x, minX) {
return x >= minX;
};
Zoom.prototype.isBeyondPossibleRight = function (x, maxX) {
return x <= maxX;
};
Zoom.prototype.isBeyondPossibleTop = function (y, minY) {
return y >= minY;
};
Zoom.prototype.isBeyondPossibleBottom = function (y, maxY) {
return y <= maxY;
};
Zoom.prototype.isImageSlide = function (index) {
var currentItem = this.core.galleryItems[index];
return this.core.getSlideType(currentItem) === 'image';
};
Zoom.prototype.getPossibleSwipeDragCords = function (scale) {
var $image = this.core
.getSlideItem(this.core.index)
.find('.lg-image')
.first();
var bottom = this.core.mediaContainerPosition.bottom;
var imgRect = $image.get().getBoundingClientRect();
var imageHeight = imgRect.height;
var imageWidth = imgRect.width;
if (scale) {
imageHeight = imageHeight + scale * imageHeight;
imageWidth = imageWidth + scale * imageWidth;
}
var minY = (imageHeight - this.containerRect.height) / 2;
var maxY = (this.containerRect.height - imageHeight) / 2 + bottom;
var minX = (imageWidth - this.containerRect.width) / 2;
var maxX = (this.containerRect.width - imageWidth) / 2;
var possibleSwipeCords = {
minY: minY,
maxY: maxY,
minX: minX,
maxX: maxX,
};
return possibleSwipeCords;
};
Zoom.prototype.setZoomSwipeStyles = function (LGel, distance) {
LGel.css('transform', 'translate3d(' + distance.x + 'px, ' + distance.y + 'px, 0)');
};
Zoom.prototype.zoomSwipe = function () {
var _this = this;
var startCoords = {};
var endCoords = {};
var isMoved = false;
// Allow x direction drag
var allowX = false;
// Allow Y direction drag
var allowY = false;
var startTime = new Date();
var endTime = new Date();
var possibleSwipeCords;
var _LGel;
var $item = this.core.getSlideItem(this.core.index);
this.core.$inner.on('touchstart.lg', function (e) {
// Allow zoom only on image
if (!_this.isImageSlide(_this.core.index)) {
return;
}
$item = _this.core.getSlideItem(_this.core.index);
if ((_this.$LG(e.target).hasClass('lg-item') ||
$item.get().contains(e.target)) &&
e.touches.length === 1 &&
_this.core.outer.hasClass('lg-zoomed')) {
e.preventDefault();
startTime = new Date();
_this.core.touchAction = 'zoomSwipe';
_LGel = _this.core
.getSlideItem(_this.core.index)
.find('.lg-img-wrap')
.first();
var dragAllowedAxises = _this.getDragAllowedAxises(0);
allowY = dragAllowedAxises.allowY;
allowX = dragAllowedAxises.allowX;
if (allowX || allowY) {
startCoords = _this.getSwipeCords(e);
}
possibleSwipeCords = _this.getPossibleSwipeDragCords();
// reset opacity and transition duration
_this.core.outer.addClass('lg-zoom-dragging lg-zoom-drag-transition');
}
});
this.core.$inner.on('touchmove.lg', function (e) {
if (e.touches.length === 1 &&
_this.core.touchAction === 'zoomSwipe' &&
(_this.$LG(e.target).hasClass('lg-item') ||
$item.get().contains(e.target))) {
e.preventDefault();
_this.core.touchAction = 'zoomSwipe';
endCoords = _this.getSwipeCords(e);
var distance = _this.getZoomSwipeCords(startCoords, endCoords, allowX, allowY, possibleSwipeCords);
if (Math.abs(endCoords.x - startCoords.x) > 15 ||
Math.abs(endCoords.y - startCoords.y) > 15) {
isMoved = true;
_this.setZoomSwipeStyles(_LGel, distance);
}
}
});
this.core.$inner.on('touchend.lg', function (e) {
if (_this.core.touchAction === 'zoomSwipe' &&
(_this.$LG(e.target).hasClass('lg-item') ||
$item.get().contains(e.target))) {
e.preventDefault();
_this.core.touchAction = undefined;
_this.core.outer.removeClass('lg-zoom-dragging');
if (!isMoved) {
return;
}
isMoved = false;
endTime = new Date();
var touchDuration = endTime.valueOf() - startTime.valueOf();
_this.touchendZoom(startCoords, endCoords, allowX, allowY, touchDuration);
}
});
};
Zoom.prototype.zoomDrag = function () {
var _this = this;
var startCoords = {};
var endCoords = {};
var isDragging = false;
var isMoved = false;
// Allow x direction drag
var allowX = false;
// Allow Y direction drag
var allowY = false;
var startTime;
var endTime;
var possibleSwipeCords;
var _LGel;
this.core.outer.on('mousedown.lg.zoom', function (e) {
// Allow zoom only on image
if (!_this.isImageSlide(_this.core.index)) {
return;
}
var $item = _this.core.getSlideItem(_this.core.index);
if (_this.$LG(e.target).hasClass('lg-item') ||
$item.get().contains(e.target)) {
startTime = new Date();
_LGel = _this.core
.getSlideItem(_this.core.index)
.find('.lg-img-wrap')
.first();
var dragAllowedAxises = _this.getDragAllowedAxises(0);
allowY = dragAllowedAxises.allowY;
allowX = dragAllowedAxises.allowX;
if (_this.core.outer.hasClass('lg-zoomed')) {
if (_this.$LG(e.target).hasClass('lg-object') &&
(allowX || allowY)) {
e.preventDefault();
startCoords = _this.getDragCords(e);
possibleSwipeCords = _this.getPossibleSwipeDragCords();
isDragging = true;
_this.core.outer
.removeClass('lg-grab')
.addClass('lg-grabbing lg-zoom-drag-transition lg-zoom-dragging');
// reset opacity and transition duration
}
}
}
});
this.$LG(window).on("mousemove.lg.zoom.global" + this.core.lgId, function (e) {
if (isDragging) {
isMoved = true;
endCoords = _this.getDragCords(e);
var distance = _this.getZoomSwipeCords(startCoords, endCoords, allowX, allowY, possibleSwipeCords);
_this.setZoomSwipeStyles(_LGel, distance);
}
});
this.$LG(window).on("mouseup.lg.zoom.global" + this.core.lgId, function (e) {
if (isDragging) {
endTime = new Date();
isDragging = false;
_this.core.outer.removeClass('lg-zoom-dragging');
// Fix for chrome mouse move on click
if (isMoved &&
(startCoords.x !== endCoords.x ||
startCoords.y !== endCoords.y)) {
endCoords = _this.getDragCords(e);
var touchDuration = endTime.valueOf() - startTime.valueOf();
_this.touchendZoom(startCoords, endCoords, allowX, allowY, touchDuration);
}
isMoved = false;
}
_this.core.outer.removeClass('lg-grabbing').addClass('lg-grab');
});
};
Zoom.prototype.closeGallery = function () {
this.resetZoom();
this.zoomInProgress = false;
};
Zoom.prototype.destroy = function () {
// Unbind all events added by lightGallery zoom plugin
this.$LG(window).off(".lg.zoom.global" + this.core.lgId);
this.core.LGel.off('.lg.zoom');
this.core.LGel.off('.zoom');
clearTimeout(this.zoomableTimeout);
this.zoomableTimeout = false;
};
return Zoom;
}());
export default Zoom;
//# sourceMappingURL=lg-zoom.es5.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,988 @@
/*!
* lightgallery | 2.9.0 | October 1st 2025
* http://www.lightgalleryjs.com/
* Copyright (c) 2020 Sachin Neravath;
* @license GPLv3
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgZoom = factory());
}(this, (function () { 'use strict';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
var __assign = function() {
__assign = Object.assign || function __assign(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);
};
var zoomSettings = {
scale: 1,
zoom: true,
infiniteZoom: true,
actualSize: true,
showZoomInOutIcons: false,
actualSizeIcons: {
zoomIn: 'lg-zoom-in',
zoomOut: 'lg-zoom-out',
},
enableZoomAfter: 300,
zoomPluginStrings: {
zoomIn: 'Zoom in',
zoomOut: 'Zoom out',
viewActualSize: 'View actual size',
},
};
/**
* List of lightGallery events
* All events should be documented here
* Below interfaces are used to build the website documentations
* */
var lGEvents = {
afterAppendSlide: 'lgAfterAppendSlide',
init: 'lgInit',
hasVideo: 'lgHasVideo',
containerResize: 'lgContainerResize',
updateSlides: 'lgUpdateSlides',
afterAppendSubHtml: 'lgAfterAppendSubHtml',
beforeOpen: 'lgBeforeOpen',
afterOpen: 'lgAfterOpen',
slideItemLoad: 'lgSlideItemLoad',
beforeSlide: 'lgBeforeSlide',
afterSlide: 'lgAfterSlide',
posterClick: 'lgPosterClick',
dragStart: 'lgDragStart',
dragMove: 'lgDragMove',
dragEnd: 'lgDragEnd',
beforeNextSlide: 'lgBeforeNextSlide',
beforePrevSlide: 'lgBeforePrevSlide',
beforeClose: 'lgBeforeClose',
afterClose: 'lgAfterClose',
rotateLeft: 'lgRotateLeft',
rotateRight: 'lgRotateRight',
flipHorizontal: 'lgFlipHorizontal',
flipVertical: 'lgFlipVertical',
autoplay: 'lgAutoplay',
autoplayStart: 'lgAutoplayStart',
autoplayStop: 'lgAutoplayStop',
};
var ZOOM_TRANSITION_DURATION = 500;
var Zoom = /** @class */ (function () {
function Zoom(instance, $LG) {
// get lightGallery core plugin instance
this.core = instance;
this.$LG = $LG;
this.settings = __assign(__assign({}, zoomSettings), this.core.settings);
return this;
}
// Append Zoom controls. Actual size, Zoom-in, Zoom-out
Zoom.prototype.buildTemplates = function () {
var zoomIcons = this.settings.showZoomInOutIcons
? "<button id=\"" + this.core.getIdName('lg-zoom-in') + "\" type=\"button\" aria-label=\"" + this.settings.zoomPluginStrings['zoomIn'] + "\" class=\"lg-zoom-in lg-icon\"></button><button id=\"" + this.core.getIdName('lg-zoom-out') + "\" type=\"button\" aria-label=\"" + this.settings.zoomPluginStrings['zoomOut'] + "\" class=\"lg-zoom-out lg-icon\"></button>"
: '';
if (this.settings.actualSize) {
zoomIcons += "<button id=\"" + this.core.getIdName('lg-actual-size') + "\" type=\"button\" aria-label=\"" + this.settings.zoomPluginStrings['viewActualSize'] + "\" class=\"" + this.settings.actualSizeIcons.zoomIn + " lg-icon\"></button>";
}
this.core.outer.addClass('lg-use-transition-for-zoom');
this.core.$toolbar.first().append(zoomIcons);
};
/**
* @desc Enable zoom option only once the image is completely loaded
* If zoomFromOrigin is true, Zoom is enabled once the dummy image has been inserted
*
* Zoom styles are defined under lg-zoomable CSS class.
*/
Zoom.prototype.enableZoom = function (event) {
var _this = this;
// delay will be 0 except first time
var _speed = this.settings.enableZoomAfter + event.detail.delay;
// set _speed value 0 if gallery opened from direct url and if it is first slide
if (this.$LG('body').first().hasClass('lg-from-hash') &&
event.detail.delay) {
// will execute only once
_speed = 0;
}
else {
// Remove lg-from-hash to enable starting animation.
this.$LG('body').first().removeClass('lg-from-hash');
}
this.zoomableTimeout = setTimeout(function () {
if (!_this.isImageSlide(_this.core.index)) {
return;
}
_this.core.getSlideItem(event.detail.index).addClass('lg-zoomable');
if (event.detail.index === _this.core.index) {
_this.setZoomEssentials();
}
}, _speed + 30);
};
Zoom.prototype.enableZoomOnSlideItemLoad = function () {
// Add zoomable class
this.core.LGel.on(lGEvents.slideItemLoad + ".zoom", this.enableZoom.bind(this));
};
Zoom.prototype.getDragCords = function (e) {
return {
x: e.pageX,
y: e.pageY,
};
};
Zoom.prototype.getSwipeCords = function (e) {
var x = e.touches[0].pageX;
var y = e.touches[0].pageY;
return {
x: x,
y: y,
};
};
Zoom.prototype.getDragAllowedAxises = function (scale, scaleDiff) {
if (!this.containerRect) {
return {
allowX: false,
allowY: false,
};
}
var $image = this.core
.getSlideItem(this.core.index)
.find('.lg-image')
.first()
.get();
var height = 0;
var width = 0;
var rect = $image.getBoundingClientRect();
if (scale) {
height = $image.offsetHeight * scale;
width = $image.offsetWidth * scale;
}
else if (scaleDiff) {
height = rect.height + scaleDiff * rect.height;
width = rect.width + scaleDiff * rect.width;
}
else {
height = rect.height;
width = rect.width;
}
var allowY = height > this.containerRect.height;
var allowX = width > this.containerRect.width;
return {
allowX: allowX,
allowY: allowY,
};
};
Zoom.prototype.setZoomEssentials = function () {
this.containerRect = this.core.$content.get().getBoundingClientRect();
};
/**
* @desc Image zoom
* Translate the wrap and scale the image to get better user experience
*
* @param {String} scale - Zoom decrement/increment value
*/
Zoom.prototype.zoomImage = function (scale, scaleDiff, reposition, resetToMax) {
if (!this.containerRect || Math.abs(scaleDiff) <= 0)
return;
var offsetX = this.containerRect.width / 2 + this.containerRect.left;
var offsetY = this.containerRect.height / 2 +
this.containerRect.top +
this.scrollTop;
var originalX;
var originalY;
if (scale === 1) {
this.positionChanged = false;
}
var dragAllowedAxises = this.getDragAllowedAxises(0, scaleDiff);
var allowY = dragAllowedAxises.allowY, allowX = dragAllowedAxises.allowX;
if (this.positionChanged) {
originalX = this.left / (this.scale - scaleDiff);
originalY = this.top / (this.scale - scaleDiff);
this.pageX = offsetX - originalX;
this.pageY = offsetY - originalY;
this.positionChanged = false;
}
var possibleSwipeCords = this.getPossibleSwipeDragCords(scaleDiff);
var x;
var y;
var _x = offsetX - this.pageX;
var _y = offsetY - this.pageY;
if (scale - scaleDiff > 1) {
var scaleVal = (scale - scaleDiff) / Math.abs(scaleDiff);
_x =
(scaleDiff < 0 ? -_x : _x) +
this.left * (scaleVal + (scaleDiff < 0 ? -1 : 1));
_y =
(scaleDiff < 0 ? -_y : _y) +
this.top * (scaleVal + (scaleDiff < 0 ? -1 : 1));
x = _x / scaleVal;
y = _y / scaleVal;
}
else {
var scaleVal = (scale - scaleDiff) * scaleDiff;
x = _x * scaleVal;
y = _y * scaleVal;
}
if (reposition) {
if (allowX) {
if (this.isBeyondPossibleLeft(x, possibleSwipeCords.minX)) {
x = possibleSwipeCords.minX;
}
else if (this.isBeyondPossibleRight(x, possibleSwipeCords.maxX)) {
x = possibleSwipeCords.maxX;
}
}
else {
if (scale > 1) {
if (x < possibleSwipeCords.minX) {
x = possibleSwipeCords.minX;
}
else if (x > possibleSwipeCords.maxX) {
x = possibleSwipeCords.maxX;
}
}
}
// @todo fix this
if (allowY) {
if (this.isBeyondPossibleTop(y, possibleSwipeCords.minY)) {
y = possibleSwipeCords.minY;
}
else if (this.isBeyondPossibleBottom(y, possibleSwipeCords.maxY)) {
y = possibleSwipeCords.maxY;
}
}
else {
// If the translate value based on index of beyond the viewport, utilize the available space to prevent image being cut out
if (scale > 1) {
//If image goes beyond viewport top, use the minim possible translate value
if (y < possibleSwipeCords.minY) {
y = possibleSwipeCords.minY;
}
else if (y > possibleSwipeCords.maxY) {
y = possibleSwipeCords.maxY;
}
}
}
}
this.setZoomStyles({
x: x,
y: y,
scale: scale,
});
this.left = x;
this.top = y;
if (resetToMax) {
this.setZoomImageSize();
}
};
Zoom.prototype.resetImageTranslate = function (index) {
if (!this.isImageSlide(index)) {
return;
}
var $image = this.core.getSlideItem(index).find('.lg-image').first();
this.imageReset = false;
$image.removeClass('reset-transition reset-transition-y reset-transition-x');
this.core.outer.removeClass('lg-actual-size');
$image.css('width', 'auto').css('height', 'auto');
setTimeout(function () {
$image.removeClass('no-transition');
}, 10);
};
Zoom.prototype.setZoomImageSize = function () {
var _this = this;
var $image = this.core
.getSlideItem(this.core.index)
.find('.lg-image')
.first();
setTimeout(function () {
var actualSizeScale = _this.getCurrentImageActualSizeScale();
if (_this.scale >= actualSizeScale) {
$image.addClass('no-transition');
_this.imageReset = true;
}
}, ZOOM_TRANSITION_DURATION);
setTimeout(function () {
var actualSizeScale = _this.getCurrentImageActualSizeScale();
if (_this.scale >= actualSizeScale) {
var dragAllowedAxises = _this.getDragAllowedAxises(_this.scale);
$image
.css('width', $image.get().naturalWidth + 'px')
.css('height', $image.get().naturalHeight + 'px');
_this.core.outer.addClass('lg-actual-size');
if (dragAllowedAxises.allowX && dragAllowedAxises.allowY) {
$image.addClass('reset-transition');
}
else if (dragAllowedAxises.allowX &&
!dragAllowedAxises.allowY) {
$image.addClass('reset-transition-x');
}
else if (!dragAllowedAxises.allowX &&
dragAllowedAxises.allowY) {
$image.addClass('reset-transition-y');
}
}
}, ZOOM_TRANSITION_DURATION + 50);
};
/**
* @desc apply scale3d to image and translate to image wrap
* @param {style} X,Y and scale
*/
Zoom.prototype.setZoomStyles = function (style) {
var $imageWrap = this.core
.getSlideItem(this.core.index)
.find('.lg-img-wrap')
.first();
var $image = this.core
.getSlideItem(this.core.index)
.find('.lg-image')
.first();
var $dummyImage = this.core.outer
.find('.lg-current .lg-dummy-img')
.first();
this.scale = style.scale;
$image.css('transform', 'scale3d(' + style.scale + ', ' + style.scale + ', 1)');
$dummyImage.css('transform', 'scale3d(' + style.scale + ', ' + style.scale + ', 1)');
var transform = 'translate3d(' + style.x + 'px, ' + style.y + 'px, 0)';
$imageWrap.css('transform', transform);
};
/**
* @param index - Index of the current slide
* @param event - event will be available only if the function is called on clicking/taping the imags
*/
Zoom.prototype.setActualSize = function (index, event) {
var _this = this;
if (this.zoomInProgress) {
return;
}
this.zoomInProgress = true;
var currentItem = this.core.galleryItems[this.core.index];
this.resetImageTranslate(index);
setTimeout(function () {
// Allow zoom only on image
if (!currentItem.src ||
_this.core.outer.hasClass('lg-first-slide-loading')) {
return;
}
var scale = _this.getCurrentImageActualSizeScale();
var prevScale = _this.scale;
if (_this.core.outer.hasClass('lg-zoomed')) {
_this.scale = 1;
}
else {
_this.scale = _this.getScale(scale);
}
_this.setPageCords(event);
_this.beginZoom(_this.scale);
_this.zoomImage(_this.scale, _this.scale - prevScale, true, true);
}, 50);
setTimeout(function () {
_this.core.outer.removeClass('lg-grabbing').addClass('lg-grab');
}, 60);
setTimeout(function () {
_this.zoomInProgress = false;
}, ZOOM_TRANSITION_DURATION + 110);
};
Zoom.prototype.getNaturalWidth = function (index) {
var $image = this.core.getSlideItem(index).find('.lg-image').first();
var naturalWidth = this.core.galleryItems[index].width;
return naturalWidth
? parseFloat(naturalWidth)
: $image.get().naturalWidth;
};
Zoom.prototype.getActualSizeScale = function (naturalWidth, width) {
var _scale;
var scale;
if (naturalWidth >= width) {
_scale = naturalWidth / width;
scale = _scale || 2;
}
else {
scale = 1;
}
return scale;
};
Zoom.prototype.getCurrentImageActualSizeScale = function () {
var $image = this.core
.getSlideItem(this.core.index)
.find('.lg-image')
.first();
var width = $image.get().offsetWidth;
var naturalWidth = this.getNaturalWidth(this.core.index) || width;
return this.getActualSizeScale(naturalWidth, width);
};
Zoom.prototype.getPageCords = function (event) {
var cords = {};
if (event) {
cords.x = event.pageX || event.touches[0].pageX;
cords.y = event.pageY || event.touches[0].pageY;
}
else {
var containerRect = this.core.$content
.get()
.getBoundingClientRect();
cords.x = containerRect.width / 2 + containerRect.left;
cords.y =
containerRect.height / 2 + this.scrollTop + containerRect.top;
}
return cords;
};
Zoom.prototype.setPageCords = function (event) {
var pageCords = this.getPageCords(event);
this.pageX = pageCords.x;
this.pageY = pageCords.y;
};
Zoom.prototype.manageActualPixelClassNames = function () {
var $actualSize = this.core.getElementById('lg-actual-size');
$actualSize
.removeClass(this.settings.actualSizeIcons.zoomIn)
.addClass(this.settings.actualSizeIcons.zoomOut);
};
// If true, zoomed - in else zoomed out
Zoom.prototype.beginZoom = function (scale) {
this.core.outer.removeClass('lg-zoom-drag-transition lg-zoom-dragging');
if (scale > 1) {
this.core.outer.addClass('lg-zoomed');
this.manageActualPixelClassNames();
}
else {
this.resetZoom();
}
return scale > 1;
};
Zoom.prototype.getScale = function (scale) {
var actualSizeScale = this.getCurrentImageActualSizeScale();
if (scale < 1) {
scale = 1;
}
else if (scale > actualSizeScale) {
scale = actualSizeScale;
}
return scale;
};
Zoom.prototype.init = function () {
var _this = this;
if (!this.settings.zoom) {
return;
}
this.buildTemplates();
this.enableZoomOnSlideItemLoad();
var tapped = null;
this.core.outer.on('dblclick.lg', function (event) {
if (!_this.$LG(event.target).hasClass('lg-image')) {
return;
}
_this.setActualSize(_this.core.index, event);
});
this.core.outer.on('touchstart.lg', function (event) {
var $target = _this.$LG(event.target);
if (event.touches.length === 1 && $target.hasClass('lg-image')) {
if (!tapped) {
tapped = setTimeout(function () {
tapped = null;
}, 300);
}
else {
clearTimeout(tapped);
tapped = null;
event.preventDefault();
_this.setActualSize(_this.core.index, event);
}
}
});
this.core.LGel.on(lGEvents.containerResize + ".zoom " + lGEvents.rotateRight + ".zoom " + lGEvents.rotateLeft + ".zoom " + lGEvents.flipHorizontal + ".zoom " + lGEvents.flipVertical + ".zoom", function () {
if (!_this.core.lgOpened ||
!_this.isImageSlide(_this.core.index) ||
_this.core.touchAction) {
return;
}
var _LGel = _this.core
.getSlideItem(_this.core.index)
.find('.lg-img-wrap')
.first();
_this.top = 0;
_this.left = 0;
_this.setZoomEssentials();
_this.setZoomSwipeStyles(_LGel, { x: 0, y: 0 });
_this.positionChanged = true;
});
// Update zoom on resize and orientationchange
this.$LG(window).on("scroll.lg.zoom.global" + this.core.lgId, function () {
if (!_this.core.lgOpened)
return;
_this.scrollTop = _this.$LG(window).scrollTop();
});
this.core.getElementById('lg-zoom-out').on('click.lg', function () {
// Allow zoom only on image
if (!_this.isImageSlide(_this.core.index)) {
return;
}
var timeout = 0;
if (_this.imageReset) {
_this.resetImageTranslate(_this.core.index);
timeout = 50;
}
setTimeout(function () {
var scale = _this.scale - _this.settings.scale;
if (scale < 1) {
scale = 1;
}
_this.beginZoom(scale);
_this.zoomImage(scale, -_this.settings.scale, true, !_this.settings.infiniteZoom);
}, timeout);
});
this.core.getElementById('lg-zoom-in').on('click.lg', function () {
_this.zoomIn();
});
this.core.getElementById('lg-actual-size').on('click.lg', function () {
_this.setActualSize(_this.core.index);
});
this.core.LGel.on(lGEvents.beforeOpen + ".zoom", function () {
_this.core.outer.find('.lg-item').removeClass('lg-zoomable');
});
this.core.LGel.on(lGEvents.afterOpen + ".zoom", function () {
_this.scrollTop = _this.$LG(window).scrollTop();
// Set the initial value center
_this.pageX = _this.core.outer.width() / 2;
_this.pageY = _this.core.outer.height() / 2 + _this.scrollTop;
_this.scale = 1;
});
// Reset zoom on slide change
this.core.LGel.on(lGEvents.afterSlide + ".zoom", function (event) {
var prevIndex = event.detail.prevIndex;
_this.scale = 1;
_this.positionChanged = false;
_this.zoomInProgress = false;
_this.resetZoom(prevIndex);
_this.resetImageTranslate(prevIndex);
if (_this.isImageSlide(_this.core.index)) {
_this.setZoomEssentials();
}
});
// Drag option after zoom
this.zoomDrag();
this.pinchZoom();
this.zoomSwipe();
// Store the zoomable timeout value just to clear it while closing
this.zoomableTimeout = false;
this.positionChanged = false;
this.zoomInProgress = false;
};
Zoom.prototype.zoomIn = function () {
// Allow zoom only on image
if (!this.isImageSlide(this.core.index)) {
return;
}
var scale = this.scale + this.settings.scale;
if (!this.settings.infiniteZoom) {
scale = this.getScale(scale);
}
this.beginZoom(scale);
this.zoomImage(scale, Math.min(this.settings.scale, scale - this.scale), true, !this.settings.infiniteZoom);
};
// Reset zoom effect
Zoom.prototype.resetZoom = function (index) {
this.core.outer.removeClass('lg-zoomed lg-zoom-drag-transition');
var $actualSize = this.core.getElementById('lg-actual-size');
var $item = this.core.getSlideItem(index !== undefined ? index : this.core.index);
$actualSize
.removeClass(this.settings.actualSizeIcons.zoomOut)
.addClass(this.settings.actualSizeIcons.zoomIn);
$item.find('.lg-img-wrap').first().removeAttr('style');
$item.find('.lg-image').first().removeAttr('style');
this.scale = 1;
this.left = 0;
this.top = 0;
// Reset pagx pagy values to center
this.setPageCords();
};
Zoom.prototype.getTouchDistance = function (e) {
return Math.sqrt((e.touches[0].pageX - e.touches[1].pageX) *
(e.touches[0].pageX - e.touches[1].pageX) +
(e.touches[0].pageY - e.touches[1].pageY) *
(e.touches[0].pageY - e.touches[1].pageY));
};
Zoom.prototype.pinchZoom = function () {
var _this = this;
var startDist = 0;
var pinchStarted = false;
var initScale = 1;
var prevScale = 0;
var $item = this.core.getSlideItem(this.core.index);
this.core.outer.on('touchstart.lg', function (e) {
$item = _this.core.getSlideItem(_this.core.index);
if (!_this.isImageSlide(_this.core.index)) {
return;
}
if (e.touches.length === 2) {
e.preventDefault();
if (_this.core.outer.hasClass('lg-first-slide-loading')) {
return;
}
initScale = _this.scale || 1;
_this.core.outer.removeClass('lg-zoom-drag-transition lg-zoom-dragging');
_this.setPageCords(e);
_this.resetImageTranslate(_this.core.index);
_this.core.touchAction = 'pinch';
startDist = _this.getTouchDistance(e);
}
});
this.core.$inner.on('touchmove.lg', function (e) {
if (e.touches.length === 2 &&
_this.core.touchAction === 'pinch' &&
(_this.$LG(e.target).hasClass('lg-item') ||
$item.get().contains(e.target))) {
e.preventDefault();
var endDist = _this.getTouchDistance(e);
var distance = startDist - endDist;
if (!pinchStarted && Math.abs(distance) > 5) {
pinchStarted = true;
}
if (pinchStarted) {
prevScale = _this.scale;
var _scale = Math.max(1, initScale + -distance * 0.02);
_this.scale =
Math.round((_scale + Number.EPSILON) * 100) / 100;
var diff = _this.scale - prevScale;
_this.zoomImage(_this.scale, Math.round((diff + Number.EPSILON) * 100) / 100, false, false);
}
}
});
this.core.$inner.on('touchend.lg', function (e) {
if (_this.core.touchAction === 'pinch' &&
(_this.$LG(e.target).hasClass('lg-item') ||
$item.get().contains(e.target))) {
pinchStarted = false;
startDist = 0;
if (_this.scale <= 1) {
_this.resetZoom();
}
else {
var actualSizeScale = _this.getCurrentImageActualSizeScale();
if (_this.scale >= actualSizeScale) {
var scaleDiff = actualSizeScale - _this.scale;
if (scaleDiff === 0) {
scaleDiff = 0.01;
}
_this.zoomImage(actualSizeScale, scaleDiff, false, true);
}
_this.manageActualPixelClassNames();
_this.core.outer.addClass('lg-zoomed');
}
_this.core.touchAction = undefined;
}
});
};
Zoom.prototype.touchendZoom = function (startCoords, endCoords, allowX, allowY, touchDuration) {
var distanceXnew = endCoords.x - startCoords.x;
var distanceYnew = endCoords.y - startCoords.y;
var speedX = Math.abs(distanceXnew) / touchDuration + 1;
var speedY = Math.abs(distanceYnew) / touchDuration + 1;
if (speedX > 2) {
speedX += 1;
}
if (speedY > 2) {
speedY += 1;
}
distanceXnew = distanceXnew * speedX;
distanceYnew = distanceYnew * speedY;
var _LGel = this.core
.getSlideItem(this.core.index)
.find('.lg-img-wrap')
.first();
var distance = {};
distance.x = this.left + distanceXnew;
distance.y = this.top + distanceYnew;
var possibleSwipeCords = this.getPossibleSwipeDragCords();
if (Math.abs(distanceXnew) > 15 || Math.abs(distanceYnew) > 15) {
if (allowY) {
if (this.isBeyondPossibleTop(distance.y, possibleSwipeCords.minY)) {
distance.y = possibleSwipeCords.minY;
}
else if (this.isBeyondPossibleBottom(distance.y, possibleSwipeCords.maxY)) {
distance.y = possibleSwipeCords.maxY;
}
}
if (allowX) {
if (this.isBeyondPossibleLeft(distance.x, possibleSwipeCords.minX)) {
distance.x = possibleSwipeCords.minX;
}
else if (this.isBeyondPossibleRight(distance.x, possibleSwipeCords.maxX)) {
distance.x = possibleSwipeCords.maxX;
}
}
if (allowY) {
this.top = distance.y;
}
else {
distance.y = this.top;
}
if (allowX) {
this.left = distance.x;
}
else {
distance.x = this.left;
}
this.setZoomSwipeStyles(_LGel, distance);
this.positionChanged = true;
}
};
Zoom.prototype.getZoomSwipeCords = function (startCoords, endCoords, allowX, allowY, possibleSwipeCords) {
var distance = {};
if (allowY) {
distance.y = this.top + (endCoords.y - startCoords.y);
if (this.isBeyondPossibleTop(distance.y, possibleSwipeCords.minY)) {
var diffMinY = possibleSwipeCords.minY - distance.y;
distance.y = possibleSwipeCords.minY - diffMinY / 6;
}
else if (this.isBeyondPossibleBottom(distance.y, possibleSwipeCords.maxY)) {
var diffMaxY = distance.y - possibleSwipeCords.maxY;
distance.y = possibleSwipeCords.maxY + diffMaxY / 6;
}
}
else {
distance.y = this.top;
}
if (allowX) {
distance.x = this.left + (endCoords.x - startCoords.x);
if (this.isBeyondPossibleLeft(distance.x, possibleSwipeCords.minX)) {
var diffMinX = possibleSwipeCords.minX - distance.x;
distance.x = possibleSwipeCords.minX - diffMinX / 6;
}
else if (this.isBeyondPossibleRight(distance.x, possibleSwipeCords.maxX)) {
var difMaxX = distance.x - possibleSwipeCords.maxX;
distance.x = possibleSwipeCords.maxX + difMaxX / 6;
}
}
else {
distance.x = this.left;
}
return distance;
};
Zoom.prototype.isBeyondPossibleLeft = function (x, minX) {
return x >= minX;
};
Zoom.prototype.isBeyondPossibleRight = function (x, maxX) {
return x <= maxX;
};
Zoom.prototype.isBeyondPossibleTop = function (y, minY) {
return y >= minY;
};
Zoom.prototype.isBeyondPossibleBottom = function (y, maxY) {
return y <= maxY;
};
Zoom.prototype.isImageSlide = function (index) {
var currentItem = this.core.galleryItems[index];
return this.core.getSlideType(currentItem) === 'image';
};
Zoom.prototype.getPossibleSwipeDragCords = function (scale) {
var $image = this.core
.getSlideItem(this.core.index)
.find('.lg-image')
.first();
var bottom = this.core.mediaContainerPosition.bottom;
var imgRect = $image.get().getBoundingClientRect();
var imageHeight = imgRect.height;
var imageWidth = imgRect.width;
if (scale) {
imageHeight = imageHeight + scale * imageHeight;
imageWidth = imageWidth + scale * imageWidth;
}
var minY = (imageHeight - this.containerRect.height) / 2;
var maxY = (this.containerRect.height - imageHeight) / 2 + bottom;
var minX = (imageWidth - this.containerRect.width) / 2;
var maxX = (this.containerRect.width - imageWidth) / 2;
var possibleSwipeCords = {
minY: minY,
maxY: maxY,
minX: minX,
maxX: maxX,
};
return possibleSwipeCords;
};
Zoom.prototype.setZoomSwipeStyles = function (LGel, distance) {
LGel.css('transform', 'translate3d(' + distance.x + 'px, ' + distance.y + 'px, 0)');
};
Zoom.prototype.zoomSwipe = function () {
var _this = this;
var startCoords = {};
var endCoords = {};
var isMoved = false;
// Allow x direction drag
var allowX = false;
// Allow Y direction drag
var allowY = false;
var startTime = new Date();
var endTime = new Date();
var possibleSwipeCords;
var _LGel;
var $item = this.core.getSlideItem(this.core.index);
this.core.$inner.on('touchstart.lg', function (e) {
// Allow zoom only on image
if (!_this.isImageSlide(_this.core.index)) {
return;
}
$item = _this.core.getSlideItem(_this.core.index);
if ((_this.$LG(e.target).hasClass('lg-item') ||
$item.get().contains(e.target)) &&
e.touches.length === 1 &&
_this.core.outer.hasClass('lg-zoomed')) {
e.preventDefault();
startTime = new Date();
_this.core.touchAction = 'zoomSwipe';
_LGel = _this.core
.getSlideItem(_this.core.index)
.find('.lg-img-wrap')
.first();
var dragAllowedAxises = _this.getDragAllowedAxises(0);
allowY = dragAllowedAxises.allowY;
allowX = dragAllowedAxises.allowX;
if (allowX || allowY) {
startCoords = _this.getSwipeCords(e);
}
possibleSwipeCords = _this.getPossibleSwipeDragCords();
// reset opacity and transition duration
_this.core.outer.addClass('lg-zoom-dragging lg-zoom-drag-transition');
}
});
this.core.$inner.on('touchmove.lg', function (e) {
if (e.touches.length === 1 &&
_this.core.touchAction === 'zoomSwipe' &&
(_this.$LG(e.target).hasClass('lg-item') ||
$item.get().contains(e.target))) {
e.preventDefault();
_this.core.touchAction = 'zoomSwipe';
endCoords = _this.getSwipeCords(e);
var distance = _this.getZoomSwipeCords(startCoords, endCoords, allowX, allowY, possibleSwipeCords);
if (Math.abs(endCoords.x - startCoords.x) > 15 ||
Math.abs(endCoords.y - startCoords.y) > 15) {
isMoved = true;
_this.setZoomSwipeStyles(_LGel, distance);
}
}
});
this.core.$inner.on('touchend.lg', function (e) {
if (_this.core.touchAction === 'zoomSwipe' &&
(_this.$LG(e.target).hasClass('lg-item') ||
$item.get().contains(e.target))) {
e.preventDefault();
_this.core.touchAction = undefined;
_this.core.outer.removeClass('lg-zoom-dragging');
if (!isMoved) {
return;
}
isMoved = false;
endTime = new Date();
var touchDuration = endTime.valueOf() - startTime.valueOf();
_this.touchendZoom(startCoords, endCoords, allowX, allowY, touchDuration);
}
});
};
Zoom.prototype.zoomDrag = function () {
var _this = this;
var startCoords = {};
var endCoords = {};
var isDragging = false;
var isMoved = false;
// Allow x direction drag
var allowX = false;
// Allow Y direction drag
var allowY = false;
var startTime;
var endTime;
var possibleSwipeCords;
var _LGel;
this.core.outer.on('mousedown.lg.zoom', function (e) {
// Allow zoom only on image
if (!_this.isImageSlide(_this.core.index)) {
return;
}
var $item = _this.core.getSlideItem(_this.core.index);
if (_this.$LG(e.target).hasClass('lg-item') ||
$item.get().contains(e.target)) {
startTime = new Date();
_LGel = _this.core
.getSlideItem(_this.core.index)
.find('.lg-img-wrap')
.first();
var dragAllowedAxises = _this.getDragAllowedAxises(0);
allowY = dragAllowedAxises.allowY;
allowX = dragAllowedAxises.allowX;
if (_this.core.outer.hasClass('lg-zoomed')) {
if (_this.$LG(e.target).hasClass('lg-object') &&
(allowX || allowY)) {
e.preventDefault();
startCoords = _this.getDragCords(e);
possibleSwipeCords = _this.getPossibleSwipeDragCords();
isDragging = true;
_this.core.outer
.removeClass('lg-grab')
.addClass('lg-grabbing lg-zoom-drag-transition lg-zoom-dragging');
// reset opacity and transition duration
}
}
}
});
this.$LG(window).on("mousemove.lg.zoom.global" + this.core.lgId, function (e) {
if (isDragging) {
isMoved = true;
endCoords = _this.getDragCords(e);
var distance = _this.getZoomSwipeCords(startCoords, endCoords, allowX, allowY, possibleSwipeCords);
_this.setZoomSwipeStyles(_LGel, distance);
}
});
this.$LG(window).on("mouseup.lg.zoom.global" + this.core.lgId, function (e) {
if (isDragging) {
endTime = new Date();
isDragging = false;
_this.core.outer.removeClass('lg-zoom-dragging');
// Fix for chrome mouse move on click
if (isMoved &&
(startCoords.x !== endCoords.x ||
startCoords.y !== endCoords.y)) {
endCoords = _this.getDragCords(e);
var touchDuration = endTime.valueOf() - startTime.valueOf();
_this.touchendZoom(startCoords, endCoords, allowX, allowY, touchDuration);
}
isMoved = false;
}
_this.core.outer.removeClass('lg-grabbing').addClass('lg-grab');
});
};
Zoom.prototype.closeGallery = function () {
this.resetZoom();
this.zoomInProgress = false;
};
Zoom.prototype.destroy = function () {
// Unbind all events added by lightGallery zoom plugin
this.$LG(window).off(".lg.zoom.global" + this.core.lgId);
this.core.LGel.off('.lg.zoom');
this.core.LGel.off('.zoom');
clearTimeout(this.zoomableTimeout);
this.zoomableTimeout = false;
};
return Zoom;
}());
return Zoom;
})));
//# sourceMappingURL=lg-zoom.umd.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
{
"name": "lightgallery/plugins/zoom",
"private": true,
"main": "lg-zoom.umd.js",
"module": "lg-zoom.es5.js",
"typings": "lg-zoom.d.ts"
}