/*! lg-zoom - v1.1.0 - 2017-08-08 * http://sachinchoolur.github.io/lightgallery * copyright (c) 2017 sachin n; licensed gplv3 */ (function (root, factory) { if (typeof define === 'function' && define.amd) { // amd. register as an anonymous module unless amdmoduleid is set define(['jquery'], function (a0) { return (factory(a0)); }); } else if (typeof exports === 'object') { // node. does not work with strict commonjs, but // only commonjs-like environments that support module.exports, // like node. module.exports = factory(require('jquery')); } else { factory(jquery); } }(this, function ($) { (function() { 'use strict'; var getuseleft = function() { var useleft = false; var ischrome = navigator.useragent.match(/chrom(e|ium)\/([0-9]+)\./); if (ischrome && parseint(ischrome[2], 10) < 54) { useleft = true; } return useleft; }; var defaults = { scale: 1, zoom: true, actualsize: true, enablezoomafter: 300, useleftforzoom: getuseleft() }; var zoom = function(element) { this.core = $(element).data('lightgallery'); this.core.s = $.extend({}, defaults, this.core.s); if (this.core.s.zoom && this.core.docss()) { this.init(); // store the zoomable timeout value just to clear it while closing this.zoomabletimeout = false; // set the initial value center this.pagex = $(window).width() / 2; this.pagey = ($(window).height() / 2) + $(window).scrolltop(); } return this; }; zoom.prototype.init = function() { var _this = this; var zoomicons = ''; if (_this.core.s.actualsize) { zoomicons += ''; } if (_this.core.s.useleftforzoom) { _this.core.$outer.addclass('lg-use-left-for-zoom'); } else { _this.core.$outer.addclass('lg-use-transition-for-zoom'); } this.core.$outer.find('.lg-toolbar').append(zoomicons); // add zoomable class _this.core.$el.on('onslideitemload.lg.tm.zoom', function(event, index, delay) { // delay will be 0 except first time var _speed = _this.core.s.enablezoomafter + delay; // set _speed value 0 if gallery opened from direct url and if it is first slide if ($('body').hasclass('lg-from-hash') && delay) { // will execute only once _speed = 0; } else { // remove lg-from-hash to enable starting animation. $('body').removeclass('lg-from-hash'); } _this.zoomabletimeout = settimeout(function() { _this.core.$slide.eq(index).addclass('lg-zoomable'); }, _speed + 30); }); var scale = 1; /** * @desc image zoom * translate the wrap and scale the image to get better user experience * * @param {string} scaleval - zoom decrement/increment value */ var zoom = function(scaleval) { var $image = _this.core.$outer.find('.lg-current .lg-image'); var _x; var _y; // find offset manually to avoid issue after zoom var offsetx = ($(window).width() - $image.prop('offsetwidth')) / 2; var offsety = (($(window).height() - $image.prop('offsetheight')) / 2) + $(window).scrolltop(); _x = _this.pagex - offsetx; _y = _this.pagey - offsety; var x = (scaleval - 1) * (_x); var y = (scaleval - 1) * (_y); $image.css('transform', 'scale3d(' + scaleval + ', ' + scaleval + ', 1)').attr('data-scale', scaleval); if (_this.core.s.useleftforzoom) { $image.parent().css({ left: -x + 'px', top: -y + 'px' }).attr('data-x', x).attr('data-y', y); } else { $image.parent().css('transform', 'translate3d(-' + x + 'px, -' + y + 'px, 0)').attr('data-x', x).attr('data-y', y); } }; var callscale = function() { if (scale > 1) { _this.core.$outer.addclass('lg-zoomed'); } else { _this.resetzoom(); } if (scale < 1) { scale = 1; } zoom(scale); }; var actualsize = function(event, $image, index, fromicon) { var w = $image.prop('offsetwidth'); var nw; if (_this.core.s.dynamic) { nw = _this.core.s.dynamicel[index].width || $image[0].naturalwidth || w; } else { nw = _this.core.$items.eq(index).attr('data-width') || $image[0].naturalwidth || w; } var _scale; if (_this.core.$outer.hasclass('lg-zoomed')) { scale = 1; } else { if (nw > w) { _scale = nw / w; scale = _scale || 2; } } if (fromicon) { _this.pagex = $(window).width() / 2; _this.pagey = ($(window).height() / 2) + $(window).scrolltop(); } else { _this.pagex = event.pagex || event.originalevent.targettouches[0].pagex; _this.pagey = event.pagey || event.originalevent.targettouches[0].pagey; } callscale(); settimeout(function() { _this.core.$outer.removeclass('lg-grabbing').addclass('lg-grab'); }, 10); }; var tapped = false; // event triggered after appending slide content _this.core.$el.on('onaferappendslide.lg.tm.zoom', function(event, index) { // get the current element var $image = _this.core.$slide.eq(index).find('.lg-image'); $image.on('dblclick', function(event) { actualsize(event, $image, index); }); $image.on('touchstart', function(event) { if (!tapped) { tapped = settimeout(function() { tapped = null; }, 300); } else { cleartimeout(tapped); tapped = null; actualsize(event, $image, index); } event.preventdefault(); }); }); // update zoom on resize and orientationchange $(window).on('resize.lg.zoom scroll.lg.zoom orientationchange.lg.zoom', function() { _this.pagex = $(window).width() / 2; _this.pagey = ($(window).height() / 2) + $(window).scrolltop(); zoom(scale); }); $('#lg-zoom-out').on('click.lg', function() { if (_this.core.$outer.find('.lg-current .lg-image').length) { scale -= _this.core.s.scale; callscale(); } }); $('#lg-zoom-in').on('click.lg', function() { if (_this.core.$outer.find('.lg-current .lg-image').length) { scale += _this.core.s.scale; callscale(); } }); $('#lg-actual-size').on('click.lg', function(event) { actualsize(event, _this.core.$slide.eq(_this.core.index).find('.lg-image'), _this.core.index, true); }); // reset zoom on slide change _this.core.$el.on('onbeforeslide.lg.tm', function() { scale = 1; _this.resetzoom(); }); // drag option after zoom _this.zoomdrag(); _this.zoomswipe(); }; // reset zoom effect zoom.prototype.resetzoom = function() { this.core.$outer.removeclass('lg-zoomed'); this.core.$slide.find('.lg-img-wrap').removeattr('style data-x data-y'); this.core.$slide.find('.lg-image').removeattr('style data-scale'); // reset pagx pagy values to center this.pagex = $(window).width() / 2; this.pagey = ($(window).height() / 2) + $(window).scrolltop(); }; 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; _this.core.$slide.on('touchstart.lg', function(e) { if (_this.core.$outer.hasclass('lg-zoomed')) { var $image = _this.core.$slide.eq(_this.core.index).find('.lg-object'); allowy = $image.prop('offsetheight') * $image.attr('data-scale') > _this.core.$outer.find('.lg').height(); allowx = $image.prop('offsetwidth') * $image.attr('data-scale') > _this.core.$outer.find('.lg').width(); if ((allowx || allowy)) { e.preventdefault(); startcoords = { x: e.originalevent.targettouches[0].pagex, y: e.originalevent.targettouches[0].pagey }; } } }); _this.core.$slide.on('touchmove.lg', function(e) { if (_this.core.$outer.hasclass('lg-zoomed')) { var _$el = _this.core.$slide.eq(_this.core.index).find('.lg-img-wrap'); var distancex; var distancey; e.preventdefault(); ismoved = true; endcoords = { x: e.originalevent.targettouches[0].pagex, y: e.originalevent.targettouches[0].pagey }; // reset opacity and transition duration _this.core.$outer.addclass('lg-zoom-dragging'); if (allowy) { distancey = (-math.abs(_$el.attr('data-y'))) + (endcoords.y - startcoords.y); } else { distancey = -math.abs(_$el.attr('data-y')); } if (allowx) { distancex = (-math.abs(_$el.attr('data-x'))) + (endcoords.x - startcoords.x); } else { distancex = -math.abs(_$el.attr('data-x')); } if ((math.abs(endcoords.x - startcoords.x) > 15) || (math.abs(endcoords.y - startcoords.y) > 15)) { if (_this.core.s.useleftforzoom) { _$el.css({ left: distancex + 'px', top: distancey + 'px' }); } else { _$el.css('transform', 'translate3d(' + distancex + 'px, ' + distancey + 'px, 0)'); } } } }); _this.core.$slide.on('touchend.lg', function() { if (_this.core.$outer.hasclass('lg-zoomed')) { if (ismoved) { ismoved = false; _this.core.$outer.removeclass('lg-zoom-dragging'); _this.touchendzoom(startcoords, endcoords, allowx, allowy); } } }); }; zoom.prototype.zoomdrag = function() { var _this = this; var startcoords = {}; var endcoords = {}; var isdraging = false; var ismoved = false; // allow x direction drag var allowx = false; // allow y direction drag var allowy = false; _this.core.$slide.on('mousedown.lg.zoom', function(e) { // execute only on .lg-object var $image = _this.core.$slide.eq(_this.core.index).find('.lg-object'); allowy = $image.prop('offsetheight') * $image.attr('data-scale') > _this.core.$outer.find('.lg').height(); allowx = $image.prop('offsetwidth') * $image.attr('data-scale') > _this.core.$outer.find('.lg').width(); if (_this.core.$outer.hasclass('lg-zoomed')) { if ($(e.target).hasclass('lg-object') && (allowx || allowy)) { e.preventdefault(); startcoords = { x: e.pagex, y: e.pagey }; isdraging = true; // ** fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723 _this.core.$outer.scrollleft += 1; _this.core.$outer.scrollleft -= 1; _this.core.$outer.removeclass('lg-grab').addclass('lg-grabbing'); } } }); $(window).on('mousemove.lg.zoom', function(e) { if (isdraging) { var _$el = _this.core.$slide.eq(_this.core.index).find('.lg-img-wrap'); var distancex; var distancey; ismoved = true; endcoords = { x: e.pagex, y: e.pagey }; // reset opacity and transition duration _this.core.$outer.addclass('lg-zoom-dragging'); if (allowy) { distancey = (-math.abs(_$el.attr('data-y'))) + (endcoords.y - startcoords.y); } else { distancey = -math.abs(_$el.attr('data-y')); } if (allowx) { distancex = (-math.abs(_$el.attr('data-x'))) + (endcoords.x - startcoords.x); } else { distancex = -math.abs(_$el.attr('data-x')); } if (_this.core.s.useleftforzoom) { _$el.css({ left: distancex + 'px', top: distancey + 'px' }); } else { _$el.css('transform', 'translate3d(' + distancex + 'px, ' + distancey + 'px, 0)'); } } }); $(window).on('mouseup.lg.zoom', function(e) { if (isdraging) { isdraging = 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 = { x: e.pagex, y: e.pagey }; _this.touchendzoom(startcoords, endcoords, allowx, allowy); } ismoved = false; } _this.core.$outer.removeclass('lg-grabbing').addclass('lg-grab'); }); }; zoom.prototype.touchendzoom = function(startcoords, endcoords, allowx, allowy) { var _this = this; var _$el = _this.core.$slide.eq(_this.core.index).find('.lg-img-wrap'); var $image = _this.core.$slide.eq(_this.core.index).find('.lg-object'); var distancex = (-math.abs(_$el.attr('data-x'))) + (endcoords.x - startcoords.x); var distancey = (-math.abs(_$el.attr('data-y'))) + (endcoords.y - startcoords.y); var miny = (_this.core.$outer.find('.lg').height() - $image.prop('offsetheight')) / 2; var maxy = math.abs(($image.prop('offsetheight') * math.abs($image.attr('data-scale'))) - _this.core.$outer.find('.lg').height() + miny); var minx = (_this.core.$outer.find('.lg').width() - $image.prop('offsetwidth')) / 2; var maxx = math.abs(($image.prop('offsetwidth') * math.abs($image.attr('data-scale'))) - _this.core.$outer.find('.lg').width() + minx); if ((math.abs(endcoords.x - startcoords.x) > 15) || (math.abs(endcoords.y - startcoords.y) > 15)) { if (allowy) { if (distancey <= -maxy) { distancey = -maxy; } else if (distancey >= -miny) { distancey = -miny; } } if (allowx) { if (distancex <= -maxx) { distancex = -maxx; } else if (distancex >= -minx) { distancex = -minx; } } if (allowy) { _$el.attr('data-y', math.abs(distancey)); } else { distancey = -math.abs(_$el.attr('data-y')); } if (allowx) { _$el.attr('data-x', math.abs(distancex)); } else { distancex = -math.abs(_$el.attr('data-x')); } if (_this.core.s.useleftforzoom) { _$el.css({ left: distancex + 'px', top: distancey + 'px' }); } else { _$el.css('transform', 'translate3d(' + distancex + 'px, ' + distancey + 'px, 0)'); } } }; zoom.prototype.destroy = function() { var _this = this; // unbind all events added by lightgallery zoom plugin _this.core.$el.off('.lg.zoom'); $(window).off('.lg.zoom'); _this.core.$slide.off('.lg.zoom'); _this.core.$el.off('.lg.tm.zoom'); _this.resetzoom(); cleartimeout(_this.zoomabletimeout); _this.zoomabletimeout = false; }; $.fn.lightgallery.modules.zoom = zoom; })(); }));