mirror of https://github.com/IoTcat/ushio-img.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
886 lines
25 KiB
886 lines
25 KiB
4 years ago
|
// ==========================================================================
|
||
|
//
|
||
|
// Guestures
|
||
|
// Adds touch guestures, handles click and tap events
|
||
|
//
|
||
|
// ==========================================================================
|
||
|
(function(window, document, $) {
|
||
|
"use strict";
|
||
|
|
||
|
var requestAFrame = (function() {
|
||
|
return (
|
||
|
window.requestAnimationFrame ||
|
||
|
window.webkitRequestAnimationFrame ||
|
||
|
window.mozRequestAnimationFrame ||
|
||
|
window.oRequestAnimationFrame ||
|
||
|
// if all else fails, use setTimeout
|
||
|
function(callback) {
|
||
|
return window.setTimeout(callback, 1000 / 60);
|
||
|
}
|
||
|
);
|
||
|
})();
|
||
|
|
||
|
var cancelAFrame = (function() {
|
||
|
return (
|
||
|
window.cancelAnimationFrame ||
|
||
|
window.webkitCancelAnimationFrame ||
|
||
|
window.mozCancelAnimationFrame ||
|
||
|
window.oCancelAnimationFrame ||
|
||
|
function(id) {
|
||
|
window.clearTimeout(id);
|
||
|
}
|
||
|
);
|
||
|
})();
|
||
|
|
||
|
var getPointerXY = function(e) {
|
||
|
var result = [];
|
||
|
|
||
|
e = e.originalEvent || e || window.e;
|
||
|
e = e.touches && e.touches.length ? e.touches : e.changedTouches && e.changedTouches.length ? e.changedTouches : [e];
|
||
|
|
||
|
for (var key in e) {
|
||
|
if (e[key].pageX) {
|
||
|
result.push({
|
||
|
x: e[key].pageX,
|
||
|
y: e[key].pageY
|
||
|
});
|
||
|
} else if (e[key].clientX) {
|
||
|
result.push({
|
||
|
x: e[key].clientX,
|
||
|
y: e[key].clientY
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
};
|
||
|
|
||
|
var distance = function(point2, point1, what) {
|
||
|
if (!point1 || !point2) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (what === "x") {
|
||
|
return point2.x - point1.x;
|
||
|
} else if (what === "y") {
|
||
|
return point2.y - point1.y;
|
||
|
}
|
||
|
|
||
|
return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
|
||
|
};
|
||
|
|
||
|
var isClickable = function($el) {
|
||
|
if (
|
||
|
$el.is('a,area,button,[role="button"],input,label,select,summary,textarea,video,audio') ||
|
||
|
$.isFunction($el.get(0).onclick) ||
|
||
|
$el.data("selectable")
|
||
|
) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Check for attributes like data-fancybox-next or data-fancybox-close
|
||
|
for (var i = 0, atts = $el[0].attributes, n = atts.length; i < n; i++) {
|
||
|
if (atts[i].nodeName.substr(0, 14) === "data-fancybox-") {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
var hasScrollbars = function(el) {
|
||
|
var overflowY = window.getComputedStyle(el)["overflow-y"],
|
||
|
overflowX = window.getComputedStyle(el)["overflow-x"],
|
||
|
vertical = (overflowY === "scroll" || overflowY === "auto") && el.scrollHeight > el.clientHeight,
|
||
|
horizontal = (overflowX === "scroll" || overflowX === "auto") && el.scrollWidth > el.clientWidth;
|
||
|
|
||
|
return vertical || horizontal;
|
||
|
};
|
||
|
|
||
|
var isScrollable = function($el) {
|
||
|
var rez = false;
|
||
|
|
||
|
while (true) {
|
||
|
rez = hasScrollbars($el.get(0));
|
||
|
|
||
|
if (rez) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
$el = $el.parent();
|
||
|
|
||
|
if (!$el.length || $el.hasClass("fancybox-stage") || $el.is("body")) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return rez;
|
||
|
};
|
||
|
|
||
|
var Guestures = function(instance) {
|
||
|
var self = this;
|
||
|
|
||
|
self.instance = instance;
|
||
|
|
||
|
self.$bg = instance.$refs.bg;
|
||
|
self.$stage = instance.$refs.stage;
|
||
|
self.$container = instance.$refs.container;
|
||
|
|
||
|
self.destroy();
|
||
|
|
||
|
self.$container.on("touchstart.fb.touch mousedown.fb.touch", $.proxy(self, "ontouchstart"));
|
||
|
};
|
||
|
|
||
|
Guestures.prototype.destroy = function() {
|
||
|
this.$container.off(".fb.touch");
|
||
|
};
|
||
|
|
||
|
Guestures.prototype.ontouchstart = function(e) {
|
||
|
var self = this,
|
||
|
$target = $(e.target),
|
||
|
instance = self.instance,
|
||
|
current = instance.current,
|
||
|
$content = current.$content,
|
||
|
isTouchDevice = e.type == "touchstart";
|
||
|
|
||
|
// Do not respond to both (touch and mouse) events
|
||
|
if (isTouchDevice) {
|
||
|
self.$container.off("mousedown.fb.touch");
|
||
|
}
|
||
|
|
||
|
// Ignore right click
|
||
|
if (e.originalEvent && e.originalEvent.button == 2) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Ignore taping on links, buttons, input elements
|
||
|
if (!$target.length || isClickable($target) || isClickable($target.parent())) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Ignore clicks on the scrollbar
|
||
|
if (!$target.is("img") && e.originalEvent.clientX > $target[0].clientWidth + $target.offset().left) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Ignore clicks while zooming or closing
|
||
|
if (!current || instance.isAnimating || instance.isClosing) {
|
||
|
e.stopPropagation();
|
||
|
e.preventDefault();
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
self.realPoints = self.startPoints = getPointerXY(e);
|
||
|
|
||
|
if (!self.startPoints.length) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
e.stopPropagation();
|
||
|
|
||
|
self.startEvent = e;
|
||
|
|
||
|
self.canTap = true;
|
||
|
self.$target = $target;
|
||
|
self.$content = $content;
|
||
|
self.opts = current.opts.touch;
|
||
|
|
||
|
self.isPanning = false;
|
||
|
self.isSwiping = false;
|
||
|
self.isZooming = false;
|
||
|
self.isScrolling = false;
|
||
|
|
||
|
self.startTime = new Date().getTime();
|
||
|
self.distanceX = self.distanceY = self.distance = 0;
|
||
|
|
||
|
self.canvasWidth = Math.round(current.$slide[0].clientWidth);
|
||
|
self.canvasHeight = Math.round(current.$slide[0].clientHeight);
|
||
|
|
||
|
self.contentLastPos = null;
|
||
|
self.contentStartPos = $.fancybox.getTranslate(self.$content) || {top: 0, left: 0};
|
||
|
self.sliderStartPos = self.sliderLastPos || $.fancybox.getTranslate(current.$slide);
|
||
|
|
||
|
// Since position will be absolute, but we need to make it relative to the stage
|
||
|
self.stagePos = $.fancybox.getTranslate(instance.$refs.stage);
|
||
|
|
||
|
self.sliderStartPos.top -= self.stagePos.top;
|
||
|
self.sliderStartPos.left -= self.stagePos.left;
|
||
|
|
||
|
self.contentStartPos.top -= self.stagePos.top;
|
||
|
self.contentStartPos.left -= self.stagePos.left;
|
||
|
|
||
|
$(document)
|
||
|
.off(".fb.touch")
|
||
|
.on(isTouchDevice ? "touchend.fb.touch touchcancel.fb.touch" : "mouseup.fb.touch mouseleave.fb.touch", $.proxy(self, "ontouchend"))
|
||
|
.on(isTouchDevice ? "touchmove.fb.touch" : "mousemove.fb.touch", $.proxy(self, "ontouchmove"));
|
||
|
|
||
|
if ($.fancybox.isMobile) {
|
||
|
document.addEventListener("scroll", self.onscroll, true);
|
||
|
}
|
||
|
|
||
|
if (!(self.opts || instance.canPan()) || !($target.is(self.$stage) || self.$stage.find($target).length)) {
|
||
|
if ($target.is(".fancybox-image")) {
|
||
|
e.preventDefault();
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!($.fancybox.isMobile && (isScrollable($target) || isScrollable($target.parent())))) {
|
||
|
e.preventDefault();
|
||
|
}
|
||
|
|
||
|
if (self.startPoints.length === 1 || current.hasError) {
|
||
|
if (self.instance.canPan()) {
|
||
|
$.fancybox.stop(self.$content);
|
||
|
|
||
|
self.$content.css("transition-duration", "");
|
||
|
|
||
|
self.isPanning = true;
|
||
|
} else {
|
||
|
self.isSwiping = true;
|
||
|
}
|
||
|
|
||
|
self.$container.addClass("fancybox-controls--isGrabbing");
|
||
|
}
|
||
|
|
||
|
if (self.startPoints.length === 2 && current.type === "image" && (current.isLoaded || current.$ghost)) {
|
||
|
self.canTap = false;
|
||
|
self.isSwiping = false;
|
||
|
self.isPanning = false;
|
||
|
|
||
|
self.isZooming = true;
|
||
|
|
||
|
$.fancybox.stop(self.$content);
|
||
|
|
||
|
self.$content.css("transition-duration", "");
|
||
|
|
||
|
self.centerPointStartX = (self.startPoints[0].x + self.startPoints[1].x) * 0.5 - $(window).scrollLeft();
|
||
|
self.centerPointStartY = (self.startPoints[0].y + self.startPoints[1].y) * 0.5 - $(window).scrollTop();
|
||
|
|
||
|
self.percentageOfImageAtPinchPointX = (self.centerPointStartX - self.contentStartPos.left) / self.contentStartPos.width;
|
||
|
self.percentageOfImageAtPinchPointY = (self.centerPointStartY - self.contentStartPos.top) / self.contentStartPos.height;
|
||
|
|
||
|
self.startDistanceBetweenFingers = distance(self.startPoints[0], self.startPoints[1]);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Guestures.prototype.onscroll = function(e) {
|
||
|
var self = this;
|
||
|
|
||
|
self.isScrolling = true;
|
||
|
|
||
|
document.removeEventListener("scroll", self.onscroll, true);
|
||
|
};
|
||
|
|
||
|
Guestures.prototype.ontouchmove = function(e) {
|
||
|
var self = this,
|
||
|
$target = $(e.target);
|
||
|
|
||
|
// Make sure user has not released over iframe or disabled element
|
||
|
if (e.originalEvent.buttons !== undefined && e.originalEvent.buttons === 0) {
|
||
|
self.ontouchend(e);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (self.isScrolling || !($target.is(self.$stage) || self.$stage.find($target).length)) {
|
||
|
self.canTap = false;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
self.newPoints = getPointerXY(e);
|
||
|
|
||
|
if (!(self.opts || self.instance.canPan()) || !self.newPoints.length || !self.newPoints.length) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!(self.isSwiping && self.isSwiping === true)) {
|
||
|
e.preventDefault();
|
||
|
}
|
||
|
|
||
|
self.distanceX = distance(self.newPoints[0], self.startPoints[0], "x");
|
||
|
self.distanceY = distance(self.newPoints[0], self.startPoints[0], "y");
|
||
|
|
||
|
self.distance = distance(self.newPoints[0], self.startPoints[0]);
|
||
|
|
||
|
// Skip false ontouchmove events (Chrome)
|
||
|
if (self.distance > 0) {
|
||
|
if (self.isSwiping) {
|
||
|
self.onSwipe(e);
|
||
|
} else if (self.isPanning) {
|
||
|
self.onPan();
|
||
|
} else if (self.isZooming) {
|
||
|
self.onZoom();
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Guestures.prototype.onSwipe = function(e) {
|
||
|
var self = this,
|
||
|
swiping = self.isSwiping,
|
||
|
left = self.sliderStartPos.left || 0,
|
||
|
angle;
|
||
|
|
||
|
// If direction is not yet determined
|
||
|
if (swiping === true) {
|
||
|
// We need at least 10px distance to correctly calculate an angle
|
||
|
if (Math.abs(self.distance) > 10) {
|
||
|
self.canTap = false;
|
||
|
|
||
|
if (self.instance.group.length < 2 && self.opts.vertical) {
|
||
|
self.isSwiping = "y";
|
||
|
} else if (self.instance.isDragging || self.opts.vertical === false || (self.opts.vertical === "auto" && $(window).width() > 800)) {
|
||
|
self.isSwiping = "x";
|
||
|
} else {
|
||
|
angle = Math.abs(Math.atan2(self.distanceY, self.distanceX) * 180 / Math.PI);
|
||
|
|
||
|
self.isSwiping = angle > 45 && angle < 135 ? "y" : "x";
|
||
|
}
|
||
|
|
||
|
self.canTap = false;
|
||
|
|
||
|
if (self.isSwiping === "y" && $.fancybox.isMobile && (isScrollable(self.$target) || isScrollable(self.$target.parent()))) {
|
||
|
self.isScrolling = true;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
self.instance.isDragging = self.isSwiping;
|
||
|
|
||
|
// Reset points to avoid jumping, because we dropped first swipes to calculate the angle
|
||
|
self.startPoints = self.newPoints;
|
||
|
|
||
|
$.each(self.instance.slides, function(index, slide) {
|
||
|
$.fancybox.stop(slide.$slide);
|
||
|
|
||
|
slide.$slide.css("transition-duration", "");
|
||
|
|
||
|
slide.inTransition = false;
|
||
|
|
||
|
if (slide.pos === self.instance.current.pos) {
|
||
|
self.sliderStartPos.left = $.fancybox.getTranslate(slide.$slide).left - $.fancybox.getTranslate(self.instance.$refs.stage).left;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Stop slideshow
|
||
|
if (self.instance.SlideShow && self.instance.SlideShow.isActive) {
|
||
|
self.instance.SlideShow.stop();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Sticky edges
|
||
|
if (swiping == "x") {
|
||
|
if (
|
||
|
self.distanceX > 0 &&
|
||
|
(self.instance.group.length < 2 || (self.instance.current.index === 0 && !self.instance.current.opts.loop))
|
||
|
) {
|
||
|
left = left + Math.pow(self.distanceX, 0.8);
|
||
|
} else if (
|
||
|
self.distanceX < 0 &&
|
||
|
(self.instance.group.length < 2 ||
|
||
|
(self.instance.current.index === self.instance.group.length - 1 && !self.instance.current.opts.loop))
|
||
|
) {
|
||
|
left = left - Math.pow(-self.distanceX, 0.8);
|
||
|
} else {
|
||
|
left = left + self.distanceX;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
self.sliderLastPos = {
|
||
|
top: swiping == "x" ? 0 : self.sliderStartPos.top + self.distanceY,
|
||
|
left: left
|
||
|
};
|
||
|
|
||
|
if (self.requestId) {
|
||
|
cancelAFrame(self.requestId);
|
||
|
|
||
|
self.requestId = null;
|
||
|
}
|
||
|
|
||
|
self.requestId = requestAFrame(function() {
|
||
|
if (self.sliderLastPos) {
|
||
|
$.each(self.instance.slides, function(index, slide) {
|
||
|
var pos = slide.pos - self.instance.currPos;
|
||
|
|
||
|
$.fancybox.setTranslate(slide.$slide, {
|
||
|
top: self.sliderLastPos.top,
|
||
|
left: self.sliderLastPos.left + pos * self.canvasWidth + pos * slide.opts.gutter
|
||
|
});
|
||
|
});
|
||
|
|
||
|
self.$container.addClass("fancybox-is-sliding");
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
Guestures.prototype.onPan = function() {
|
||
|
var self = this;
|
||
|
|
||
|
// Prevent accidental movement (sometimes, when tapping casually, finger can move a bit)
|
||
|
if (distance(self.newPoints[0], self.realPoints[0]) < ($.fancybox.isMobile ? 10 : 5)) {
|
||
|
self.startPoints = self.newPoints;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
self.canTap = false;
|
||
|
|
||
|
self.contentLastPos = self.limitMovement();
|
||
|
|
||
|
if (self.requestId) {
|
||
|
cancelAFrame(self.requestId);
|
||
|
|
||
|
self.requestId = null;
|
||
|
}
|
||
|
|
||
|
self.requestId = requestAFrame(function() {
|
||
|
$.fancybox.setTranslate(self.$content, self.contentLastPos);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// Make panning sticky to the edges
|
||
|
Guestures.prototype.limitMovement = function() {
|
||
|
var self = this;
|
||
|
|
||
|
var canvasWidth = self.canvasWidth;
|
||
|
var canvasHeight = self.canvasHeight;
|
||
|
|
||
|
var distanceX = self.distanceX;
|
||
|
var distanceY = self.distanceY;
|
||
|
|
||
|
var contentStartPos = self.contentStartPos;
|
||
|
|
||
|
var currentOffsetX = contentStartPos.left;
|
||
|
var currentOffsetY = contentStartPos.top;
|
||
|
|
||
|
var currentWidth = contentStartPos.width;
|
||
|
var currentHeight = contentStartPos.height;
|
||
|
|
||
|
var minTranslateX, minTranslateY, maxTranslateX, maxTranslateY, newOffsetX, newOffsetY;
|
||
|
|
||
|
if (currentWidth > canvasWidth) {
|
||
|
newOffsetX = currentOffsetX + distanceX;
|
||
|
} else {
|
||
|
newOffsetX = currentOffsetX;
|
||
|
}
|
||
|
|
||
|
newOffsetY = currentOffsetY + distanceY;
|
||
|
|
||
|
// Slow down proportionally to traveled distance
|
||
|
minTranslateX = Math.max(0, canvasWidth * 0.5 - currentWidth * 0.5);
|
||
|
minTranslateY = Math.max(0, canvasHeight * 0.5 - currentHeight * 0.5);
|
||
|
|
||
|
maxTranslateX = Math.min(canvasWidth - currentWidth, canvasWidth * 0.5 - currentWidth * 0.5);
|
||
|
maxTranslateY = Math.min(canvasHeight - currentHeight, canvasHeight * 0.5 - currentHeight * 0.5);
|
||
|
|
||
|
// ->
|
||
|
if (distanceX > 0 && newOffsetX > minTranslateX) {
|
||
|
newOffsetX = minTranslateX - 1 + Math.pow(-minTranslateX + currentOffsetX + distanceX, 0.8) || 0;
|
||
|
}
|
||
|
|
||
|
// <-
|
||
|
if (distanceX < 0 && newOffsetX < maxTranslateX) {
|
||
|
newOffsetX = maxTranslateX + 1 - Math.pow(maxTranslateX - currentOffsetX - distanceX, 0.8) || 0;
|
||
|
}
|
||
|
|
||
|
// \/
|
||
|
if (distanceY > 0 && newOffsetY > minTranslateY) {
|
||
|
newOffsetY = minTranslateY - 1 + Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8) || 0;
|
||
|
}
|
||
|
|
||
|
// /\
|
||
|
if (distanceY < 0 && newOffsetY < maxTranslateY) {
|
||
|
newOffsetY = maxTranslateY + 1 - Math.pow(maxTranslateY - currentOffsetY - distanceY, 0.8) || 0;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
top: newOffsetY,
|
||
|
left: newOffsetX
|
||
|
};
|
||
|
};
|
||
|
|
||
|
Guestures.prototype.limitPosition = function(newOffsetX, newOffsetY, newWidth, newHeight) {
|
||
|
var self = this;
|
||
|
|
||
|
var canvasWidth = self.canvasWidth;
|
||
|
var canvasHeight = self.canvasHeight;
|
||
|
|
||
|
if (newWidth > canvasWidth) {
|
||
|
newOffsetX = newOffsetX > 0 ? 0 : newOffsetX;
|
||
|
newOffsetX = newOffsetX < canvasWidth - newWidth ? canvasWidth - newWidth : newOffsetX;
|
||
|
} else {
|
||
|
// Center horizontally
|
||
|
newOffsetX = Math.max(0, canvasWidth / 2 - newWidth / 2);
|
||
|
}
|
||
|
|
||
|
if (newHeight > canvasHeight) {
|
||
|
newOffsetY = newOffsetY > 0 ? 0 : newOffsetY;
|
||
|
newOffsetY = newOffsetY < canvasHeight - newHeight ? canvasHeight - newHeight : newOffsetY;
|
||
|
} else {
|
||
|
// Center vertically
|
||
|
newOffsetY = Math.max(0, canvasHeight / 2 - newHeight / 2);
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
top: newOffsetY,
|
||
|
left: newOffsetX
|
||
|
};
|
||
|
};
|
||
|
|
||
|
Guestures.prototype.onZoom = function() {
|
||
|
var self = this;
|
||
|
|
||
|
// Calculate current distance between points to get pinch ratio and new width and height
|
||
|
var contentStartPos = self.contentStartPos;
|
||
|
|
||
|
var currentWidth = contentStartPos.width;
|
||
|
var currentHeight = contentStartPos.height;
|
||
|
|
||
|
var currentOffsetX = contentStartPos.left;
|
||
|
var currentOffsetY = contentStartPos.top;
|
||
|
|
||
|
var endDistanceBetweenFingers = distance(self.newPoints[0], self.newPoints[1]);
|
||
|
|
||
|
var pinchRatio = endDistanceBetweenFingers / self.startDistanceBetweenFingers;
|
||
|
|
||
|
var newWidth = Math.floor(currentWidth * pinchRatio);
|
||
|
var newHeight = Math.floor(currentHeight * pinchRatio);
|
||
|
|
||
|
// This is the translation due to pinch-zooming
|
||
|
var translateFromZoomingX = (currentWidth - newWidth) * self.percentageOfImageAtPinchPointX;
|
||
|
var translateFromZoomingY = (currentHeight - newHeight) * self.percentageOfImageAtPinchPointY;
|
||
|
|
||
|
// Point between the two touches
|
||
|
var centerPointEndX = (self.newPoints[0].x + self.newPoints[1].x) / 2 - $(window).scrollLeft();
|
||
|
var centerPointEndY = (self.newPoints[0].y + self.newPoints[1].y) / 2 - $(window).scrollTop();
|
||
|
|
||
|
// And this is the translation due to translation of the centerpoint
|
||
|
// between the two fingers
|
||
|
var translateFromTranslatingX = centerPointEndX - self.centerPointStartX;
|
||
|
var translateFromTranslatingY = centerPointEndY - self.centerPointStartY;
|
||
|
|
||
|
// The new offset is the old/current one plus the total translation
|
||
|
var newOffsetX = currentOffsetX + (translateFromZoomingX + translateFromTranslatingX);
|
||
|
var newOffsetY = currentOffsetY + (translateFromZoomingY + translateFromTranslatingY);
|
||
|
|
||
|
var newPos = {
|
||
|
top: newOffsetY,
|
||
|
left: newOffsetX,
|
||
|
scaleX: pinchRatio,
|
||
|
scaleY: pinchRatio
|
||
|
};
|
||
|
|
||
|
self.canTap = false;
|
||
|
|
||
|
self.newWidth = newWidth;
|
||
|
self.newHeight = newHeight;
|
||
|
|
||
|
self.contentLastPos = newPos;
|
||
|
|
||
|
if (self.requestId) {
|
||
|
cancelAFrame(self.requestId);
|
||
|
|
||
|
self.requestId = null;
|
||
|
}
|
||
|
|
||
|
self.requestId = requestAFrame(function() {
|
||
|
$.fancybox.setTranslate(self.$content, self.contentLastPos);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
Guestures.prototype.ontouchend = function(e) {
|
||
|
var self = this;
|
||
|
var dMs = Math.max(new Date().getTime() - self.startTime, 1);
|
||
|
|
||
|
var swiping = self.isSwiping;
|
||
|
var panning = self.isPanning;
|
||
|
var zooming = self.isZooming;
|
||
|
var scrolling = self.isScrolling;
|
||
|
|
||
|
self.endPoints = getPointerXY(e);
|
||
|
|
||
|
self.$container.removeClass("fancybox-controls--isGrabbing");
|
||
|
|
||
|
$(document).off(".fb.touch");
|
||
|
|
||
|
document.removeEventListener("scroll", self.onscroll, true);
|
||
|
|
||
|
if (self.requestId) {
|
||
|
cancelAFrame(self.requestId);
|
||
|
|
||
|
self.requestId = null;
|
||
|
}
|
||
|
|
||
|
self.isSwiping = false;
|
||
|
self.isPanning = false;
|
||
|
self.isZooming = false;
|
||
|
self.isScrolling = false;
|
||
|
|
||
|
self.instance.isDragging = false;
|
||
|
|
||
|
if (self.canTap) {
|
||
|
return self.onTap(e);
|
||
|
}
|
||
|
|
||
|
self.speed = 366;
|
||
|
|
||
|
// Speed in px/ms
|
||
|
self.velocityX = self.distanceX / dMs * 0.5;
|
||
|
self.velocityY = self.distanceY / dMs * 0.5;
|
||
|
|
||
|
self.speedX = Math.max(self.speed * 0.5, Math.min(self.speed * 1.5, 1 / Math.abs(self.velocityX) * self.speed));
|
||
|
|
||
|
if (panning) {
|
||
|
self.endPanning();
|
||
|
} else if (zooming) {
|
||
|
self.endZooming();
|
||
|
} else {
|
||
|
self.endSwiping(swiping, scrolling);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
Guestures.prototype.endSwiping = function(swiping, scrolling) {
|
||
|
var self = this,
|
||
|
ret = false,
|
||
|
len = self.instance.group.length;
|
||
|
|
||
|
self.sliderLastPos = null;
|
||
|
|
||
|
// Close if swiped vertically / navigate if horizontally
|
||
|
if (swiping == "y" && !scrolling && Math.abs(self.distanceY) > 50) {
|
||
|
// Continue vertical movement
|
||
|
$.fancybox.animate(
|
||
|
self.instance.current.$slide,
|
||
|
{
|
||
|
top: self.sliderStartPos.top + self.distanceY + self.velocityY * 150,
|
||
|
opacity: 0
|
||
|
},
|
||
|
200
|
||
|
);
|
||
|
|
||
|
ret = self.instance.close(true, 200);
|
||
|
} else if (swiping == "x" && self.distanceX > 50 && len > 1) {
|
||
|
ret = self.instance.previous(self.speedX);
|
||
|
} else if (swiping == "x" && self.distanceX < -50 && len > 1) {
|
||
|
ret = self.instance.next(self.speedX);
|
||
|
}
|
||
|
|
||
|
if (ret === false && (swiping == "x" || swiping == "y")) {
|
||
|
if (scrolling || len < 2) {
|
||
|
self.instance.centerSlide(self.instance.current, 150);
|
||
|
} else {
|
||
|
self.instance.jumpTo(self.instance.current.index);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
self.$container.removeClass("fancybox-is-sliding");
|
||
|
};
|
||
|
|
||
|
// Limit panning from edges
|
||
|
// ========================
|
||
|
Guestures.prototype.endPanning = function() {
|
||
|
var self = this;
|
||
|
var newOffsetX, newOffsetY, newPos;
|
||
|
|
||
|
if (!self.contentLastPos) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (self.opts.momentum === false) {
|
||
|
newOffsetX = self.contentLastPos.left;
|
||
|
newOffsetY = self.contentLastPos.top;
|
||
|
} else {
|
||
|
// Continue movement
|
||
|
newOffsetX = self.contentLastPos.left + self.velocityX * self.speed;
|
||
|
newOffsetY = self.contentLastPos.top + self.velocityY * self.speed;
|
||
|
}
|
||
|
|
||
|
newPos = self.limitPosition(newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height);
|
||
|
|
||
|
newPos.width = self.contentStartPos.width;
|
||
|
newPos.height = self.contentStartPos.height;
|
||
|
|
||
|
$.fancybox.animate(self.$content, newPos, 330);
|
||
|
};
|
||
|
|
||
|
Guestures.prototype.endZooming = function() {
|
||
|
var self = this;
|
||
|
|
||
|
var current = self.instance.current;
|
||
|
|
||
|
var newOffsetX, newOffsetY, newPos, reset;
|
||
|
|
||
|
var newWidth = self.newWidth;
|
||
|
var newHeight = self.newHeight;
|
||
|
|
||
|
if (!self.contentLastPos) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
newOffsetX = self.contentLastPos.left;
|
||
|
newOffsetY = self.contentLastPos.top;
|
||
|
|
||
|
reset = {
|
||
|
top: newOffsetY,
|
||
|
left: newOffsetX,
|
||
|
width: newWidth,
|
||
|
height: newHeight,
|
||
|
scaleX: 1,
|
||
|
scaleY: 1
|
||
|
};
|
||
|
|
||
|
// Reset scalex/scaleY values; this helps for perfomance and does not break animation
|
||
|
$.fancybox.setTranslate(self.$content, reset);
|
||
|
|
||
|
if (newWidth < self.canvasWidth && newHeight < self.canvasHeight) {
|
||
|
self.instance.scaleToFit(150);
|
||
|
} else if (newWidth > current.width || newHeight > current.height) {
|
||
|
self.instance.scaleToActual(self.centerPointStartX, self.centerPointStartY, 150);
|
||
|
} else {
|
||
|
newPos = self.limitPosition(newOffsetX, newOffsetY, newWidth, newHeight);
|
||
|
|
||
|
// Switch from scale() to width/height or animation will not work correctly
|
||
|
$.fancybox.setTranslate(self.$content, $.fancybox.getTranslate(self.$content));
|
||
|
|
||
|
$.fancybox.animate(self.$content, newPos, 150);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Guestures.prototype.onTap = function(e) {
|
||
|
var self = this;
|
||
|
var $target = $(e.target);
|
||
|
|
||
|
var instance = self.instance;
|
||
|
var current = instance.current;
|
||
|
|
||
|
var endPoints = (e && getPointerXY(e)) || self.startPoints;
|
||
|
|
||
|
var tapX = endPoints[0] ? endPoints[0].x - $(window).scrollLeft() - self.stagePos.left : 0;
|
||
|
var tapY = endPoints[0] ? endPoints[0].y - $(window).scrollTop() - self.stagePos.top : 0;
|
||
|
|
||
|
var where;
|
||
|
|
||
|
var process = function(prefix) {
|
||
|
var action = current.opts[prefix];
|
||
|
|
||
|
if ($.isFunction(action)) {
|
||
|
action = action.apply(instance, [current, e]);
|
||
|
}
|
||
|
|
||
|
if (!action) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
switch (action) {
|
||
|
case "close":
|
||
|
instance.close(self.startEvent);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case "toggleControls":
|
||
|
instance.toggleControls(true);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case "next":
|
||
|
instance.next();
|
||
|
|
||
|
break;
|
||
|
|
||
|
case "nextOrClose":
|
||
|
if (instance.group.length > 1) {
|
||
|
instance.next();
|
||
|
} else {
|
||
|
instance.close(self.startEvent);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case "zoom":
|
||
|
if (current.type == "image" && (current.isLoaded || current.$ghost)) {
|
||
|
if (instance.canPan()) {
|
||
|
instance.scaleToFit();
|
||
|
} else if (instance.isScaledDown()) {
|
||
|
instance.scaleToActual(tapX, tapY);
|
||
|
} else if (instance.group.length < 2) {
|
||
|
instance.close(self.startEvent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Ignore right click
|
||
|
if (e.originalEvent && e.originalEvent.button == 2) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Skip if clicked on the scrollbar
|
||
|
if (!$target.is("img") && tapX > $target[0].clientWidth + $target.offset().left) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Check where is clicked
|
||
|
if ($target.is(".fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container")) {
|
||
|
where = "Outside";
|
||
|
} else if ($target.is(".fancybox-slide")) {
|
||
|
where = "Slide";
|
||
|
} else if (
|
||
|
instance.current.$content &&
|
||
|
instance.current.$content
|
||
|
.find($target)
|
||
|
.addBack()
|
||
|
.filter($target).length
|
||
|
) {
|
||
|
where = "Content";
|
||
|
} else {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Check if this is a double tap
|
||
|
if (self.tapped) {
|
||
|
// Stop previously created single tap
|
||
|
clearTimeout(self.tapped);
|
||
|
self.tapped = null;
|
||
|
|
||
|
// Skip if distance between taps is too big
|
||
|
if (Math.abs(tapX - self.tapX) > 50 || Math.abs(tapY - self.tapY) > 50) {
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
// OK, now we assume that this is a double-tap
|
||
|
process("dblclick" + where);
|
||
|
} else {
|
||
|
// Single tap will be processed if user has not clicked second time within 300ms
|
||
|
// or there is no need to wait for double-tap
|
||
|
self.tapX = tapX;
|
||
|
self.tapY = tapY;
|
||
|
|
||
|
if (current.opts["dblclick" + where] && current.opts["dblclick" + where] !== current.opts["click" + where]) {
|
||
|
self.tapped = setTimeout(function() {
|
||
|
self.tapped = null;
|
||
|
|
||
|
process("click" + where);
|
||
|
}, 500);
|
||
|
} else {
|
||
|
process("click" + where);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
$(document).on("onActivate.fb", function(e, instance) {
|
||
|
if (instance && !instance.Guestures) {
|
||
|
instance.Guestures = new Guestures(instance);
|
||
|
}
|
||
|
});
|
||
|
})(window, document, window.jQuery || jQuery);
|