I'm looking for a Javascript plugin allowing me to magnify zoom on two images at the same time. This would apply as an action on two twin images.
I recently found a script called jQuery BUP but it's unusable and doesn't work and my skills aren't good enough to debug it.
So I took a simple magnify zoom plugin and I wanted to adapt it to give the expected result but I can't.
Here is my JSFiddle : https://jsfiddle.net/Mackgregor/pjLafsm0/3/
(function($) {
$.fn.magnify = function(oOptions) {
// Default options
oOptions = $.extend({
'src': '',
'speed': 100,
'timeout': -1,
'touchBottomOffset': 0,
'finalWidth': null,
'finalHeight': null,
'magnifiedWidth': null,
'magnifiedHeight': null,
'limitBounds': false,
'mobileCloseEvent': 'touchstart',
'afterLoad': function(){}
}, oOptions);
var $that = this, // Preserve scope
$html = $('html'),
// Initiate
init = function(el) {
var $image = $(el),
$anchor = $image.closest('a'),
oDataAttr = {};
// Get data attributes
for (var i in oOptions) {
oDataAttr[i] = $image.attr('data-magnify-' + i.toLowerCase());
}
// Disable zooming if no valid large image source
var sZoomSrc = oDataAttr['src'] || oOptions['src'] || $anchor.attr('href') || '';
if (!sZoomSrc) return;
var $container,
$lens,
nImageWidth,
nImageHeight,
nMagnifiedWidth,
nMagnifiedHeight,
nLensWidth,
nLensHeight,
nBoundX = 0,
nBoundY = 0,
nPosX, nPosY, // Absolute cursor position
nX, nY, // Relative cursor position
oContainerOffset, // Relative to document
oImageOffset, // Relative to container
// Get true offsets
getOffset = function() {
var o = $container.offset();
// Store offsets from container border to image inside
// NOTE: .offset() does NOT take into consideration image border and padding.
oImageOffset = {
'top': ($image.offset().top-o.top) + parseInt($image.css('border-top-width')) + parseInt($image.css('padding-top')),
'left': ($image.offset().left-o.left) + parseInt($image.css('border-left-width')) + parseInt($image.css('padding-left'))
};
o.top += oImageOffset['top'];
o.left += oImageOffset['left'];
return o;
},
// Hide the lens
hideLens = function() {
if ($lens.is(':visible')) $lens.fadeOut(oOptions['speed'], function() {
$html.removeClass('magnifying').trigger('magnifyend'); // Reset overflow-x
});
},
moveLens = function(e) {
// Reinitialize if image initially hidden
if (!nImageHeight) {
refresh();
return;
}
if (e) {
e.preventDefault();
// Save last coordinates in case we need to call this function directly (required when
// updating magnifiedWidth/magnifiedHeight while the lens is visible).
nPosX = e.pageX || e.originalEvent.touches[0].pageX;
nPosY = e.pageY || e.originalEvent.touches[0].pageY;
$image.data('lastPos', {
'x': nPosX,
'y': nPosY
});
} else {
nPosX = $image.data('lastPos').x;
nPosY = $image.data('lastPos').y;
}
// x/y coordinates of the mouse pointer or touch point. This is the position of
// .magnify relative to the document.
//
// We deduct the positions of .magnify from the mouse or touch positions relative to
// the document to get the mouse or touch positions relative to the container.
nX = nPosX - oContainerOffset['left'],
nY = (nPosY - oContainerOffset['top']) - oOptions['touchBottomOffset'];
// Toggle magnifying lens
if (!$lens.is(':animated')) {
if (nX>nBoundX && nX<nImageWidth-nBoundX && nY>nBoundY && nY<nImageHeight-nBoundY) {
if ($lens.is(':hidden')) {
$html.addClass('magnifying').trigger('magnifystart'); // Hide overflow-x while zooming
$lens.fadeIn(oOptions['speed']);
}
} else {
hideLens();
}
}
if ($lens.is(':visible')) {
// Move the magnifying lens with the mouse
var sBgPos = '';
if (nMagnifiedWidth && nMagnifiedHeight) {
// Change the background position of .magnify-lens according to the position of
// the mouse over the .magnify-image image. This allows us to get the ratio of
// the pixel under the mouse pointer with respect to the image and use that to
// position the large image inside the magnifying lens.
var nRatioX = -Math.round(nX/nImageWidth*nMagnifiedWidth-nLensWidth/2),
nRatioY = -Math.round(nY/nImageHeight*nMagnifiedHeight-nLensHeight/2);
if (oOptions['limitBounds']) {
// Enforce bounds to ensure only image is visible in lens
var nBoundRight = -Math.round((nImageWidth-nBoundX)/nImageWidth*nMagnifiedWidth-nLensWidth/2),
nBoundBottom = -Math.round((nImageHeight-nBoundY)/nImageHeight*nMagnifiedHeight-nLensHeight/2);
// Left and right edges
if (nRatioX>0) nRatioX = 0;
else if (nRatioX<nBoundRight) nRatioX = nBoundRight;
// Top and bottom edges
if (nRatioY>0) nRatioY = 0;
else if (nRatioY<nBoundBottom) nRatioY = nBoundBottom;
}
sBgPos = nRatioX + 'px ' + nRatioY + 'px';
}
// Now the lens moves with the mouse. The logic is to deduct half of the lens's
// width and height from the mouse coordinates to place it with its center at the
// mouse coordinates. If you hover on the image now, you should see the magnifying
// lens in action.
$lens.css({
'top': Math.round(nY-nLensHeight/2) + oImageOffset['top'] + 'px',
'left': Math.round(nX-nLensWidth/2) + oImageOffset['left'] + 'px',
'background-position': sBgPos
});
}
};
// Data attributes have precedence over options object
if (!isNaN(+oDataAttr['speed'])) oOptions['speed'] = +oDataAttr['speed'];
if (!isNaN(+oDataAttr['timeout'])) oOptions['timeout'] = +oDataAttr['timeout'];
if (!isNaN(+oDataAttr['finalWidth'])) oOptions['finalWidth'] = +oDataAttr['finalWidth'];
if (!isNaN(+oDataAttr['finalHeight'])) oOptions['finalHeight'] = +oDataAttr['finalHeight'];
if (!isNaN(+oDataAttr['magnifiedWidth'])) oOptions['magnifiedWidth'] = +oDataAttr['magnifiedWidth'];
if (!isNaN(+oDataAttr['magnifiedHeight'])) oOptions['magnifiedHeight'] = +oDataAttr['magnifiedHeight'];
if (oDataAttr['limitBounds']==='true') oOptions['limitBounds'] = true;
if (typeof window[oDataAttr['afterLoad']]==='function') oOptions.afterLoad = window[oDataAttr['afterLoad']];
// Implement touch point bottom offset only on mobile devices
if (/\b(Android|BlackBerry|IEMobile|iPad|iPhone|Mobile|Opera Mini)\b/.test(navigator.userAgent)) {
if (!isNaN(+oDataAttr['touchBottomOffset'])) oOptions['touchBottomOffset'] = +oDataAttr['touchBottomOffset'];
} else {
oOptions['touchBottomOffset'] = 0;
}
// Save any inline styles for resetting
$image.data('originalStyle', $image.attr('style'));
// Activate magnification:
// 1. Try to get large image dimensions
// 2. Proceed only if able to get large image dimensions OK
// [1] Calculate the native (magnified) image dimensions. The zoomed version is only shown
// after the native dimensions are available. To get the actual dimensions we have to create
// this image object.
var elZoomImage = new Image();
$(elZoomImage).on({
'load': function() {
// [2] Got image dimensions OK.
// Fix overlap bug at the edges during magnification
$image.css('display', 'block');
// Create container div if necessary
if (!$image.parent('.magnify').length) {
$image.wrap('<div class="magnify"></div>');
}
$container = $image.parent('.magnify');
// Create the magnifying lens div if necessary
if ($image.prev('.magnify-lens').length) {
$container.children('.magnify-lens').css('background-image', 'url(\'' + sZoomSrc + '\')');
} else {
$image.before('<div class="magnify-lens loading" style="background:url(\'' + sZoomSrc + '\') 0 0 no-repeat"></div>');
}
$lens = $container.children('.magnify-lens');
// Remove the "Loading..." text
$lens.removeClass('loading');
// Cache dimensions and offsets for improved performance
// NOTE: This code is inside the load() function, which is important. The width and
// height of the object would return 0 if accessed before the image is fully loaded.
nImageWidth = oOptions['finalWidth'] || $image.width();
nImageHeight = oOptions['finalHeight'] || $image.height();
nMagnifiedWidth = oOptions['magnifiedWidth'] || elZoomImage.width;
nMagnifiedHeight = oOptions['magnifiedHeight'] || elZoomImage.height;
nLensWidth = $lens.width();
nLensHeight = $lens.height();
oContainerOffset = getOffset(); // Required by refresh()
// Set zoom boundaries
if (oOptions['limitBounds']) {
nBoundX = (nLensWidth/2) / (nMagnifiedWidth/nImageWidth);
nBoundY = (nLensHeight/2) / (nMagnifiedHeight/nImageHeight);
}
// Enforce non-native large image size?
if (nMagnifiedWidth!==elZoomImage.width || nMagnifiedHeight!==elZoomImage.height) {
$lens.css('background-size', nMagnifiedWidth + 'px ' + nMagnifiedHeight + 'px');
}
// Store zoom dimensions for mobile plugin
$image.data('zoomSize', {
'width': nMagnifiedWidth,
'height': nMagnifiedHeight
});
// Store mobile close event for mobile plugin
$container.data('mobileCloseEvent', oDataAttr['mobileCloseEvent'] || oOptions['mobileCloseEvent']);
// Clean up
elZoomImage = null;
// Execute callback
oOptions.afterLoad();
// Simulate a lens move to update positioning if magnifiedWidth/magnifiedHeight is
// updated while the lens is visible
if ($lens.is(':visible')) moveLens();
// Handle mouse movements
$container.off().on({
'mousemove touchmove': moveLens,
'mouseenter': function() {
// Need to update offsets here to support accordions
oContainerOffset = getOffset();
},
'mouseleave': hideLens
});
// Prevent magnifying lens from getting "stuck"
if (oOptions['timeout']>=0) {
$container.on('touchend', function() {
setTimeout(hideLens, oOptions['timeout']);
});
}
// Ensure lens is closed when tapping outside of it
$('body').not($container).on('touchstart', hideLens);
// Support image map click-throughs while zooming
var sUsemap = $image.attr('usemap');
if (sUsemap) {
var $map = $('map[name=' + sUsemap.slice(1) + ']');
// Image map needs to be on the same DOM level as image source
$image.after($map);
$container.click(function(e) {
// Trigger click on image below lens at current cursor position
if (e.clientX || e.clientY) {
$lens.hide();
var elPoint = document.elementFromPoint(
e.clientX || e.originalEvent.touches[0].clientX,
e.clientY || e.originalEvent.touches[0].clientY
);
if (elPoint.nodeName==='AREA') {
elPoint.click();
} else {
// Workaround for buggy implementation of elementFromPoint()
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1227469
$('area', $map).each(function() {
var a = $(this).attr('coords').split(',');
if (nX>=a[0] && nX<=a[2] && nY>=a[1] && nY<=a[3]) {
this.click();
return false;
}
});
}
}
});
}
if ($anchor.length) {
// Make parent anchor inline-block to have correct dimensions
$anchor.css('display', 'inline-block');
// Disable parent anchor if it's sourcing the large image
if ($anchor.attr('href') && !(oDataAttr['src'] || oOptions['src'])) {
$anchor.click(function(e) {
e.preventDefault();
});
}
}
},
'error': function() {
// Clean up
elZoomImage = null;
}
});
elZoomImage.src = sZoomSrc;
}, // END init()
// Simple debounce
nTimer = 0,
refresh = function() {
clearTimeout(nTimer);
nTimer = setTimeout(function() {
$that.destroy();
$that.magnify(oOptions);
}, 100);
};
/**
* Public Methods
*/
// Turn off zoom and reset to original state
this.destroy = function() {
this.each(function() {
var $this = $(this),
$lens = $this.prev('div.magnify-lens'),
sStyle = $this.data('originalStyle');
if ($this.parent('div.magnify').length && $lens.length) {
if (sStyle) $this.attr('style', sStyle);
else $this.removeAttr('style');
$this.unwrap();
$lens.remove();
}
});
// Unregister event handler
$(window).off('resize', refresh);
return $that;
}
// Handle window resizing
$(window).resize(refresh);
return this.each(function() {
// Initiate magnification powers
init(this);
});
};
}(jQuery));
// Calling the magnify
$(document).ready(function() {
$('.zoom').magnify();
});
Can anyone help me ?
Thank you in advance for your answers and have patience with those who don't have as much knowledge as you please ;)