/*! lightgallery - v1.2.0 - 2015-08-26 * http://sachinchoolur.github.io/lightgallery/ * copyright (c) 2015 sachin n; licensed apache 2.0 */ /** * zoom plugin * @version 1.2.0 * @author sachin n - @sachinchoolur * @license mit license (mit) */ (function($, window, document, undefined) { 'use strict'; var defaults = { scale: 1, zoom: true, enablezoomafter: 300 }; 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(); this.zoomabletimeout = false; } return this; }; zoom.prototype.init = function() { var _this = this; var zoomicons = ''; 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 one time _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 * @param {boolean} db - true if zoom called via doubleclick * @todo currently zoom origin is center it should work from all the directions */ var zoom = function(scaleval, db, pagex, pagey) { var $image = _this.core.$outer.find('.lg-current .lg-image'); var _x; var _y; if (db) { _x = pagex - $image.offset().left; _y = pagey - $image.offset().top; } else { _x = $image.width() / 2; _y = $image.height() / 2; } var x = (scaleval - 1) * (_x); var y = (scaleval - 1) * (_y); $image.css('transform', 'scale3d(' + scaleval + ', ' + scaleval + ', 1)').attr('data-scale', scaleval); $image.parent().css('transform', 'translate3d(-' + x + 'px, -' + y + 'px, 0)').attr('data-x', x).attr('data-y', y); }; var callscale = function(db, pagex, pagey) { if (scale > 1) { _this.core.$outer.addclass('lg-zoomed'); } else { _this.core.$outer.removeclass('lg-zoomed'); } if (scale < 1) { scale = 1; } zoom(scale, db, pagex, pagey); }; // 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.dblclick(function(event) { var w = $image.width(); var 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; } } callscale(true, event.pagex, event.pagey); settimeout(function() { _this.core.$outer.removeclass('lg-grabbing').addclass('lg-grab'); }, 10); }); }); // update zoom on resize and orientationchange $(window).on('resize.lg.zoom orientationchange.lg.zoom', function() { settimeout(function() { if (_this.core.$outer.hasclass('lg-zoomed')) { zoom(scale); } }, 10); }); $('#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(); } }); // reset zoom on slide change _this.core.$el.on('onbeforeslide.lg.tm', function() { _this.resetzoom(); }); // drag option after zoom if (!_this.core.istouch) { _this.zoomdrag(); } if (_this.core.istouch) { _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'); }; 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.outerheight() * $image.attr('data-scale') > _this.core.$outer.find('.lg').height(); allowx = $image.outerwidth() * $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 = e.originalevent.targettouches[0].pagex; 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')); } _$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.outerheight() * $image.attr('data-scale') > _this.core.$outer.find('.lg').height(); allowx = $image.outerwidth() * $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')); } _$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.outerheight()) / 2; var maxy = math.abs(($image.outerheight() * math.abs($image.attr('data-scale'))) - _this.core.$outer.find('.lg').height() + miny); var minx = (_this.core.$outer.find('.lg').width() - $image.outerwidth()) / 2; var maxx = math.abs(($image.outerwidth() * math.abs($image.attr('data-scale'))) - _this.core.$outer.find('.lg').width() + minx); 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')); } _$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; })(jquery, window, document);