multizoom.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. // Multi-Zoom Script (c)2012 John Davenport Scheuer
  2. // as first seen in http://www.dynamicdrive.com/forums/
  3. // username: jscheuer1 - This Notice Must Remain for Legal Use
  4. // requires: a modified version of Dynamic Drive's Featured Image Zoomer (w/ adjustable power) (included)
  5. /*Featured Image Zoomer (May 8th, 2010)
  6. * This notice must stay intact for usage
  7. * Author: Dynamic Drive at http://www.dynamicdrive.com/
  8. * Visit http://www.dynamicdrive.com/ for full source code
  9. */
  10. // Feb 21st, 2011: Script updated to v1.5, which now includes new feature by jscheuer1 (http://www.dynamicdrive.com/forums/member.php?u=2033) to show optional "magnifying lens" while over thumbnail image.
  11. // March 1st, 2011: Script updated to v1.51. Minor improvements to inner workings of script.
  12. // July 9th, 12': Script updated to v1.5.1, which fixes mouse wheel issue with script when used with a more recent version of jQuery.
  13. // Nov 5th, 2012: Unofficial update to v1.5.1m for integration with multi-zoom (adds multiple images to be zoomed via thumbnail activated image swapping)
  14. // Nov 28th, 2012: Version 2.1 w/Multi Zoom, updates - new features and bug fixes
  15. var featuredimagezoomer = { // the two options for Featured Image Zoomer:
  16. loadinggif: 'spinningred.gif', // full path or URL to "loading" gif
  17. magnifycursor: 'crosshair' // value for CSS's 'cursor' property when over the zoomable image
  18. };
  19. //////////////// No Need To Edit Beyond Here ////////////////
  20. //jQuery.noConflict();
  21. (function($){
  22. $('head').append('<style type="text/css">.featuredimagezoomerhidden {visibility: hidden!important;}</style>');
  23. $.fn.multizoomhide = function(){
  24. return $('<style type="text/css">' + this.selector + ' {visibility: hidden;}<\/style>').appendTo('head');
  25. };
  26. $.fn.addmultizoom = function(options){
  27. var indoptions = {largeimage: options.largeimage}, $imgObj = $(options.imgObj + ':not(".thumbs")'),
  28. $descArea = $(options.descArea), first = true, splitre = /, ?/;
  29. options = $.extend({
  30. speed: 'slow',
  31. initzoomablefade: true,
  32. zoomablefade: true
  33. }, options);
  34. function loadfunction(){
  35. var lnk = this, styleobj1 = {}, styleobj2 = {}, $nim, lnkd, lnkt, lnko, w, h;
  36. if((lnkd = lnk.getAttribute('data-dims'))){
  37. lnkd = lnkd.split(splitre);
  38. w = lnkd[0]; h = lnkd[1];
  39. }
  40. $(new Image()).error(function(){
  41. if(lnk.tagName && !options.notmulti){
  42. alert("Error: I couldn't find the image:\n\n" + lnk.href + ((lnkt = lnk.getAttribute('data-title'))? '\n\n"' + lnkt + '"' : ''));
  43. if((lnko = $imgObj.data('last-trigger'))){
  44. first = true;
  45. $(lnko).trigger('click');
  46. }
  47. }
  48. }).load(function(){
  49. var opacity = $imgObj.css('opacity'), combinedoptions = {}, $parent;
  50. if(isNaN(opacity)){opacity = 1;}
  51. if(options.notmulti || !indoptions.largeimage){
  52. w = options.width || $imgObj.width(); h = options.height || $imgObj.height();
  53. }
  54. $imgObj.attr('src', this.src).css({width: w || options.width || this.width, height: (h = +(h || options.height || this.height))});
  55. if($imgObj.data('added')) {$imgObj.data('added').remove()};
  56. $imgObj.data('last-trigger', lnk);
  57. if(options.imagevertcenter){styleobj1 = {top: ($imgObj.parent().innerHeight() - h) / 2};}
  58. $imgObj.css(styleobj1).addimagezoom($.extend(combinedoptions, options, indoptions))
  59. .data('added', $('.magnifyarea:last' + (combinedoptions.cursorshade? ', .cursorshade:last' : '') + ', .zoomstatus:last, .zoomtracker:last'));
  60. if(options.magvertcenter){
  61. $('.magnifyarea:last').css({marginTop: (h - $('.magnifyarea:last').height()) / 2});
  62. }
  63. if(options.descpos){
  64. $parent = $imgObj.parent();
  65. styleobj2 = {left: $parent.offset().left + ($parent.outerWidth() - $parent.width()) / 2, top: h + $imgObj.offset().top};
  66. }
  67. if(options.notmulti){
  68. $descArea.css(styleobj2);
  69. } else {
  70. $descArea.css(styleobj2).empty().append(lnk.getAttribute('data-title') || '');
  71. }
  72. if(+opacity < 1){$imgObj.add($descArea).animate({opacity: 1}, options.speed);}
  73. }).attr('src', $imgObj.data('src'));
  74. }
  75. this.click(function(e){
  76. e.preventDefault();
  77. var src = $imgObj.attr('src'), ms, zr, cs, opacityObj = {opacity: 0};
  78. if(!first && (src === this.href || src === this.getAttribute('href'))){return;}
  79. if(first && !options.initzoomablefade || !options.zoomablefade){opacityObj = {};}
  80. first = false;
  81. indoptions.largeimage = this.getAttribute('data-large') || options.largeimage || '';
  82. if(indoptions.largeimage === 'none'){indoptions.largeimage = '';}
  83. if((ms = this.getAttribute('data-magsize')) || options.magnifiersize){
  84. indoptions.magnifiersize = (ms? ms.split(splitre) : '') || options.magnifiersize;
  85. } else {delete indoptions.magnifiersize;}
  86. indoptions.zoomrange = ((zr = this.getAttribute('data-zoomrange'))? (zr = zr.split(splitre)) : '') || options.zoomrange || '';
  87. if(zr){zr[0] = +zr[0]; zr[1] = +zr[1];}
  88. indoptions.cursorshade = ((cs = this.getAttribute('data-lens'))? cs : '') || options.cursorshade || '';
  89. if(cs){indoptions.cursorshade = eval(cs);}
  90. $imgObj.data('added') &&
  91. $imgObj.stop(true, true).data('added').not('.zoomtracker').remove().end()
  92. .css({background: 'url(' + featuredimagezoomer.loadinggif + ') center no-repeat'});
  93. $imgObj.css($.extend({visibility: 'visible'}, ($imgObj.data('added')? options.zoomablefade? {opacity: 0.25} : opacityObj : opacityObj))).data('src', this.href);
  94. $descArea.css($.extend({visibility: 'visible'}, opacityObj));
  95. loadfunction.call(this);
  96. }).eq(0).trigger('click');
  97. return this;
  98. };
  99. // Featured Image Zoomer main code:
  100. $.extend(featuredimagezoomer, {
  101. dsetting: { //default settings
  102. magnifierpos: 'right',
  103. magnifiersize:[200, 200],
  104. cursorshadecolor: '#fff',
  105. cursorshadeopacity: 0.3,
  106. cursorshadeborder: '1px solid black',
  107. cursorshade: false,
  108. leftoffset: 15, //offsets here are used (added to) the width of the magnifyarea when
  109. rightoffset: 10 //calculating space requirements and to position it visa vis any drop shadow
  110. },
  111. isie: (function(){/*@cc_on @*//*@if(@_jscript_version >= 5)return true;@end @*/return false;})(), //is this IE?
  112. showimage: function($tracker, $mag, showstatus){
  113. var specs=$tracker.data('specs'), d=specs.magpos, fiz=this;
  114. var coords=$tracker.data('specs').coords //get coords of tracker (from upper corner of document)
  115. specs.windimensions={w:$(window).width(), h:$(window).height()}; //remember window dimensions
  116. var magcoords={} //object to store coords magnifier DIV should move to
  117. magcoords.left = coords.left + (d === 'left'? -specs.magsize.w - specs.lo : $tracker.width() + specs.ro);
  118. //switch sides for magnifiers that don't have enough room to display on the right if there's room on the left:
  119. if(d!=='left' && magcoords.left + specs.magsize.w + specs.lo >= specs.windimensions.w && coords.left - specs.magsize.w >= specs.lo){
  120. magcoords.left = coords.left - specs.magsize.w - specs.lo;
  121. } else if(d==='left' && magcoords.left < specs.ro) { //if there's no room on the left, move to the right
  122. magcoords.left = coords.left + $tracker.width() + specs.ro;
  123. }
  124. $mag.css({left: magcoords.left, top:coords.top}).show(); //position magnifier DIV on page
  125. specs.$statusdiv.html('Current Zoom: '+specs.curpower+'<div style="font-size:80%">Use Mouse Wheel to Zoom In/Out</div>');
  126. if (showstatus) //show status DIV? (only when a range of zoom is defined)
  127. fiz.showstatusdiv(specs, 400, 2000);
  128. },
  129. hideimage: function($tracker, $mag, showstatus){
  130. var specs=$tracker.data('specs');
  131. $mag.hide();
  132. if (showstatus)
  133. this.hidestatusdiv(specs);
  134. },
  135. showstatusdiv: function(specs, fadedur, showdur){
  136. clearTimeout(specs.statustimer)
  137. specs.$statusdiv.css({visibility: 'visible'}).fadeIn(fadedur) //show status div
  138. specs.statustimer=setTimeout(function(){featuredimagezoomer.hidestatusdiv(specs)}, showdur) //hide status div after delay
  139. },
  140. hidestatusdiv: function(specs){
  141. specs.$statusdiv.stop(true, true).hide()
  142. },
  143. getboundary: function(b, val, specs){ //function to set x and y boundaries magnified image can move to (moved outside moveimage for efficiency)
  144. if (b=="left"){
  145. var rb=-specs.imagesize.w*specs.curpower+specs.magsize.w
  146. return (val>0)? 0 : (val<rb)? rb : val
  147. }
  148. else{
  149. var tb=-specs.imagesize.h*specs.curpower+specs.magsize.h
  150. return (val>0)? 0 : (val<tb)? tb : val
  151. }
  152. },
  153. moveimage: function($tracker, $maginner, $cursorshade, e){
  154. var specs=$tracker.data('specs'), csw = Math.round(specs.magsize.w/specs.curpower), csh = Math.round(specs.magsize.h/specs.curpower),
  155. csb = specs.csborder, fiz = this, imgcoords=specs.coords, pagex=(e.pageX || specs.lastpagex), pagey=(e.pageY || specs.lastpagey),
  156. x=pagex-imgcoords.left, y=pagey-imgcoords.top;
  157. $cursorshade.css({ // keep shaded area sized and positioned proportionately to area being magnified
  158. visibility: '',
  159. width: csw,
  160. height: csh,
  161. top: Math.min(specs.imagesize.h-csh-csb, Math.max(0, y-(csb+csh)/2)) + imgcoords.top,
  162. left: Math.min(specs.imagesize.w-csw-csb, Math.max(0, x-(csb+csw)/2)) + imgcoords.left
  163. });
  164. var newx=-x*specs.curpower+specs.magsize.w/2 //calculate x coord to move enlarged image
  165. var newy=-y*specs.curpower+specs.magsize.h/2
  166. $maginner.css({left:fiz.getboundary('left', newx, specs), top:fiz.getboundary('top', newy, specs)})
  167. specs.$statusdiv.css({left:pagex-10, top:pagey+20})
  168. specs.lastpagex=pagex //cache last pagex value (either e.pageX or lastpagex), as FF1.5 returns undefined for e.pageX for "DOMMouseScroll" event
  169. specs.lastpagey=pagey
  170. },
  171. magnifyimage: function($tracker, e, zoomrange){
  172. if (!e.detail && !e.wheelDelta){e = e.originalEvent;}
  173. var delta=e.detail? e.detail*(-120) : e.wheelDelta //delta returns +120 when wheel is scrolled up, -120 when scrolled down
  174. var zoomdir=(delta<=-120)? "out" : "in"
  175. var specs=$tracker.data('specs')
  176. var magnifier=specs.magnifier, od=specs.imagesize, power=specs.curpower
  177. var newpower=(zoomdir=="in")? Math.min(power+1, zoomrange[1]) : Math.max(power-1, zoomrange[0]) //get new power
  178. var nd=[od.w*newpower, od.h*newpower] //calculate dimensions of new enlarged image within magnifier
  179. magnifier.$image.css({width:nd[0], height:nd[1]})
  180. specs.curpower=newpower //set current power to new power after magnification
  181. specs.$statusdiv.html('Current Zoom: '+specs.curpower)
  182. this.showstatusdiv(specs, 0, 500)
  183. $tracker.trigger('mousemove')
  184. },
  185. highestzindex: function($img){
  186. var z = 0, $els = $img.parents().add($img), elz;
  187. $els.each(function(){
  188. elz = $(this).css('zIndex');
  189. elz = isNaN(elz)? 0 : +elz;
  190. z = Math.max(z, elz);
  191. });
  192. return z;
  193. },
  194. init: function($img, options){
  195. var setting=$.extend({}, this.dsetting, options), w = $img.width(), h = $img.height(), o = $img.offset(),
  196. fiz = this, $tracker, $cursorshade, $statusdiv, $magnifier, lastpage = {pageX: 0, pageY: 0},
  197. basezindex = setting.zIndex || this.highestzindex($img);
  198. if(h === 0 || w === 0){
  199. $(new Image()).load(function(){
  200. featuredimagezoomer.init($img, options);
  201. }).attr('src', $img.attr('src'));
  202. return;
  203. }
  204. $img.css({visibility: 'visible'});
  205. setting.largeimage = setting.largeimage || $img.get(0).src;
  206. $magnifier=$('<div class="magnifyarea" style="position:absolute;z-index:'+basezindex+';width:'+setting.magnifiersize[0]+'px;height:'+setting.magnifiersize[1]+'px;left:-10000px;top:-10000px;visibility:hidden;overflow:hidden;border:1px solid black;" />')
  207. .append('<div style="position:relative;left:0;top:0;z-index:'+basezindex+';" />')
  208. .appendTo(document.body) //create magnifier container
  209. //following lines - create featured image zoomer divs, and absolutely positioned them for placement over the thumbnail and each other:
  210. if(setting.cursorshade){
  211. $cursorshade = $('<div class="cursorshade" style="visibility:hidden;position:absolute;left:0;top:0;z-index:'+basezindex+';" />')
  212. .css({border: setting.cursorshadeborder, opacity: setting.cursorshadeopacity, backgroundColor: setting.cursorshadecolor})
  213. .appendTo(document.body);
  214. } else {
  215. $cursorshade = $('<div />'); //dummy shade div to satisfy $tracker.data('specs')
  216. }
  217. $statusdiv = $('<div class="zoomstatus preloadevt" style="position:absolute;visibility:hidden;left:0;top:0;z-index:'+basezindex+';" />')
  218. .html('<img src="'+this.loadinggif+'" />')
  219. .appendTo(document.body); //create DIV to show "loading" gif/ "Current Zoom" info
  220. $tracker = $('<div class="zoomtracker" style="cursor:progress;position:absolute;z-index:'+basezindex+';left:'+o.left+'px;top:'+o.top+'px;height:'+h+'px;width:'+w+'px;" />')
  221. .css({backgroundImage: (this.isie? 'url(cannotbe)' : 'none')})
  222. .appendTo(document.body);
  223. $(window).bind('load resize', function(){ //in case resizing the window repostions the image or description
  224. var o = $img.offset(), $parent;
  225. $tracker.css({left: o.left, top: o.top});
  226. if(options.descpos && options.descArea){
  227. $parent = $img.parent();
  228. $(options.descArea).css({left: $parent.offset().left + ($parent.outerWidth() - $parent.width()) / 2, top: $img.height() + o.top});
  229. }
  230. });
  231. function getspecs($maginner, $bigimage){ //get specs function
  232. var magsize={w:$magnifier.width(), h:$magnifier.height()}
  233. var imagesize={w:w, h:h}
  234. var power=(setting.zoomrange)? setting.zoomrange[0] : ($bigimage.width()/w).toFixed(5)
  235. $tracker.data('specs', {
  236. $statusdiv: $statusdiv,
  237. statustimer: null,
  238. magnifier: {$outer:$magnifier, $inner:$maginner, $image:$bigimage},
  239. magsize: magsize,
  240. magpos: setting.magnifierpos,
  241. imagesize: imagesize,
  242. curpower: power,
  243. coords: getcoords(),
  244. csborder: $cursorshade.outerWidth(),
  245. lo: setting.leftoffset,
  246. ro: setting.rightoffset
  247. })
  248. }
  249. function getcoords(){ //get coords of thumb image function
  250. var offset=$tracker.offset() //get image's tracker div's offset from document
  251. return {left:offset.left, top:offset.top}
  252. }
  253. $tracker.mouseover(function(e){
  254. $cursorshade.add($magnifier).add($statusdiv).removeClass('featuredimagezoomerhidden');
  255. $tracker.data('premouseout', false);
  256. }).mouseout(function(e){
  257. $cursorshade.add($magnifier).add($statusdiv.not('.preloadevt')).addClass('featuredimagezoomerhidden');
  258. $tracker.data('premouseout', true);
  259. }).mousemove(function(e){ //save tracker mouse position for initial magnifier appearance, if needed
  260. lastpage.pageX = e.pageX;
  261. lastpage.pageY = e.pageY;
  262. });
  263. $tracker.one('mouseover', function(e){
  264. var $maginner=$magnifier.find('div:eq(0)')
  265. var $bigimage=$('<img src="'+setting.largeimage+'"/>').appendTo($maginner)
  266. var largeloaded = featuredimagezoomer.loaded[$('<a href="'+setting.largeimage+'"></a>').get(0).href];
  267. var showstatus=setting.zoomrange && setting.zoomrange[1]>setting.zoomrange[0]
  268. var imgcoords=getcoords()
  269. if(!largeloaded){
  270. $img.stop(true, true).css({opacity:0.1}) //"dim" image while large image is loading
  271. $statusdiv.css({left:imgcoords.left+w/2-$statusdiv.width()/2, top:imgcoords.top+h/2-$statusdiv.height()/2, visibility:'visible'})
  272. }
  273. $bigimage.bind('loadevt', function(event, e){ //magnified image ONLOAD event function (to be triggered later)
  274. if(e.type === 'error'){
  275. $img.css({opacity: 1}).data('added').remove();
  276. var src = $('<a href="' + $bigimage.attr('src') + '"></a>').get(0).href;
  277. if(window.console && console.error){
  278. console.error('Cannot find Featured Image Zoomer larger image: ' + src);
  279. } else {
  280. alert('Cannot find Featured Image Zoomer larger image:\n\n' + src);
  281. }
  282. return;
  283. }
  284. featuredimagezoomer.loaded[this.src] = true;
  285. $img.css({opacity:1}) //restore thumb image opacity
  286. $statusdiv.empty().css({border:'1px solid black', background:'#C0C0C0', padding:'4px', font:'bold 13px Arial', opacity:0.8}).hide().removeClass('preloadevt');
  287. if($tracker.data('premouseout')){
  288. $statusdiv.addClass('featuredimagezoomerhidden');
  289. }
  290. if (setting.zoomrange){ //if set large image to a specific power
  291. var nd=[w*setting.zoomrange[0], h*setting.zoomrange[0]] //calculate dimensions of new enlarged image
  292. $bigimage.css({width:nd[0], height:nd[1]})
  293. }
  294. getspecs($maginner, $bigimage) //remember various info about thumbnail and magnifier
  295. $magnifier.css({display:'none', visibility:'visible'})
  296. $tracker.mouseover(function(e){ //image onmouseover
  297. $tracker.data('specs').coords=getcoords() //refresh image coords (from upper left edge of document)
  298. fiz.showimage($tracker, $magnifier, showstatus)
  299. })
  300. $tracker.mousemove(function(e){ //image onmousemove
  301. fiz.moveimage($tracker, $maginner, $cursorshade, e)
  302. })
  303. if (!$tracker.data('premouseout')){
  304. fiz.showimage($tracker, $magnifier, showstatus);
  305. fiz.moveimage($tracker, $maginner, $cursorshade, lastpage);
  306. }
  307. $tracker.mouseout(function(e){ //image onmouseout
  308. fiz.hideimage($tracker, $magnifier, showstatus)
  309. }).css({cursor: fiz.magnifycursor});
  310. if (setting.zoomrange && setting.zoomrange[1]>setting.zoomrange[0]){ //if zoom range enabled
  311. $tracker.bind('DOMMouseScroll mousewheel', function(e){
  312. fiz.magnifyimage($tracker, e, setting.zoomrange);
  313. e.preventDefault();
  314. });
  315. } else if(setting.disablewheel){
  316. $tracker.bind('DOMMouseScroll mousewheel', function(e){e.preventDefault();});
  317. }
  318. }) //end $bigimage onload
  319. if ($bigimage.get(0).complete){ //if image has already loaded (account for IE, Opera not firing onload event if so)
  320. $bigimage.trigger('loadevt', {type: 'load'})
  321. }
  322. else{
  323. $bigimage.bind('load error', function(e){$bigimage.trigger('loadevt', e)})
  324. }
  325. })
  326. },
  327. iname: (function(){var itag = $('<img />'), iname = itag.get(0).tagName; itag.remove(); return iname;})(),
  328. loaded: {},
  329. hashre: /^#/
  330. });
  331. $.fn.addimagezoom = function(options){
  332. console.log("Inside add image zoom");
  333. console.log(options);
  334. console.log(this);
  335. console.log(this.selector);
  336. //var sel = $("#img-front"), $thumbs = $(sel.replace(featuredimagezoomer.hashre, '.') + '.thumbs a');
  337. var sel = this.selector, $thumbs = $(sel.replace(featuredimagezoomer.hashre, '.') + '.thumbs a');
  338. options = options || {};
  339. if(options.multizoom !== null && ($thumbs).size()){
  340. $thumbs.addmultizoom($.extend(options, {imgObj: sel, multizoom: null}));
  341. return this;
  342. } else if(options.multizoom){
  343. $(options.multizoom).addmultizoom($.extend(options, {imgObj: sel, multizoom: null}));
  344. return this;
  345. } else if (options.multizoom !== null){
  346. return this.each(function(){
  347. if (this.tagName !== featuredimagezoomer.iname)
  348. return true; //skip to next matched element
  349. $('<a href="' + this.src + '"></a>').addmultizoom($.extend(options, {imgObj: sel, multizoom: null, notmulti: true}));
  350. });
  351. }
  352. return this.each(function(){ //return jQuery obj
  353. if (this.tagName !== featuredimagezoomer.iname)
  354. return true; //skip to next matched element
  355. featuredimagezoomer.init($(this), options);
  356. });
  357. };
  358. })(jQuery);