Tutorial 1: JQuery Zoom Effect

A plugin to enlarge images on touch, click, or mouseover.

Domes of Saint Basil's Cathedral

Hover

Moto racers on the ice are taking left turn

Grab

Winter lake view from top in the Silver Star resort

Click to activate

little squirrel eating nuts on the trail

Click to toggle

Photos used in this demo: Natalia Korobenko


Instructions

Zoom appends html inside the element it is assigned to. This excludes img elements (see below).

  // Example:
$(document).ready(function(){
  $('a.photo').zoom({url: 'photo-big.jpg'});
});

// Using Colorbox with Zoom
$(document).ready(function(){
  $('a.photo').zoom({
    url: 'photo-big.jpg', 
    callback: function(){
      $(this).colorbox({href: this.src});
    }
  });
});

To use zoom with img elements, they will need to be wrapped with another element. It is impossible to read some layout related CSS styles from JavaScript (percent-based width and height, margins set to auto, etc.) so the safe thing to do is to defer this change to individual site owners. The following is all that is needed in some cases:

$(document).ready(function(){
  $('img')
    .wrap('')
    .css('display', 'block')
    .parent()
    .zoom();
});

Removing Zoom

Trigger the zoom.destroy event to remove zoom from an element:

$('#example').zoom(); // add zoom
$('#example').trigger('zoom.destroy'); // remove zoom

HTML

  <div class="demo_container">
 
	<span class='zoom' id='ex1'>
		<img src="images/saint_basils_cathedral.jpg" width="300" height="auto"/>
		<h4>Hover</h4>
	</span>
    
	<span class='zoom' id='ex2'>
		<img src="images/speedway.JPG" width="300" height="auto"/>
		<h4>Grab</h4>
	</span>
    
	<span class='zoom' id='ex3'>
		<img src="images/winter_silver_star.JPG" width="300" />
		<h4>Click to activate</h4>
	</span>
    
	<span class='zoom' id='ex4'>
		<img src="images/squirrel.JPG" width="300" height="auto"/>
		<h4>Click to toggle</h4>
	</span>
    
   </div>

The CSS

Let's style it up!

.demo_container {
	width: 670px;
	margin: 0 auto;
}

.zoom {
display:inline-block;
position: relative;
clear: both;
margin: 15px;
border: 1px solid #333;
		}
		
/* magnifying glass icon */
.zoom:after {
	content:'';
	display:block; 
	width:33px; 
	height:33px; 
	position:absolute; 
	top:0;
	right:0;
	background:url(../images/icon.png);
		}

.zoom img {
display: block;
}

.zoom img::selection {
	 background-color: transparent;
	  }


#ex2 img:hover {
	 cursor: url(../images/grab.cur), default; 
	 }
	 
#ex2 img:active {
	 cursor: url(../images/grabbed.cur), default; 
	 }


JavaScript

	
(function ($) {
	var defaults = {
		url: false,
		callback: false,
		target: false,
		duration: 120,
		on: 'mouseover', // other options: grab, click, toggle
		touch: true, // enables a touch fallback
		onZoomIn: false,
		onZoomOut: false,
		magnify: 1
	};

	// Core Zoom Logic, independent of event listeners.
	$.zoom = function(target, source, img, magnify) {
		var targetHeight,
			targetWidth,
			sourceHeight,
			sourceWidth,
			xRatio,
			yRatio,
			offset,
			position = $(target).css('position'),
			$source = $(source);

// The parent element needs positioning so that the zoomed element
// can be correctly positioned within.
target.style.position = /(absolute|fixed)/.test(position) ? position : 'relative';
	target.style.overflow = 'hidden';

		img.style.width = img.style.height = '';

		$(img)
			.addClass('zoomImg')
			.css({
				position: 'absolute',
				top: 0,
				left: 0,
				opacity: 0,
				width: img.width * magnify,
				height: img.height * magnify,
				border: 'none',
				maxWidth: 'none',
				maxHeight: 'none'
			})
			.appendTo(target);

		return {
			init: function() {
				targetWidth = $(target).outerWidth();
				targetHeight = $(target).outerHeight();

				if (source === target) {
					sourceWidth = targetWidth;
					sourceHeight = targetHeight;
				} else {
					sourceWidth = $source.outerWidth();
					sourceHeight = $source.outerHeight();
				}

				xRatio = (img.width - targetWidth) / sourceWidth;
				yRatio = (img.height - targetHeight) / sourceHeight;

				offset = $source.offset();
			},
			move: function (e) {
				var left = (e.pageX - offset.left),
					top = (e.pageY - offset.top);

				top = Math.max(Math.min(top, sourceHeight), 0);
				left = Math.max(Math.min(left, sourceWidth), 0);

				img.style.left = (left * -xRatio) + 'px';
				img.style.top = (top * -yRatio) + 'px';
			}
		};
	};

	$.fn.zoom = function (options) {
		return this.each(function () {
			var
			settings = $.extend({}, defaults, options || {}),
			//target will display the zoomed image
			target = settings.target || this,
			//source will provide zoom location info (thumbnail)
			source = this,
			$source = $(source),
			img = document.createElement('img'),
			$img = $(img),
			mousemove = 'mousemove.zoom',
			clicked = false,
			touched = false,
			$urlElement;

// If a url wasn't specified, look for an image element.
			if (!settings.url) {
			$urlElement = $source.find('img');
		if ($urlElement[0]) {
settings.url = $urlElement.data('src') || $urlElement.attr('src');
		}
		if (!settings.url) {
		return;
		}
		}

(function(){
	var position = target.style.position;
	var overflow = target.style.overflow;

		$source.one('zoom.destroy', function(){
		$source.off(".zoom");
		target.style.position = position;
		target.style.overflow = overflow;
		$img.remove();
		});
				
	}());

	img.onload = function () {
	var zoom = $.zoom(target, source, img, settings.magnify);

		function start(e) {
		zoom.init();
		zoom.move(e);

// Skip the fade-in for IE8 and lower since it chokes on fading-in
// and changing position based on mousemovement at the same time.
$img.stop()
.fadeTo($.support.opacity ? settings.duration : 0, 1, $.isFunction(settings.onZoomIn)
 ? settings.onZoomIn.call(img) : false);
	}

	function stop() {
		$img.stop()
.fadeTo(settings.duration, 0, 
$.isFunction(settings.onZoomOut) 
     ? settings.onZoomOut.call(img) : false);
				}

    // Mouse events
    if (settings.on === 'grab') {
      $source
        .on('mousedown.zoom',
           function (e) {
          if (e.which === 1) {
      $(document).one('mouseup.zoom',
           function () {
               stop();

       $(document).off(mousemove, zoom.move);
           }
          );

                  start(e);

         $(document).on(mousemove, zoom.move);

                e.preventDefault();
               }
             }
            );
    } else if (settings.on === 'click') {
       $source.on('click.zoom',
        function (e) {
         if (clicked) {
  // bubble the event up to the document to trigger the unbind.
            return;
             } else {
              clicked = true;
              start(e);
              $(document).on(mousemove, zoom.move);
             $(document).one('click.zoom',
            function () {
             stop();
            clicked = false;
            $(document).off(mousemove, zoom.move);
           }
          );
          return false;
           }
          }
        );
    } else if (settings.on === 'toggle') {
        $source.on('click.zoom',
            function (e) {
                if (clicked) {
                    stop();
                } else {
                    start(e);
                }
                clicked = !clicked;
            }
        );
    } else if (settings.on === 'mouseover') {
        zoom.init(); 
 // Preemptively call init because IE7 will
 // fire the mousemove handler before the hover handler.

        $source
            .on('mouseenter.zoom', start)
            .on('mouseleave.zoom', stop)
            .on(mousemove, zoom.move);
    }

    // Touch fallback
    if (settings.touch) {
        $source
            .on('touchstart.zoom', function (e) {
                e.preventDefault();
                if (touched) {
                    touched = false;
                    stop();
                } else {
                    touched = true;
                    start( e.originalEvent.touches[0] || e.originalEvent.changedTouches[0] );
                }
            })
            .on('touchmove.zoom', function (e) {
                e.preventDefault();
                zoom.move( e.originalEvent.touches[0] || e.originalEvent.changedTouches[0] );
            });
    }
				
				if ($.isFunction(settings.callback)) {
					settings.callback.call(img);
				}
			};

			img.src = settings.url;
		});
	};

	$.fn.zoom.defaults = defaults;
}(window.jQuery));
		

Don't forget to include javascript links in your code!

<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'></script>
	<script src="js/zoom_js.js"></script>

Your gallery is now ready to be posted!