| 1 |
/** |
| 2 |
* VikFXGallery jQuery plugin. Forked from |
| 3 |
* the original project simplelightbox. |
| 4 |
* v. 0.12 |
| 5 |
*/ |
| 6 |
;(function($, window, document, undefined) |
| 7 |
{ |
| 8 |
'use strict'; |
| 9 |
$.fn.vikFxGallery = function(options) |
| 10 |
{ |
| 11 |
var options = $.extend({ |
| 12 |
sourceAttr: 'href', |
| 13 |
overlay: true, |
| 14 |
spinner: true, |
| 15 |
nav: true, |
| 16 |
navText: ['‹', '›'], |
| 17 |
captions: true, |
| 18 |
captionDelay: 0, |
| 19 |
captionSelector: 'img', |
| 20 |
captionType: 'attr', |
| 21 |
captionsData: 'title', |
| 22 |
captionPosition: 'bottom', |
| 23 |
captionClass: '', |
| 24 |
close: true, |
| 25 |
closeText: '×', |
| 26 |
swipeClose: true, |
| 27 |
showCounter: false, |
| 28 |
fileExt: 'png|jpg|jpeg|gif|webp', |
| 29 |
animationSlide: true, |
| 30 |
animationSpeed: 250, |
| 31 |
preloading: true, |
| 32 |
enableKeyboard: true, |
| 33 |
loop: true, |
| 34 |
rel: false, |
| 35 |
docClose: true, |
| 36 |
swipeTolerance: 50, |
| 37 |
widthRatio: 0.8, |
| 38 |
heightRatio: 0.9, |
| 39 |
scaleImageToRatio: false, |
| 40 |
disableRightClick: false, |
| 41 |
disableScroll: true, |
| 42 |
alertError: false, |
| 43 |
alertErrorMessage: 'Image not found', |
| 44 |
additionalHtml: false, |
| 45 |
history: true, |
| 46 |
throttleInterval: 0, |
| 47 |
doubleTapZoom: 2, |
| 48 |
maxZoom: 10, |
| 49 |
htmlClass: 'vikfxg-img-active' |
| 50 |
}, options); |
| 51 |
|
| 52 |
// global variables |
| 53 |
var touchDevice = ('ontouchstart' in window), |
| 54 |
pointerEnabled = window.navigator.pointerEnabled || window.navigator.msPointerEnabled, |
| 55 |
touched = function(event) { |
| 56 |
if (touchDevice) return true; |
| 57 |
if (!pointerEnabled || typeof event === 'undefined' || typeof event.pointerType === 'undefined') return false; |
| 58 |
if (typeof event.MSPOINTER_TYPE_MOUSE !== 'undefined') { |
| 59 |
if (event.MSPOINTER_TYPE_MOUSE != event.pointerType) return true; |
| 60 |
} |
| 61 |
else { |
| 62 |
if (event.pointerType != 'mouse') return true; |
| 63 |
} |
| 64 |
return false; |
| 65 |
}, |
| 66 |
swipeDiff = 0, |
| 67 |
swipeYDiff = 0, |
| 68 |
curImg = $(), |
| 69 |
transPrefix = function() { |
| 70 |
var s = document.body || document.documentElement; |
| 71 |
s = s.style; |
| 72 |
if (s.WebkitTransition === '') return '-webkit-'; |
| 73 |
if (s.MozTransition === '') return '-moz-'; |
| 74 |
if (s.OTransition === '') return '-o-'; |
| 75 |
if (s.transition === '') return ''; |
| 76 |
return false; |
| 77 |
}, |
| 78 |
opened = false, |
| 79 |
loaded = [], |
| 80 |
getRelated = function(rel, jqObj) { |
| 81 |
var $related = jqObj.filter(function () { |
| 82 |
return ($(this).attr('rel') === rel); |
| 83 |
}); |
| 84 |
return $related; |
| 85 |
}, |
| 86 |
objects = (options.rel && options.rel !== false) ? getRelated(options.rel, $(this)) : this, |
| 87 |
tagname = (objects.get()[0] ? objects.get()[0].tagName : null), |
| 88 |
transPrefix = transPrefix(), |
| 89 |
globalScrollbarwidth = 0, |
| 90 |
canTransisions = (transPrefix !== false) ? true : false, |
| 91 |
supportsPushState = ('pushState' in history), |
| 92 |
historyhasChanged = false, |
| 93 |
historyUpdateTimeout, |
| 94 |
winLoc = window.location, |
| 95 |
getHash = function() { |
| 96 |
return winLoc.hash.substring(1); |
| 97 |
}, |
| 98 |
initialHash = getHash(), |
| 99 |
updateHash = function() { |
| 100 |
var hash = getHash(), |
| 101 |
newHash = 'pid='+(index+1); |
| 102 |
var newURL = winLoc.href.split('#')[0] + '#' + newHash; |
| 103 |
|
| 104 |
if (supportsPushState) { |
| 105 |
history[historyhasChanged ? 'replaceState' : 'pushState']('', document.title, newURL); |
| 106 |
}else { |
| 107 |
if (historyhasChanged) { |
| 108 |
winLoc.replace(newURL); |
| 109 |
} else { |
| 110 |
winLoc.hash = newHash; |
| 111 |
} |
| 112 |
} |
| 113 |
historyhasChanged = true; |
| 114 |
}, |
| 115 |
resetHash = function() { |
| 116 |
if (supportsPushState) { |
| 117 |
history.pushState('', document.title, winLoc.pathname + winLoc.search); |
| 118 |
} else { |
| 119 |
winLoc.hash = ''; |
| 120 |
} |
| 121 |
clearTimeout(historyUpdateTimeout); |
| 122 |
|
| 123 |
}, |
| 124 |
updateURL = function() { |
| 125 |
if (!historyhasChanged) { |
| 126 |
updateHash(); // first time |
| 127 |
} else { |
| 128 |
historyUpdateTimeout = setTimeout(updateHash, 800); |
| 129 |
} |
| 130 |
}, |
| 131 |
throttle = function(func, limit) { |
| 132 |
var inThrottle; |
| 133 |
return function() { |
| 134 |
var args = arguments; |
| 135 |
var context = this; |
| 136 |
if (!inThrottle) { |
| 137 |
func.apply(context, args); |
| 138 |
inThrottle = true; |
| 139 |
setTimeout(function() { |
| 140 |
return inThrottle = false; |
| 141 |
}, limit); |
| 142 |
} |
| 143 |
}; |
| 144 |
}, |
| 145 |
prefix = 'vikfxgl', |
| 146 |
overlay = $('<div>').addClass('vikfxg-overlay'), |
| 147 |
closeBtn = $('<button>').addClass('vikfxg-close').html(options.closeText), |
| 148 |
spinner = $('<div>').addClass('vikfxg-spinner').html('<div></div>'), |
| 149 |
nav = $('<div>').addClass('vikfxg-navigation').html('<button class="vikfxg-prev">'+options.navText[0]+'</button><button class="vikfxg-next">'+options.navText[1]+'</button>'), |
| 150 |
counter = $('<div>').addClass('vikfxg-counter').html('<span class="vikfxg-current"></span>/<span class="vikfxg-total"></span>'), |
| 151 |
animating = false, |
| 152 |
index = 0, |
| 153 |
startIndex = 0, |
| 154 |
caption = $('<div>').addClass('vikfxg-caption '+options.captionClass+' pos-'+options.captionPosition), |
| 155 |
image = $('<div>').addClass('vikfxg-image'), |
| 156 |
wrapper = $('<div>').addClass('vikfxg-wrapper').addClass('vikfx-gallery'), |
| 157 |
isValidLink = function(element) { |
| 158 |
if (!options.fileExt) return true; |
| 159 |
var filEext = /\.([0-9a-z]+)(?=[?#])|(\.)(?:[\w]+)$/gmi; |
| 160 |
var testExt = $(element).attr(options.sourceAttr).match(filEext); |
| 161 |
return testExt && $(element).prop('tagName').toUpperCase() == tagname && (new RegExp('\.(' + options.fileExt + ')$', 'i')).test(testExt); |
| 162 |
}, |
| 163 |
setup = function() { |
| 164 |
if (options.close) closeBtn.appendTo(wrapper); |
| 165 |
if (options.showCounter) { |
| 166 |
if (objects.length > 1) { |
| 167 |
counter.appendTo(wrapper); |
| 168 |
counter.find('.vikfxg-total').text(objects.length); |
| 169 |
} |
| 170 |
} |
| 171 |
if (options.nav) nav.appendTo(wrapper); |
| 172 |
if (options.spinner) spinner.appendTo(wrapper); |
| 173 |
}, |
| 174 |
openImage = function(elem) { |
| 175 |
elem.trigger($.Event('show.vikfxgallery')); |
| 176 |
if (options.disableScroll) globalScrollbarwidth = handleScrollbar('hide'); |
| 177 |
if (options.htmlClass && options.htmlClass != '') $('html').addClass(options.htmlClass); |
| 178 |
wrapper.appendTo('body'); |
| 179 |
image.appendTo(wrapper); |
| 180 |
if (options.overlay) overlay.appendTo($('body')); |
| 181 |
animating = true; |
| 182 |
index = objects.index(elem); |
| 183 |
curImg = $('<img/>') |
| 184 |
.hide() |
| 185 |
.attr('src', elem.attr(options.sourceAttr)) |
| 186 |
.attr('data-scale', 1) |
| 187 |
.attr('data-translate-x', 0) |
| 188 |
.attr('data-translate-y', 0); |
| 189 |
if (loaded.indexOf(elem.attr(options.sourceAttr)) == -1) { |
| 190 |
loaded.push(elem.attr(options.sourceAttr)); |
| 191 |
} |
| 192 |
image.html('').attr('style',''); |
| 193 |
curImg.appendTo(image); |
| 194 |
addEvents(); |
| 195 |
overlay.fadeIn('fast'); |
| 196 |
$('.vikfxg-close').fadeIn('fast'); |
| 197 |
spinner.show(); |
| 198 |
nav.fadeIn('fast'); |
| 199 |
$('.vikfxg-wrapper .vikfxg-counter .vikfxg-current').text(index +1); |
| 200 |
counter.fadeIn('fast'); |
| 201 |
adjustImage(); |
| 202 |
if (options.preloading) preload(); |
| 203 |
setTimeout(function() { |
| 204 |
elem.trigger($.Event('shown.vikfxgallery')); |
| 205 |
}, options.animationSpeed); |
| 206 |
}, |
| 207 |
adjustImage = function(dir) { |
| 208 |
if (!curImg.length) return; |
| 209 |
var tmpImage = new Image(), |
| 210 |
windowWidth = window.innerWidth * options.widthRatio, |
| 211 |
windowHeight = window.innerHeight * options.heightRatio; |
| 212 |
tmpImage.src = curImg.attr('src'); |
| 213 |
curImg.data('scale',1); |
| 214 |
curImg.data('translate-x',0); |
| 215 |
curImg.data('translate-y',0); |
| 216 |
zoomPanElement(0,0,1); |
| 217 |
$(tmpImage).on('error',function(ev) { |
| 218 |
// image not found |
| 219 |
objects.eq(index).trigger($.Event('error.vikfxgallery')); |
| 220 |
animating = false; |
| 221 |
opened = true; |
| 222 |
spinner.hide(); |
| 223 |
var dirDefinined = (dir == 1 || dir == -1); |
| 224 |
if (startIndex === index && dirDefinined) { |
| 225 |
close(); |
| 226 |
return; |
| 227 |
} |
| 228 |
if (options.alertError) { |
| 229 |
alert(options.alertErrorMessage); |
| 230 |
} else { |
| 231 |
console.error(options.alertErrorMessage); |
| 232 |
} |
| 233 |
if (dirDefinined) { |
| 234 |
loadImage(dir); |
| 235 |
} else { |
| 236 |
loadImage(1); |
| 237 |
} |
| 238 |
return; |
| 239 |
}); |
| 240 |
|
| 241 |
tmpImage.onload = function() { |
| 242 |
if (typeof dir !== 'undefined') { |
| 243 |
objects.eq(index) |
| 244 |
.trigger($.Event('changed.vikfxgallery')) |
| 245 |
.trigger($.Event((dir ===1 ? 'nextDone' : 'prevDone') + '.vikfxgallery')); |
| 246 |
} |
| 247 |
|
| 248 |
// history |
| 249 |
if (options.history) { |
| 250 |
updateURL(); |
| 251 |
} |
| 252 |
|
| 253 |
if (loaded.indexOf(curImg.attr('src')) == -1) { |
| 254 |
loaded.push(curImg.attr('src')); |
| 255 |
} |
| 256 |
var imageWidth = tmpImage.width, |
| 257 |
imageHeight = tmpImage.height; |
| 258 |
|
| 259 |
if (options.scaleImageToRatio || imageWidth > windowWidth || imageHeight > windowHeight) { |
| 260 |
var ratio = imageWidth / imageHeight > windowWidth / windowHeight ? imageWidth / windowWidth : imageHeight / windowHeight; |
| 261 |
imageWidth /= ratio; |
| 262 |
imageHeight /= ratio; |
| 263 |
} |
| 264 |
|
| 265 |
$('.vikfxg-image').css({ |
| 266 |
'top': (window.innerHeight - imageHeight) / 2 + 'px', |
| 267 |
'left': (window.innerWidth - imageWidth - globalScrollbarwidth)/ 2 + 'px', |
| 268 |
'width': imageWidth + 'px', |
| 269 |
'height': imageHeight + 'px' |
| 270 |
}); |
| 271 |
spinner.hide(); |
| 272 |
curImg |
| 273 |
.fadeIn('fast'); |
| 274 |
opened = true; |
| 275 |
var cSel = (options.captionSelector == 'self') ? objects.eq(index) : objects.eq(index).find(options.captionSelector); |
| 276 |
var captionText; |
| 277 |
if (options.captionType == 'data') { |
| 278 |
captionText = cSel.data(options.captionsData); |
| 279 |
} else if (options.captionType == 'text') { |
| 280 |
captionText = cSel.html(); |
| 281 |
} else { |
| 282 |
captionText = cSel.prop(options.captionsData); |
| 283 |
} |
| 284 |
|
| 285 |
if (!options.loop) { |
| 286 |
if (index === 0) { $('.vikfxg-prev').hide();} |
| 287 |
if (index >= objects.length -1) {$('.vikfxg-next').hide();} |
| 288 |
if (index > 0) { $('.vikfxg-prev').show(); } |
| 289 |
if (index < objects.length -1) { $('.vikfxg-next').show(); } |
| 290 |
} |
| 291 |
|
| 292 |
if (objects.length == 1) $('.vikfxg-prev, .vikfxg-next').hide(); |
| 293 |
|
| 294 |
if (dir == 1 || dir == -1) { |
| 295 |
var css = { 'opacity': 1.0 }; |
| 296 |
if (options.animationSlide) { |
| 297 |
if (canTransisions) { |
| 298 |
slide(0, 100 * dir + 'px'); |
| 299 |
setTimeout(function() { |
| 300 |
slide(options.animationSpeed / 1000, 0 + 'px'); |
| 301 |
}, 50); |
| 302 |
} |
| 303 |
else { |
| 304 |
css.left = parseInt($('.vikfxg-image').css('left')) + 100 * dir + 'px'; |
| 305 |
} |
| 306 |
} |
| 307 |
|
| 308 |
$('.vikfxg-image').animate(css, options.animationSpeed, function() { |
| 309 |
animating = false; |
| 310 |
setCaption(captionText, imageWidth); |
| 311 |
}); |
| 312 |
} else { |
| 313 |
animating = false; |
| 314 |
setCaption(captionText, imageWidth); |
| 315 |
} |
| 316 |
if (options.additionalHtml && $('.vikfxg-additional-html').length === 0) { |
| 317 |
$('<div>').html(options.additionalHtml).addClass('vikfxg-additional-html').appendTo($('.vikfxg-image')); |
| 318 |
} |
| 319 |
}; |
| 320 |
}, |
| 321 |
setCaption = function(captiontext, imageWidth) { |
| 322 |
if (captiontext !== '' && typeof captiontext !== "undefined" && options.captions) { |
| 323 |
caption.html(captiontext).css({'width': imageWidth + 'px'}).hide().appendTo($('.vikfxg-image')).delay(options.captionDelay).fadeIn('fast'); |
| 324 |
} |
| 325 |
}, |
| 326 |
slide = function(speed, pos) { |
| 327 |
var styles = {}; |
| 328 |
styles[transPrefix + 'transform'] = 'translateX(' + pos + ')'; |
| 329 |
styles[transPrefix + 'transition'] = transPrefix + 'transform ' + speed + 's linear'; |
| 330 |
$('.vikfxg-image').css(styles); |
| 331 |
}, |
| 332 |
zoomPanElement = function(targetOffsetX, targetOffsetY, targetScale) { |
| 333 |
var styles = {}; |
| 334 |
styles[transPrefix + 'transform'] = 'translate(' + targetOffsetX + ',' + targetOffsetY+ ') scale('+targetScale+')'; |
| 335 |
curImg.css(styles); |
| 336 |
}, |
| 337 |
minMax = function(value, min, max) { |
| 338 |
return (value < min) ? min : (value > max) ? max : value; |
| 339 |
}, |
| 340 |
setZoomData = function(initialScale,targetOffsetX,targetOffsetY) { |
| 341 |
curImg.data('scale',initialScale); |
| 342 |
curImg.data('translate-x',targetOffsetX); |
| 343 |
curImg.data('translate-y',targetOffsetY); |
| 344 |
}, |
| 345 |
addEvents = function() { |
| 346 |
// resize/responsive |
| 347 |
$(window).on('resize.'+prefix, adjustImage); |
| 348 |
|
| 349 |
// close lightbox on close btn |
| 350 |
$(document).on('click.'+prefix+ ' touchstart.'+prefix, '.vikfxg-close', function(e) { |
| 351 |
e.preventDefault(); |
| 352 |
if (opened) { close();} |
| 353 |
}); |
| 354 |
|
| 355 |
if (options.history) { |
| 356 |
setTimeout(function() { |
| 357 |
$(window).on('hashchange.'+prefix,function() { |
| 358 |
if (opened) { |
| 359 |
if (getHash() === initialHash) { |
| 360 |
close(); |
| 361 |
return; |
| 362 |
} |
| 363 |
} |
| 364 |
}); |
| 365 |
}, 40); |
| 366 |
} |
| 367 |
|
| 368 |
// nav-buttons |
| 369 |
nav.on('click.'+prefix, 'button', throttle(function(e) { |
| 370 |
e.preventDefault(); |
| 371 |
swipeDiff = 0; |
| 372 |
loadImage($(this).hasClass('vikfxg-next') ? 1 : -1); |
| 373 |
}, options.throttleInterval)); |
| 374 |
|
| 375 |
// touch helpers |
| 376 |
var swipeStart = 0, |
| 377 |
swipeEnd = 0, |
| 378 |
swipeYStart = 0, |
| 379 |
swipeYEnd = 0, |
| 380 |
zoomed = false, |
| 381 |
mousedown = false, |
| 382 |
imageLeft = 0, |
| 383 |
containerHeight, |
| 384 |
containerWidth, |
| 385 |
containerOffsetX, |
| 386 |
containerOffsetY, |
| 387 |
imgHeight, |
| 388 |
imgWidth, |
| 389 |
capture = false, |
| 390 |
initialOffsetX, |
| 391 |
initialOffsetY, |
| 392 |
initialPointerOffsetX, |
| 393 |
initialPointerOffsetY, |
| 394 |
initialPointerOffsetX2, |
| 395 |
initialPointerOffsetY2, |
| 396 |
initialScale = minMax(1, 1, options.maxZoom), |
| 397 |
initialPinchDistance, |
| 398 |
pointerOffsetX, |
| 399 |
pointerOffsetY, |
| 400 |
pointerOffsetX2, |
| 401 |
pointerOffsetY2, |
| 402 |
targetOffsetX, |
| 403 |
targetOffsetY, |
| 404 |
targetScale, |
| 405 |
pinchOffsetX, |
| 406 |
pinchOffsetY, |
| 407 |
limitOffsetX, |
| 408 |
limitOffsetY, |
| 409 |
scaleDifference, |
| 410 |
targetPinchDistance, |
| 411 |
touchCount, |
| 412 |
doubleTapped = false, |
| 413 |
touchmoveCount = 0; |
| 414 |
|
| 415 |
image |
| 416 |
.on('touchstart.'+prefix+' mousedown.'+prefix, function(e) |
| 417 |
{ |
| 418 |
if (e.target.tagName === 'A' && e.type == 'touchstart') { |
| 419 |
return true; |
| 420 |
} |
| 421 |
e = e.originalEvent; |
| 422 |
if (e.type == 'mousedown') { |
| 423 |
initialPointerOffsetX = e.clientX; |
| 424 |
initialPointerOffsetY = e.clientY; |
| 425 |
containerHeight = image.height(); |
| 426 |
containerWidth = image.width(); |
| 427 |
imgHeight = curImg.height(); |
| 428 |
imgWidth = curImg.width(); |
| 429 |
containerOffsetX = image.position().left; |
| 430 |
containerOffsetY = image.position().top; |
| 431 |
|
| 432 |
initialOffsetX = parseFloat(curImg.data('translate-x')); |
| 433 |
initialOffsetY = parseFloat(curImg.data('translate-y')); |
| 434 |
|
| 435 |
capture = true; |
| 436 |
} else { |
| 437 |
touchCount = e.touches.length; |
| 438 |
initialPointerOffsetX = e.touches[0].clientX; |
| 439 |
initialPointerOffsetY = e.touches[0].clientY; |
| 440 |
containerHeight = image.height(); |
| 441 |
containerWidth = image.width(); |
| 442 |
imgHeight = curImg.height(); |
| 443 |
imgWidth = curImg.width(); |
| 444 |
containerOffsetX = image.position().left; |
| 445 |
containerOffsetY = image.position().top; |
| 446 |
|
| 447 |
if (touchCount === 1) /* Single touch */ { |
| 448 |
if (!doubleTapped) { |
| 449 |
doubleTapped = true; |
| 450 |
setTimeout(function() { |
| 451 |
doubleTapped = false; |
| 452 |
}, 300); |
| 453 |
} else { |
| 454 |
curImg.addClass('vikfxg-transition'); |
| 455 |
if (!zoomed) { |
| 456 |
initialScale = options.doubleTapZoom; |
| 457 |
setZoomData(0,0, initialScale); |
| 458 |
zoomPanElement(0 + "px", 0 + "px", initialScale); |
| 459 |
$('.vikfxg-caption').fadeOut(200); |
| 460 |
zoomed = true; |
| 461 |
} else { |
| 462 |
initialScale = 1; |
| 463 |
setZoomData(0,0,initialScale); |
| 464 |
zoomPanElement(0 + "px", 0 + "px", initialScale); |
| 465 |
zoomed = false; |
| 466 |
} |
| 467 |
|
| 468 |
setTimeout(function() { |
| 469 |
curImg.removeClass('vikfxg-transition'); |
| 470 |
}, 200); |
| 471 |
return false; |
| 472 |
} |
| 473 |
|
| 474 |
initialOffsetX = parseFloat(curImg.data('translate-x')); |
| 475 |
initialOffsetY = parseFloat(curImg.data('translate-y')); |
| 476 |
} |
| 477 |
else if (touchCount === 2) /* Pinch */ { |
| 478 |
initialPointerOffsetX2 = e.touches[1].clientX; |
| 479 |
initialPointerOffsetY2 = e.touches[1].clientY; |
| 480 |
initialOffsetX = parseFloat(curImg.data('translate-x')); |
| 481 |
initialOffsetY = parseFloat(curImg.data('translate-y')); |
| 482 |
pinchOffsetX = (initialPointerOffsetX + initialPointerOffsetX2) / 2; |
| 483 |
pinchOffsetY = (initialPointerOffsetY + initialPointerOffsetY2) / 2; |
| 484 |
initialPinchDistance = Math.sqrt(((initialPointerOffsetX - initialPointerOffsetX2) * (initialPointerOffsetX - initialPointerOffsetX2)) + ((initialPointerOffsetY - initialPointerOffsetY2) * (initialPointerOffsetY - initialPointerOffsetY2))); |
| 485 |
} |
| 486 |
capture = true; |
| 487 |
} |
| 488 |
|
| 489 |
if (mousedown) return true; |
| 490 |
if (canTransisions) imageLeft = parseInt(image.css('left')); |
| 491 |
mousedown = true; |
| 492 |
swipeDiff = 0; |
| 493 |
swipeYDiff = 0; |
| 494 |
swipeStart = e.pageX || e.touches[ 0 ].pageX; |
| 495 |
swipeYStart = e.pageY || e.touches[ 0 ].pageY; |
| 496 |
return false; |
| 497 |
}) |
| 498 |
.on('touchmove.'+prefix+' mousemove.'+prefix+' MSPointerMove', function(e) |
| 499 |
{ |
| 500 |
if (!mousedown) return true; |
| 501 |
e.preventDefault(); |
| 502 |
e = e.originalEvent; |
| 503 |
/* Initialize helpers */ |
| 504 |
if (e.type == 'touchmove') { |
| 505 |
if (capture === false) return false; |
| 506 |
pointerOffsetX = e.touches[0].clientX; |
| 507 |
pointerOffsetY = e.touches[0].clientY; |
| 508 |
touchCount = e.touches.length; |
| 509 |
touchmoveCount++; |
| 510 |
|
| 511 |
if (touchCount > 1) /* Pinch */ { |
| 512 |
pointerOffsetX2 = e.touches[1].clientX; |
| 513 |
pointerOffsetY2 = e.touches[1].clientY; |
| 514 |
targetPinchDistance = Math.sqrt(((pointerOffsetX - pointerOffsetX2) * (pointerOffsetX - pointerOffsetX2)) + ((pointerOffsetY - pointerOffsetY2) * (pointerOffsetY - pointerOffsetY2))); |
| 515 |
if (initialPinchDistance === null) { |
| 516 |
initialPinchDistance = targetPinchDistance; |
| 517 |
} |
| 518 |
|
| 519 |
if (Math.abs(initialPinchDistance - targetPinchDistance) >= 1) { |
| 520 |
/* Initialize helpers */ |
| 521 |
targetScale = minMax(targetPinchDistance / initialPinchDistance * initialScale, 1, options.maxZoom); |
| 522 |
limitOffsetX = ((imgWidth * targetScale) - containerWidth) / 2; |
| 523 |
limitOffsetY = ((imgHeight * targetScale) - containerHeight) / 2; |
| 524 |
scaleDifference = targetScale - initialScale; |
| 525 |
targetOffsetX = (imgWidth * targetScale) <= containerWidth ? 0: minMax(initialOffsetX - ((((((pinchOffsetX - containerOffsetX) - (containerWidth / 2)) - initialOffsetX) / (targetScale - scaleDifference))) * scaleDifference), limitOffsetX * (-1), limitOffsetX); |
| 526 |
targetOffsetY = (imgHeight * targetScale) <= containerHeight ? 0 : minMax(initialOffsetY - ((((((pinchOffsetY - containerOffsetY) - (containerHeight / 2)) - initialOffsetY) / (targetScale - scaleDifference))) * scaleDifference), limitOffsetY * (-1), limitOffsetY); |
| 527 |
|
| 528 |
zoomPanElement(targetOffsetX + "px", targetOffsetY + "px", targetScale); |
| 529 |
|
| 530 |
if (targetScale > 1) { |
| 531 |
zoomed = true; |
| 532 |
$('.vikfxg-caption').fadeOut(200); |
| 533 |
} |
| 534 |
|
| 535 |
initialPinchDistance = targetPinchDistance; |
| 536 |
initialScale = targetScale; |
| 537 |
initialOffsetX = targetOffsetX; |
| 538 |
initialOffsetY = targetOffsetY; |
| 539 |
} |
| 540 |
} else { |
| 541 |
targetScale = initialScale; |
| 542 |
limitOffsetX = ((imgWidth * targetScale) - containerWidth) / 2; |
| 543 |
limitOffsetY = ((imgHeight * targetScale) - containerHeight) / 2; |
| 544 |
targetOffsetX = (imgWidth * targetScale) <= containerWidth ? 0 : minMax(pointerOffsetX - (initialPointerOffsetX - initialOffsetX), limitOffsetX * (-1), limitOffsetX); |
| 545 |
targetOffsetY = (imgHeight * targetScale) <= containerHeight ? 0 : minMax(pointerOffsetY - (initialPointerOffsetY - initialOffsetY), limitOffsetY * (-1), limitOffsetY); |
| 546 |
|
| 547 |
if (Math.abs(targetOffsetX) === Math.abs(limitOffsetX)) { |
| 548 |
initialOffsetX = targetOffsetX; |
| 549 |
initialPointerOffsetX = pointerOffsetX; |
| 550 |
} |
| 551 |
|
| 552 |
if (Math.abs(targetOffsetY) === Math.abs(limitOffsetY)) { |
| 553 |
initialOffsetY = targetOffsetY; |
| 554 |
initialPointerOffsetY = pointerOffsetY; |
| 555 |
} |
| 556 |
|
| 557 |
setZoomData(initialScale,targetOffsetX,targetOffsetY); |
| 558 |
zoomPanElement(targetOffsetX + "px", targetOffsetY + "px", targetScale); |
| 559 |
} |
| 560 |
} |
| 561 |
/* Mouse Move implementation */ |
| 562 |
if (e.type == 'mousemove' && mousedown) { |
| 563 |
if (e.type == 'touchmove') return true; |
| 564 |
if (capture === false) return false; |
| 565 |
pointerOffsetX = e.clientX; |
| 566 |
pointerOffsetY = e.clientY; |
| 567 |
targetScale = initialScale; |
| 568 |
limitOffsetX = ((imgWidth * targetScale) - containerWidth) / 2; |
| 569 |
limitOffsetY = ((imgHeight * targetScale) - containerHeight) / 2; |
| 570 |
targetOffsetX = (imgWidth * targetScale) <= containerWidth ? 0 : minMax(pointerOffsetX - (initialPointerOffsetX - initialOffsetX), limitOffsetX * (-1), limitOffsetX); |
| 571 |
targetOffsetY = (imgHeight * targetScale) <= containerHeight ? 0 : minMax(pointerOffsetY - (initialPointerOffsetY - initialOffsetY), limitOffsetY * (-1), limitOffsetY); |
| 572 |
|
| 573 |
if (Math.abs(targetOffsetX) === Math.abs(limitOffsetX)) { |
| 574 |
initialOffsetX = targetOffsetX; |
| 575 |
initialPointerOffsetX = pointerOffsetX; |
| 576 |
} |
| 577 |
|
| 578 |
if (Math.abs(targetOffsetY) === Math.abs(limitOffsetY)) { |
| 579 |
initialOffsetY = targetOffsetY; |
| 580 |
initialPointerOffsetY = pointerOffsetY; |
| 581 |
} |
| 582 |
|
| 583 |
setZoomData(initialScale,targetOffsetX,targetOffsetY); |
| 584 |
zoomPanElement(targetOffsetX + "px", targetOffsetY + "px", targetScale); |
| 585 |
} |
| 586 |
if (!zoomed) { |
| 587 |
swipeEnd = e.pageX || e.touches[ 0 ].pageX; |
| 588 |
swipeYEnd = e.pageY || e.touches[ 0 ].pageY; |
| 589 |
swipeDiff = swipeStart - swipeEnd; |
| 590 |
swipeYDiff = swipeYStart - swipeYEnd; |
| 591 |
if (options.animationSlide) { |
| 592 |
if (canTransisions) slide(0, -swipeDiff + 'px'); |
| 593 |
else image.css('left', imageLeft - swipeDiff + 'px'); |
| 594 |
} |
| 595 |
} |
| 596 |
}) |
| 597 |
.on('touchend.'+prefix+' mouseup.'+prefix+' touchcancel.'+prefix+' mouseleave.'+prefix+' pointerup pointercancel MSPointerUp MSPointerCancel',function(e) |
| 598 |
{ |
| 599 |
e = e.originalEvent; |
| 600 |
if (touchDevice && e.type =='touchend') { |
| 601 |
touchCount = e.touches.length; |
| 602 |
if (touchCount === 0) /* No touch */ { |
| 603 |
/* Set attributes */ |
| 604 |
setZoomData(initialScale,targetOffsetX,targetOffsetY); |
| 605 |
if (initialScale == 1) { |
| 606 |
zoomed = false; |
| 607 |
$('.vikfxg-caption').fadeIn(200); |
| 608 |
} |
| 609 |
initialPinchDistance = null; |
| 610 |
capture = false; |
| 611 |
} else if (touchCount === 1) /* Single touch */ { |
| 612 |
initialPointerOffsetX = e.touches[0].clientX; |
| 613 |
initialPointerOffsetY = e.touches[0].clientY; |
| 614 |
} else if (touchCount > 1) /* Pinch */ { |
| 615 |
initialPinchDistance = null; |
| 616 |
} |
| 617 |
} |
| 618 |
|
| 619 |
if (mousedown) { |
| 620 |
mousedown = false; |
| 621 |
var possibleDir = true; |
| 622 |
if (!options.loop) { |
| 623 |
if (index === 0 && swipeDiff < 0) { possibleDir = false; } |
| 624 |
if (index >= objects.length -1 && swipeDiff > 0) { possibleDir = false; } |
| 625 |
} |
| 626 |
if (Math.abs(swipeDiff) > options.swipeTolerance && possibleDir) { |
| 627 |
loadImage(swipeDiff > 0 ? 1 : -1); |
| 628 |
} |
| 629 |
else if (options.animationSlide) |
| 630 |
{ |
| 631 |
if (canTransisions) slide(options.animationSpeed / 1000, 0 + 'px'); |
| 632 |
else image.animate({ 'left': imageLeft + 'px' }, options.animationSpeed / 2); |
| 633 |
} |
| 634 |
|
| 635 |
if (options.swipeClose && Math.abs(swipeYDiff) > 50 && Math.abs(swipeDiff) < options.swipeTolerance) { |
| 636 |
close(); |
| 637 |
} |
| 638 |
} |
| 639 |
}) |
| 640 |
/** Detect Double click on image*/ |
| 641 |
.on('dblclick', function(e) |
| 642 |
{ |
| 643 |
initialPointerOffsetX = e.clientX; |
| 644 |
initialPointerOffsetY = e.clientY; |
| 645 |
containerHeight = image.height(); |
| 646 |
containerWidth = image.width(); |
| 647 |
imgHeight = curImg.height(); |
| 648 |
imgWidth = curImg.width(); |
| 649 |
containerOffsetX = image.position().left; |
| 650 |
containerOffsetY = image.position().top; |
| 651 |
|
| 652 |
curImg.addClass('vikfxg-transition'); |
| 653 |
if (!zoomed) { |
| 654 |
initialScale = options.doubleTapZoom; |
| 655 |
setZoomData(0,0, initialScale); |
| 656 |
zoomPanElement(0 + "px", 0 + "px", initialScale); |
| 657 |
$('.vikfxg-caption').fadeOut(200); |
| 658 |
zoomed = true; |
| 659 |
} else { |
| 660 |
initialScale = 1; |
| 661 |
setZoomData(0,0,initialScale); |
| 662 |
zoomPanElement(0 + "px", 0 + "px", initialScale); |
| 663 |
zoomed = false; |
| 664 |
} |
| 665 |
|
| 666 |
setTimeout(function() { |
| 667 |
curImg.removeClass('vikfxg-transition'); |
| 668 |
}, 200); |
| 669 |
capture = true; |
| 670 |
return false; |
| 671 |
}); |
| 672 |
}, |
| 673 |
removeEvents = function() { |
| 674 |
nav.off('click', 'button'); |
| 675 |
$(document).off('click.'+prefix, '.vikfxg-close'); |
| 676 |
$(window).off('resize.'+prefix); |
| 677 |
$(window).off('hashchange.'+prefix); |
| 678 |
}, |
| 679 |
preload = function() { |
| 680 |
var next = (index+1 < 0) ? objects.length -1: (index+1 >= objects.length -1) ? 0 : index+1, |
| 681 |
prev = (index-1 < 0) ? objects.length -1: (index-1 >= objects.length -1) ? 0 : index-1; |
| 682 |
$('<img />').attr('src', objects.eq(next).attr(options.sourceAttr)).on('load', function() { |
| 683 |
if (loaded.indexOf($(this).attr('src')) == -1) { |
| 684 |
loaded.push($(this).attr('src')); |
| 685 |
} |
| 686 |
objects.eq(index).trigger($.Event('nextImageLoaded.vikfxgallery')); |
| 687 |
}); |
| 688 |
$('<img />').attr('src', objects.eq(prev).attr(options.sourceAttr)).on('load', function() { |
| 689 |
if (loaded.indexOf($(this).attr('src')) == -1) { |
| 690 |
loaded.push($(this).attr('src')); |
| 691 |
} |
| 692 |
objects.eq(index).trigger($.Event('prevImageLoaded.vikfxgallery')); |
| 693 |
}); |
| 694 |
|
| 695 |
}, |
| 696 |
loadImage = function(dir) { |
| 697 |
objects.eq(index) |
| 698 |
.trigger($.Event('change.vikfxgallery')) |
| 699 |
.trigger($.Event((dir === 1 ? 'next' : 'prev') + '.vikfxgallery')); |
| 700 |
|
| 701 |
var newIndex = index + dir; |
| 702 |
if (animating || (newIndex < 0 || newIndex >= objects.length) && options.loop === false) return; |
| 703 |
index = (newIndex < 0) ? objects.length -1: (newIndex > objects.length -1) ? 0 : newIndex; |
| 704 |
$('.vikfxg-wrapper .vikfxg-counter .vikfxg-current').text(index +1); |
| 705 |
var css = { 'opacity': 0 }; |
| 706 |
if (options.animationSlide) { |
| 707 |
if (canTransisions) slide(options.animationSpeed / 1000, (-100 * dir) - swipeDiff + 'px'); |
| 708 |
else css.left = parseInt($('.vikfxg-image').css('left')) + -100 * dir + 'px'; |
| 709 |
} |
| 710 |
|
| 711 |
$('.vikfxg-image').animate(css, options.animationSpeed, function() { |
| 712 |
setTimeout(function() { |
| 713 |
// fadeout old image |
| 714 |
var elem = objects.eq(index); |
| 715 |
curImg |
| 716 |
.attr('src', elem.attr(options.sourceAttr)); |
| 717 |
|
| 718 |
if (loaded.indexOf(elem.attr(options.sourceAttr)) == -1) { |
| 719 |
spinner.show(); |
| 720 |
} |
| 721 |
$('.vikfxg-caption').remove(); |
| 722 |
adjustImage(dir); |
| 723 |
if (options.preloading) preload(); |
| 724 |
}, 100); |
| 725 |
}); |
| 726 |
}, |
| 727 |
close = function() { |
| 728 |
if (animating) return; |
| 729 |
var elem = objects.eq(index), |
| 730 |
triggered = false; |
| 731 |
|
| 732 |
elem.trigger($.Event('close.vikfxgallery')); |
| 733 |
if (options.history) { |
| 734 |
resetHash(); |
| 735 |
} |
| 736 |
$('.vikfxg-image img, .vikfxg-overlay, .vikfxg-close, .vikfxg-navigation, .vikfxg-image .vikfxg-caption, .vikfxg-counter').fadeOut('fast', function() { |
| 737 |
if (options.disableScroll) handleScrollbar('show'); |
| 738 |
if (options.htmlClass && options.htmlClass != '') $('html').removeClass(options.htmlClass); |
| 739 |
$('.vikfxg-wrapper, .vikfxg-overlay').remove(); |
| 740 |
removeEvents(); |
| 741 |
if (!triggered) elem.trigger($.Event('closed.vikfxgallery')); |
| 742 |
triggered = true; |
| 743 |
}); |
| 744 |
curImg = $(); |
| 745 |
opened = false; |
| 746 |
animating = false; |
| 747 |
}, |
| 748 |
handleScrollbar = function(type) { |
| 749 |
var scrollbarWidth = 0; |
| 750 |
if (type == 'hide') { |
| 751 |
var fullWindowWidth = window.innerWidth; |
| 752 |
if (!fullWindowWidth) { |
| 753 |
var documentElementRect = document.documentElement.getBoundingClientRect(); |
| 754 |
fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left); |
| 755 |
} |
| 756 |
if (document.body.clientWidth < fullWindowWidth) { |
| 757 |
var scrollDiv = document.createElement('div'), |
| 758 |
padding = parseInt($('body').css('padding-right'),10); |
| 759 |
scrollDiv.className = 'vikfxg-scrollbar-measure'; |
| 760 |
$('body').append(scrollDiv); |
| 761 |
scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; |
| 762 |
$(document.body)[0].removeChild(scrollDiv); |
| 763 |
$('body').data('padding',padding); |
| 764 |
if (scrollbarWidth > 0) { |
| 765 |
$('body').addClass('hidden-scroll').css({'padding-right':padding+scrollbarWidth}); |
| 766 |
} |
| 767 |
} |
| 768 |
} else { |
| 769 |
$('body').removeClass('hidden-scroll').css({'padding-right':$('body').data('padding')}); |
| 770 |
} |
| 771 |
return scrollbarWidth; |
| 772 |
}; |
| 773 |
|
| 774 |
// events |
| 775 |
setup(); |
| 776 |
|
| 777 |
// open lightbox |
| 778 |
objects.on('click.'+prefix, function(e) { |
| 779 |
if (isValidLink(this)) { |
| 780 |
e.preventDefault(); |
| 781 |
if (animating) return false; |
| 782 |
var elem = $(this); |
| 783 |
startIndex = objects.index(elem); |
| 784 |
openImage(elem); |
| 785 |
} |
| 786 |
}); |
| 787 |
|
| 788 |
// close on click on doc |
| 789 |
$(document).on('click.'+prefix+ ' touchstart.'+prefix, function(e) { |
| 790 |
if (opened) { |
| 791 |
if ((options.docClose && $(e.target).closest('.vikfxg-image').length === 0 && $(e.target).closest('.vikfxg-navigation').length === 0)) { |
| 792 |
close(); |
| 793 |
} |
| 794 |
} |
| 795 |
}); |
| 796 |
|
| 797 |
// disable rightclick |
| 798 |
if (options.disableRightClick) { |
| 799 |
$(document).on('contextmenu', '.vikfxg-image img', function(e) { |
| 800 |
return false; |
| 801 |
}); |
| 802 |
} |
| 803 |
|
| 804 |
// keyboard-control |
| 805 |
if (options.enableKeyboard) { |
| 806 |
$(document).on('keyup.'+prefix, throttle(function(e) { |
| 807 |
swipeDiff = 0; |
| 808 |
// keyboard control only if lightbox is open |
| 809 |
var key = e.keyCode; |
| 810 |
if (animating && key == 27) { |
| 811 |
curImg.attr('src', ''); |
| 812 |
animating = false; |
| 813 |
close(); |
| 814 |
} |
| 815 |
|
| 816 |
if (opened) { |
| 817 |
e.preventDefault(); |
| 818 |
if (key == 27) { |
| 819 |
close(); |
| 820 |
} |
| 821 |
if (key == 37 || e.keyCode == 39) { |
| 822 |
loadImage(e.keyCode == 39 ? 1 : -1); |
| 823 |
} |
| 824 |
} |
| 825 |
}, options.throttleInterval)); |
| 826 |
} |
| 827 |
|
| 828 |
// Public methods |
| 829 |
this.open = function(elem) { |
| 830 |
elem = elem || $(this[0]); |
| 831 |
startIndex = objects.index(elem); |
| 832 |
openImage(elem); |
| 833 |
}; |
| 834 |
|
| 835 |
this.close = function() { |
| 836 |
close(); |
| 837 |
}; |
| 838 |
|
| 839 |
this.next = function() { |
| 840 |
loadImage(1); |
| 841 |
}; |
| 842 |
|
| 843 |
this.prev = function() { |
| 844 |
loadImage(-1); |
| 845 |
}; |
| 846 |
|
| 847 |
this.destroy = function() { |
| 848 |
$(document).off('click.'+prefix).off('keyup.'+prefix); |
| 849 |
close(); |
| 850 |
$('.vikfxg-overlay, .vikfxg-wrapper').remove(); |
| 851 |
this.off('click'); |
| 852 |
}; |
| 853 |
|
| 854 |
this.refresh = function() { |
| 855 |
this.destroy(); |
| 856 |
$(this).vikFxGallery(options); |
| 857 |
}; |
| 858 |
|
| 859 |
return this; |
| 860 |
|
| 861 |
}; |
| 862 |
})(jQuery, window, document); |
| 863 |
|