PDA

View Full Version : Featured Image Zoomer



vwphillips
11-05-2012, 02:39 PM
This post concerns

http://www.dynamicdrive.com/dynamicindex4/featuredzoomer.htm

there have been a number of requests to swap images

With out knowing JQUERY I came up with this, I am sure it could be done better with a knowledge of JQUERY

http://www.vicsjavascripts.org.uk/DD/121104A.htm

the other this that concerns me is that if the z-Index of the image is >0 the pan window is hidden behind the image
I tried changing the z-Index of the cursorshadow but it had an adverse effect(the cursorshadow flickers)

jscheuer1
11-05-2012, 07:54 PM
It's not ready for release yet (close), but I have this in the works:

http://home.comcast.net/~jscheuer1/side/featuredimagezoomer/multizoom/demo.htm

I'm not 100% sure I understand what you're saying about the z-index. The way the script is setup is that no z-indexes are used. It relies upon the fact that a positioned element will cover another positioned element if it comes later in the DOM. If you add z-index to one, you must add the same z-index to them all. Otherwise, the ones earlier in the DOM with a z-index over 1 will cover those later in the DOM that are using no z-index (z-index defaults to 1 for positioned elements). There are many elements involved though, not just the shade and the image itself. Perhaps that's why you had problems when applying z-index to just the image and the shade. You can use a DOM inspector to see all of the elements involved.

Here they are for my demo page linked to above ('view generated source code' Firefox developer tools):


<div class="magnifyarea" style="position: absolute; width: 300px; height: 300px; left: -10000px; top: -10000px; visibility: hidden; overflow: hidden; border: 1px solid black; margin-top: -37px;"><div style="position:relative;left:0;top:0;"></div></div><div class="cursorshade" style="visibility: hidden; position: absolute; left: 0px; top: 0px; border: 1px solid black; opacity: 0.3; background-color: rgb(255, 255, 255);"></div><div class="zoomstatus preloadevt" style="position:absolute;visibility:hidden;left:0;top:0;"><img src="spinningred.gif"></div><div class="zoomtracker" style="cursor: progress; position: absolute; left: 31.5px; top: 136.833px; height: 226px; width: 300px; background-image: none;"></div>

<div class="magnifyarea" style="position:absolute;width:200px;height:200px;left:-10000px;top:-10000px;visibility:hidden;overflow:hidden;border:1px solid black;"><div style="position:relative;left:0;top:0;"></div></div><div class="zoomstatus preloadevt" style="position:absolute;visibility:hidden;left:0;top:0;"><img src="spinningred.gif"></div><div class="zoomtracker" style="cursor: progress; position: absolute; left: 19px; top: 545.333px; height: 243px; width: 325px; background-image: none;"></div>

But a clearer picture emerges when using a DOM inspector. Unfortunately I don't think that data can be easily pasted into a message here.

You can get the full code on the demo page. I'm publishing the added code here to fulfill 'first published' should anyone try to copy my work as their own:


// Multi-Zoom Script (c)2012 John Davenport Scheuer
// as first seen in http://www.dynamicdrive.com/forums/
// username: jscheuer1 - This Notice Must Remain for Legal Use
// requires: a modified version of Dynamic Drive's Featured Image Zoomer (w/ adjustable power) (included with full credit below multizoom code)

var featuredimagezoomer = { // the two options for Featured Image Zoomer:
loadinggif: 'spinningred.gif', // full path or URL to "loading" gif
magnifycursor: 'crosshair', // value for CSS's 'cursor' attribute, zoomable image
};

//////////////// No Need To Edit Beyond Here ////////////////

(function($){
$.fn.multizoomhide = function(){
return $('<style type="text/css">' + this.selector + ' {visibility: hidden;}<\/style>').appendTo('head');
};

$.fn.addmultizoom = function(options){

var indoptions = {largeimage: options.largeimage}, $imgObj = $(options.imgObj), $descArea = $(options.descArea), first = true, splitre = /, ?/,
addedselector = '.magnifyarea:last' + (options.cursorshade? ', .cursorshade:last' : '') + ', .zoomstatus:last, .zoomtracker:last';

function loadfunction(){
var lnk = this, styleobj1 = {}, styleobj2 = {}, $nim, lnkd, lnkt, lnko, w, h;
if((lnkd = lnk.getAttribute('data-dims'))){
lnkd = lnkd.split(splitre);
w = lnkd[0]; h = lnkd[1];
}
$(new Image()).error(function(){
if(lnk.tagName){
alert("Error: I couldn't find the image:\n\n" + lnk.href + ((lnkt = lnk.getAttribute('data-title'))? '\n\n"' + lnkt + '"' : ''));
if((lnko = lnk.getAttribute('data-lastimage'))){
$imgObj.attr('src', lnko).css({opacity: 1});
$descArea.css({opacity: 1});
}
}
}).load(function(){
$imgObj.css({width: w || options.width || this.width, height: (h = +(h || options.height || this.height))});
$imgObj.data('added') && $imgObj.data('added').remove();
if(options.imagevertcenter){styleobj1 = {top: ($imgObj.parent().innerHeight() - h) / 2};}
$imgObj.css(styleobj1).addimagezoom($.extend({}, options, indoptions))
.data('added', $(addedselector)).animate({opacity: 1}, options.speed || 'slow');
if(options.magvertcenter){
$('.magnifyarea:last').css({marginTop: (h - $('.magnifyarea:last').height()) / 2});
}
if(options.disablewheel){
$('.zoomtracker:last').bind('DOMMouseScroll mousewheel', function(e){e.preventDefault();});
}
if(options.descpos){styleobj2 = {left: $imgObj.parent().offset().left, top: h + $imgObj.offset().top};}
$descArea.css(styleobj2).empty().append(lnk.getAttribute('data-title') || '').animate({opacity: 1}, options.speed || 'slow');
}).attr('src', $imgObj.attr('src'));
}

this.click(function(e){
e.preventDefault();
var src = $imgObj.attr('src'), ms, zr, cs;
if(!first && (src === this.href || src === this.getAttribute('href'))){return;}
first = false;
indoptions.largeimage = this.getAttribute('data-large') || options.largeimage || '';
if(indoptions.largeimage === 'none'){indoptions.largeimage = '';}
if((ms = this.getAttribute('data-magsize')) || options.magnifiersize){
indoptions.magnifiersize = (ms? ms.split(splitre) : '') || options.magnifiersize;
} else {delete indoptions.magnifiersize;}
indoptions.zoomrange = ((zr = this.getAttribute('data-zoomrange'))? (zr = zr.split(splitre)) : '') || options.zoomrange || '';
if(zr){zr[0] = +zr[0]; zr[1] = +zr[1];}
indoptions.cursorshade = ((cs = this.getAttribute('data-lens'))? cs : '') || options.cursorshade || '';
if(cs){indoptions.cursorshade = eval(cs);}
this.setAttribute('data-lastimage', src);
$imgObj.css({visibility: 'visible', opacity: 0}).attr('src', this.href);
$descArea.css({visibility: 'visible', opacity: 0});
loadfunction.call(this);
}).eq(0).trigger('click');

return this;
};
})(jQuery);

vwphillips
11-06-2012, 10:01 AM
about the z-Index

I'm not 100% sure I understand what you're saying about the z-index

not unreasonable markup


<div style="position:relative;z-Index:2;width:400px;height:400px;background-Color:red;" >
<img id="image1" border="0" src="http://www.vicsjavascripts.org.uk/StdImages/Egypt12.jpg" style="width:300px;height:225px" />
</div>


will stop the cursor shade displaying

jscheuer1
11-07-2012, 01:48 AM
I got that much. I wasn't sure that I 100% understood what you were trying to do with it or what you were trying to do to fix it.

Why would it need a z-index 0f 2?

Anyways, I was just thinking about it in an abstract way, just before I logged on just now. jQuery can easily get the z-index of the image (regardless of whether if it's set inline or in the stylesheet) and use it for all of the other elements the script creates. That should fix it, and in fact (in a quick trial) does. Use this updated version of the script:

4829

It does just what I proposed in both my last post:


There are many elements involved though, not just the shade and the image itself. Perhaps that's why you had problems when applying z-index to just the image and the shade.

and this one. The only thing I got wrong in that last post is that the default z-index when none is specified is 0, not 1. It works out the same though.

The only changes are in the first 18 or so lines of the init function:


init: function($, $img, options){
var setting=$.extend({}, this.dsetting, options), w = $img.width(), h = $img.height(), o = $img.offset(),
fiz = this, $tracker, $cursorshade, $statusdiv, $magnifier, lastpage = {pageX: 0, pageY: 0}, basezindex = $img.css('zIndex');
setting.largeimage = setting.largeimage || $img.get(0).src;
$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;" />')
.append('<div style="position:relative;left:0;top:0;z-index:'+basezindex+';" />')
.appendTo(document.body) //create magnifier container
//following lines - create featured image zoomer divs, and absolutely positioned them for placement over the thumbnail and each other:
if(setting.cursorshade){
$cursorshade = $('<div class="cursorshade" style="visibility:hidden;position:absolute;left:0;top:0;z-index:'+basezindex+';" />')
.css({border: setting.cursorshadeborder, opacity: setting.cursorshadeopacity, backgroundColor: setting.cursorshadecolor})
.appendTo(document.body);
} else {
$cursorshade = $('<div />'); //dummy shade div to satisfy $tracker.data('specs')
}
$statusdiv = $('<div class="zoomstatus preloadevt" style="position:absolute;visibility:hidden;left:0;top:0;z-index:'+basezindex+';" />')
.html('<img src="'+this.loadinggif+'" />')
.appendTo(document.body); //create DIV to show "loading" gif/ "Current Zoom" info
$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;" />')
.css({backgroundImage: (this.isie? 'url(cann . . .

vwphillips
11-07-2012, 12:39 PM
my testing indicates that basezindex = $img.css('zIndex'); returns the image z-Index NOT the nested image z-Index


<div style="position:relative;z-Index:2;width:400px;height:400px;background-Color:red;" >
<img id="image1" border="0" src="http://www.vicsjavascripts.org.uk/StdImages/Egypt12.jpg" style="position:relative;z-Index:2;width:300px;height:225px" />
</div>


returns a z-Index of 2 NOT 4

Beverleyh
11-07-2012, 01:01 PM
This is looking really good chaps. I cant really offer much input on the code but I just wanted to say that the image swap would be a very welcome addition, and what you have so far is looking fab!.

Keep up the great work - I've already got a twitchy mouse-finger in anticipation of its official release.

jscheuer1
11-07-2012, 02:47 PM
Thanks Beverleyh!

I have an announcement to make. It looks fairly certain that this multi zoom script will soon either replace the current Featured Image Zoomer or be offered as a script in its own right here on Dynamic Drive.

Vic, I questioned it initially whether the script should compensate for the designer who uses it using a z-index value on the image. But I figured, "Hey they might do that." And I could see how that might mess things up. However, using a lot of nested positioned elements, though required for a script of this type, is poor design for page layout in general. I think we can leave that vulnerability in there. The designer using this script with that sort of layout will either have to figure it out or seek help here.

However, the script can compensate for what I would at this point call user stupidity. To do so, add the highlighted function and make the highlighted change to the already updated init function:


highestzindex: function($, $img){
var z = 0, $els = $img.parents().add($img), elz;
$els.each(function(){
elz = $(this).css('zIndex');
elz = isNaN(elz)? 0 : +elz;
z = Math.max(z, elz);
});
return z;
},

init: function($, $img, options){
var setting=$.extend({}, this.dsetting, options), w = $img.width(), h = $img.height(), o = $img.offset(),
fiz = this, $tracker, $cursorshade, $statusdiv, $magnifier, lastpage = {pageX: 0, pageY: 0}, basezindex = this.highestzindex($, $img);
setting.largeim . . .

Another way of fixing this 'problem' is to apply the appropriate z-index in the stylesheet. For example, in your scenario with the z-index: 2 nested in a z-index: 4 element:


.zoomtracker, .magnifyarea, .zoomstatus, .cursorshade {
z-index: 4 !important;
}

BTW, the script originally assigned a high z-index, like 1000 to all of these elements. But the major problem in my mind with that is of a drop down menu disappearing behind it. So at that point I opted for no z-index.


A more real issue with the multi zoom script is that, unlike the single image one, since the original or zoomable image changes, if there are varying sizes for these images, the page layout will get jumpy whenever one is changing from one original image to another of a different size. In my demo I solve that problem easily by using a container element of a fixed width and height for the original image. The width is as wide or wider than the widest original image and as tall or taller than the tallest original image. The script can optionally detect these dimensions and center the image in this container, or the image can be allowed to find its own place in this container, or be styled as to where it will go, at least preventing the rest of the page from jumping around.

I could have the script make this container if it's missing. But that would require loading all of the original images and measuring them, or require that the designer using the script supply these dimensions (the latter is done in the case of many slideshow scripts). The former could unnecessarily delay the initialization (lots of large original images) of the script and/or mess with the layout of the page and is complex to do. The latter adds another layer of complexity in explaining the script.

Then there's the fact that a container would natively be display block, while an image is display inline. Floats or tables can be used to make up for that where needed/desired. I'm just trying to figure out the best way to deal with and explain all that to users of the script.

Beverleyh
11-07-2012, 03:13 PM
Woo Hoo! Dibs on first download!


... I'm just trying to figure out the best way to deal with and explain all that to users of the script.

I really have to applaud ddadmin and all of you involved on keeping the site ship-shape.

Its often an overlooked practice, but the daily (and highly successful, I might add) administration here is top rate. Not only do we get a shed load of amazing scripts, we also get excellently logical and well explained documentation to go with it.

AND happy, smiley chappies helping everyone out in the forums too!

We are spoilt rotten here really, aren't we ;)

vwphillips
11-07-2012, 03:27 PM
for the z-Index

I would be happy with an option for the z-Index and a default of say 101

better still specify a class name of the cursorshade which specifies the z-Index(and border/opacity as required)

as for image size

either set the swap image height to the originals height

or just explain to the user that using a different image size will change the page layout.


btw

you may be interested in

http://www.vicsjavascripts.org.uk/ImageViewerV/ImageViewerV.htm

which is of similar size the rhe original DD script but with many more options
edit
in my script the origin image size is retained on image swap, not sure if it is worth allowing it to change

jscheuer1
11-08-2012, 04:14 PM
I've decided to go with the highestzindex() function as described in my last post with an option to set it. So you can set it, if you do not, it will default to the highest parent element's z-index. Adding to the code from my last post, that would be:


highestzindex: function($, $img){
var z = 0, $els = $img.parents().add($img), elz;
$els.each(function(){
elz = $(this).css('zIndex');
elz = isNaN(elz)? 0 : +elz;
z = Math.max(z, elz);
});
return z;
},

init: function($, $img, options){
var setting=$.extend({}, this.dsetting, options), w = $img.width(), h = $img.height(), o = $img.offset(),
fiz = this, $tracker, $cursorshade, $statusdiv, $magnifier, lastpage = {pageX: 0, pageY: 0},
basezindex = setting.zIndex || this.highestzindex($, $img);
setting.largeim . . .

As the release of the updated version including multi-zoom is immanent, you can just wait until that comes out and use it*. It can be used to make a single zommable using the old syntax, as well as to make multi-zoom features using the new.

So you could do like (old syntax for a single feature):


$('#image1').addimagezoom({
zoomrange: [3, 10],
magnifiersize: [300,300],
magnifierpos: 'right',
cursorshade: true,
zIndex: 4,
largeimage: 'http://i44.tinypic.com/11icnk5.jpg' //<-- No comma after last option!
})

or (new multi-zoom syntax):


$('.triggers a').addmultizoom({ // options same as for regular Featured Image Zoomer's addimagezoom unless noted as '- new'
imgObj: '#image1', // image selector for zoomable image (required) - new
descArea: '#description', // description selector (optional - but required if descriptions are used) - new
speed: 1500, // duration of fade in for new zoomable image (in milliseconds, optional) - new
descpos: true, // if set to true - description position follows image position at a set distance, defaults to false (optional) - new
imagevertcenter: true, // zoomable image centers vertically in its container (optional) - new
magvertcenter: true, // magnified area centers vertically in relation to the zoomable image (optional) - new
zoomrange: [3, 10],
magnifiersize: [300,300],
zIndex: 4, // set z-index for created elements, should be as high or higher than the cumlative z-index of the zoomable image - new
magnifierpos: 'right',
cursorshade: true,
largeimage: 'milla.jpg' //<-- No comma after last option!
});

I've made it like this because there really are a lot of layouts out there that use a lot of positioning and z-index. In the long run this (defaulting to highest parent z-index) will save a lot of headaches, and if it causes any problems those can be resolved using the manual setting. At the same time, in what I consider a normal well thought out layout, the new default (which will effectively be 0 in such layouts, so will be the old default for those) will preserve in the original intent of not interfering with drop down menus and other features that must stack higher than static content.



*The current development version has this added as well, same link:

http://home.comcast.net/~jscheuer1/side/featuredimagezoomer/multizoom/demo.htm

vwphillips
11-09-2012, 12:46 PM
that appears appears to fix the z-Index

just a matter of getting the DD script updated

about your demo

It relies on having thumbnails to swap
so no thumbnails = no functionality

better to use the image ID for basic functionality
and the thumbnails as an option

jscheuer1
11-10-2012, 04:22 AM
about your demo

It relies on having thumbnails to swap
so no thumbnails = no functionality

better to use the image ID for basic functionality
and the thumbnails as an option

I see your point and will consider it visa vis modifying how the script is invoked. However, as it currently stands, if you don't want to have thumbnails - want a single Featured Image Zoomer, you can use the old syntax with the new script:



$('#image1').addimagezoom({
zoomrange: [3, 10],
magnifiersize: [300,300],
magnifierpos: 'right',
cursorshade: true,
zIndex: 4,
largeimage: 'http://i44.tinypic.com/11icnk5.jpg' //<-- No comma after last option!
})

and it will work just fine.

jscheuer1
11-10-2012, 05:46 PM
OK, I decided to go with you're suggestion. The new syntax is like the old syntax with an added property to turn on multizoom:


$('#image2').addimagezoom({ // options same as for previous Featured Image Zoomer's addimagezoom unless noted as '- new' or '- requires multizoom'
multizoom: '.triggers2 a', // triggers for image swapping (required for multizoom) - new
descArea: '#description2', // description selector (optional - but required if descriptions are used) - requires multizoom
disablewheel: true // even without variable zoom, mousewheel will not shift image position while mouse is over image (optional) - new
//^-- No comma after last option!
});

If you use the multizoom property, it will use those thumbnail links to setup a multizoom feature. If not, it will act like the previous version. So it's no longer a new script, nor an addon, rather an update of the existing Featured Image Zoomer.

Some of the new features are available even in single image mode. The code has changed slightly. The updated demo page reflects these latest developments both in code and documentation. Same address:

http://home.comcast.net/~jscheuer1/side/featuredimagezoomer/multizoom/demo.htm

vwphillips
11-12-2012, 02:56 AM
unfortunately the magnified image container does no appear to have a z-Index so that is hidden behind other elements

I had a typo

Just a matter of getting the DD script updated?

jscheuer1
11-12-2012, 12:28 PM
I'm not sure what you're saying here. Are you using the latest version from:

http://home.comcast.net/~jscheuer1/side/featuredimagezoomer/multizoom/demo.htm

?

I have been updating frequently. Make sure to clear your browser cache before downloading.

As for:


Just a matter of getting the DD script updated?

Perhaps. The official version has not been updated yet.

On a side note - I've been working on a tweak where if there's markup for thumbnails associated with an image, that invokes multizoom, no extra multizoom property needs to be specified. However, it breaks down in the latest jQuery versions (1.8+), probably due to a bug. I'm thinking of going with it anyway and requiring jQuery 1.7.2 (the latest without this bug) and possibly making a bug report. A bug report is extra work though and I would have better luck with it if I could further isolate the cause. As it stands now, I can only tell what code invokes it, not the actual problem. Took me forever to realize it was version specific, I should have checked that sooner.

I found a workaround. The problem is in jQ 1.8+ and relates to a problem with its .not() function which is documented and supposedly fixed, but obviously not entirely. I found that by using the :not() selector instead of the function I was able to get jQ1.8 to cooperate. So now I've updated the live development demo with the new code. You can still specify a selector for the thumbnails if you choose. But if you use the expected format, the script will detect it and use it. The format is the selector for the image as a classname with an added classname, 'thumbs'. So image1's thumbnails go in an element with a class of "image1 thumbs". I needed the not (whether selector or function doesn't matter) to filter out the thumbnails should someone choose to select the primary zoomable image tag via a classname.