Saturday, October 5, 2013

jQuery Plugin: modified Image Magnifier plugin for multiple images

I had a project requirement for an image magnifier for multiple images in a single page. The page will have a list of products where each product have an image magnifier as part of its listing.

I found this jQuery plugin called Easy Image Zoom among other plugins while googling for the term "image magnifier jquery".

The original jQuery plugin, demo and instructions are found on the plugin author's page.

The plugin was easy to use but only worked with just one image for each page.

So I modified the image magnifier plugin so that it will work with multiple images in one page. The plugin's javascript code with the annotated modifications is listed below. The code in blue text are the new codes and codes in red text are commented out codes.

/*
 * Easy Zoom 1.0 - jQuery plugin
 * written by Alen Grakalic
 * http://cssglobe.com/post/9711/jquery-plugin-easy-image-zoom
 *
 * Copyright (c) 2011 Alen Grakalic (http://cssglobe.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Built for jQuery library
 * http://jquery.com
 *
 */

 /*

 Required markup sample

 <a href="large.jpg"><img src="small.jpg" alt=""></a>

 */

(function($) {

$.fn.easyZoom = function(options){

var defaults = {
id: 'easy_zoom',
parent: 'body',
append: true,
preload: 'Loading...',
error: 'There has been a problem with loading the image.'
};

var obj;
var img = new Image();
var loaded = false;
var found = true;
var timeout;
var w1,w2,w3,w4,h1,h2,h3,h4,rw,rh;
var over = false;
//new code 
var hoveredLink;

var options = $.extend(defaults, options);

this.each(function(){

obj = this;
// works only for anchors
var tagName = this.tagName.toLowerCase();
if(tagName == 'a'){
/* - commented out this code because the img var only stores the image of the last <a> link element
var href = $(this).attr('href');
img.src = href + '?' + (new Date()).getTime() + ' =' + (new Date()).getTime();
$(img).error(function(){ found = false; })
img.onload = function(){
loaded = true;
img.onload=function(){};
};
*/
$(this)
.css('cursor','crosshair')
//.click(function(e){ e.preventDefault(); })
.click(function(){ hide(); })
.mouseover(function(e){ start(e, this); })
.mouseout(function(){ hide(); })
.mousemove(function(e){ move(e); })
};

});

function start(e, imgLink){
hide();

/* begin new code */
//assign mouseovered image link to global var hoveredLink
hoveredLink = imgLink;
//load the zoom image (big image) for the mouseovered image link
var href = imgLink.href;
img = new Image();
img.onload = function(){
loaded = true;
};
img.src = href;
$(img).error(function(){ found = false; })
/* end new code */

var zoom = $('<div id="'+ options.id +'">'+ options.preload +'</div>');
if(options.append) { zoom.appendTo(options.parent) } else { zoom.prependTo(options.parent) };
$('#'+ options.id).html('').append(options.preload);
if(!found){
error();
} else {
if(loaded){
show(e);
} else {
loop(e);
};
};
};

function loop(e){
if(loaded){
show(e);
clearTimeout(timeout);
} else {
timeout = setTimeout(function(){loop(e)},200);
};
};

function show(e){
over = true;
w1 = 0; h1 = 0; w2 = 0; h2 = 0; w3 = 0; h3 = 0; w4 = 0; h4 = 0; rw = 0; rh = 0;
$(img).css({'position':'absolute','top':'0','left':'0'});
//put the big image in the popup DIV
$('#'+ options.id).html('').append(img);
/* - commented out and replaced this code because $('img', obj) wrongly gets the last small image in the page
w1 = $('img', obj).width();
h1 = $('img', obj).height();
*/

/* begin new code */
/* use children[0] to get the thumb image because firstElementChild returns null in IE10 and
firstChild returns a text node in Chrome. children is a collection of just the child nodes that are elements */
//get small image properties
w1 = $(hoveredLink.children[0]).width();
h1 = $(hoveredLink.children[0]).height();
/* end new code */

//get popup zoom DIV properties
w2 = $('#'+ options.id).width();
h2 = $('#'+ options.id).height();

//get big image properties
w3 = $(img).width();
h3 = $(img).height();

//get difference between big image properties and  DIV (of big image) properties
w4 = w3 - w2;
h4 = h3 - h2;

//get ratio of w4 and h4 against small image properties
rw = w4/w1;
rh = h4/h1;

move(e);
};

function hide(){
over = false;
/* begin new code */
loaded = false;
found = true;
/* end new code */
$('#'+ options.id).remove();
};

function error(){
$('#'+ options.id).html(options.error);
};

function move(e){
if(over){
// target image movement
//var p = $('img',obj).offset();

//replaced code above with new code below to get the correct thumb image (small image link)
/* begin new code */
/* use children[0] to get the thumb image because firstElementChild returns null in IE10 and
firstChild returns a text node in Chrome. children is a collection of just the child nodes that are elements */
var thumbImg = hoveredLink.children[0];
var p = $(thumbImg).offset(); //get the 'top' and 'left' coordinates of the small image
/* end new code */

//pageX returns the mouse position relative to the LEFT edge of the document
//pl = difference between the mouse position and LEFT coordinate of the small image
var pl = e.pageX - p.left;

//pageY returns the mouse position relative to the TOP edge of the document
//pt = difference between the mouse position and TOP coordinate of the small image
var pt = e.pageY - p.top;

//rw is the RATIO of the big image width against the width of the zoom DIV (of big image)
//xl = the new LEFT coordinate of the big image
var xl = pl*rw;

//rh is the RATIO of the big image height against the height of the zoom DIV (of big image)
//xt = the new TOP coordinate of the big image
var xt = pt*rh;

xl = (xl>w4) ? w4 : xl;
xt = (xt>h4) ? h4 : xt;

//if big image is smaller than popup DIV container, center the image in the DIV
//else, do the image magnifier scroll
if (w4 < 0 && h4 < 0) {
//top property of big image = (Div height - big image height) / 2
var topVal = (h2-h3)/2;
$(img).css({'position':'relative', 'top':topVal, 'display':'block', 'margin':'0 auto'});
} else {
//$('#'+ options.id + ' img').css({'left':xl*(-1),'top':xt*(-1)});   --> original code replaced with the one below
$(img).css({'left':xl*(-1),'top':xt*(-1)});
}
};
/* begin new code */
//check if big image was loaded (is available)
if (!loaded) {
$('#'+ options.id).html('').append("Big image is not available");
};
/* end new code */
};

};

})(jQuery);



For this image magnifier to work, you need to put the following code inside the <head> tag of your page as shown below:

<head>
     <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
     <script type="text/javascript" src="easyzoom.js"></script>

     <script type="text/javascript">
          jQuery(function($){
             $('a.zoom').easyZoom();
          });
     </script>
</head>


You also need to use an anchor element using the small image linking to the big image with the following structure:

<a href="large.jpg" class="zoom"><img src="small.jpg" alt="Small image" /></a>


You may change the anchor's classname to any value but be sure to update the jQuery javascript in your <head> tag. So if you change the anchor's classname to 'bigZoom' be sure to update the jQuery script to:

     <script type="text/javascript">
          jQuery(function($){
             $('a.bigZoom').easyZoom();
          });
     </script>


You will also need to include the CSS style rules for the newly created image magnifier element with a default ID of  'easy_zoom' (see the plugin's javascript code for default ID).  In terms of CSS all you need to do is define the newly created image magnifier element’s size, position and appearance.

The plugin's author used the style rule below for his demo:

#easy_zoom{
width:600px;
height:400px;
border:5px solid #eee;
background:#fff;
color:#333;
position:absolute;
top:15px;
left:400px;
overflow:hidden;
-moz-box-shadow:0 0 10px #555;
-webkit-box-shadow:0 0 10px #555;
box-shadow:0 0 10px #555;
/* vertical and horizontal alignment used for preloader text */
line-height:400px;
text-align:center;
}


Your image should now have an image magnifier effect with these simple codes in your page.

Again, the demo and instructions are found in the plugin author's page.


Customization Example

There are several custom options you could use which are found in the link above.

Here is one example of using a different CSS style rule with an ID of 'zoomFromProductList'  for another image magnifier element.

All you need to do is update the jQuery javascript in your <head> tag as shown below.

     <script type="text/javascript">
          jQuery(function($){
             $('a.zoom').easyZoom({
id: 'zoomFromProductList'
});
          });
     </script>


Then add the new CSS style rule for ID 'zoomFromProductList' as shown below.

#zoomFromProductList {
width:600px;
height:400px;
border:5px solid #eee;
background:#fff;
color:#333;
position: fixed;
top: 30%;
left: 50%;
overflow:hidden;
-moz-box-shadow:0 0 10px #555;
-webkit-box-shadow:0 0 10px #555;
box-shadow:0 0 10px #555;
/* vertical and horizontal alignment used for preloader text */
line-height:400px;
text-align:center;
z-index: 1500;
}


That's it. I hope you find this image magnifier widget useful on your website.

No comments:

Post a Comment