I like the idea of using ImageFlow with Lightbox2, however, I don't like that it required a tweaked version of ImageFlow, nor that I then had to modify my image list to wrap the Lightbox2 elements around them. Additionally, Lightbox2 adds a lot of functionality that's not being using in this case (all the next/previous image controls, image caching, etc), and it also wants to initialize itself during the window.onload event which I don't want in my Ajax apps.
So, wrote my own Lightbox Lite. Well, technically, I extracted my own Lightbox Lite from the Lightbox2 code with a few modifications.
To begin with, I added this block of HTML to my web page. The Lightbox2 code constructs this dynamically in its initialize
function, but I don't see the advantage of that vs just hard coding it into the page to begin with.
<div id="photo" style="display:none">
<div id="lightbox">
<div id="outerImageContainer">
<div id="imageContainer">
<img id="lightboxImage" style="display:none"></img>
<div id="imageloading">
<img src="images/loadingImage.gif">
</div>
</div>
</div>
<div id="imageDataContainer" style="display:none">
<div id="imageData">
<div id="imageDetails">
<span id="imagecaption"></span>
</div>
<div id="imageBottomNav" onclick="LightBoxLite.reset();" style="float:right" >
<img src="images/close-button.png" alt="Close" title="Close">
</div>
</div>
</div>
</div>
</div>
Then I added the relevant CSS rules to my stylesheet:
#photo {
z-index: 51;
position: absolute;
top: 5px;
left: 1px;
width: 100%;
}
#outerImageContainer {
background-color: white;
width: 250px;
height: 250px;
margin: 0 auto;
}
#imageContainer {
padding-top: 10px;
}
#imageloading {
position: absolute;
top: 40%;
left: 47.5%;
}
#imageDataContainer {
font: 10px Verdana, Helvetica, sans-serif;
background-color: white;
margin: 0 auto;
line-height: 1.4em;
overflow: auto;
width: 100%;
padding-bottom: 5px;
}
#imageData {
padding: 0 10px;
color: #666;
}
#imageData #imageDetails {
width: 80%;
float: left;
text-align: left;
}
#imageData #imageCaption {
font-weight: bold;
}
Next I added the Lightbox Lite code to my JavaScript (note, you still need prototype.js and script.aculo.us):
LightBoxLite = function() {
var borderSize = 10;
var resizeDuration = 0.6;
/**
* resizeImageContainer
*
* @param {Number} desired width
* @param {Number} desired height
*/
function resizeImageContainer( imgWidth, imgHeight) {
// get current width and height
var widthCurrent = $('outerImageContainer').getWidth();
var heightCurrent = $('outerImageContainer').getHeight();
// get new width and height
var widthNew = (imgWidth + (borderSize * 2));
var heightNew = (imgHeight + (borderSize * 2));
// scalars based on change from old to new
var xScale = ( widthNew / widthCurrent) * 100;
var yScale = ( heightNew / heightCurrent) * 100;
// calculate size difference between new and old image, and resize if necessary
var wDiff = widthCurrent - widthNew;
var hDiff = heightCurrent - heightNew;
if (!( hDiff === 0)) {
new Effect.Scale('outerImageContainer', yScale, {scaleX: false, duration: resizeDuration, queue: 'front'});
}
if (!( wDiff === 0)) {
new Effect.Scale('outerImageContainer', xScale, {scaleY: false, delay: resizeDuration, duration: resizeDuration});
}
$('imageDataContainer').style.width = widthNew + "px";
showImage();
}
/**
* updateDetails
*
*/
function updateDetails() {
var caption = $('lightboxImage').src.split('/').pop().split('.')[0].gsub("%20", " ");
$('imagecaption').innerHTML = caption;
new Effect.Parallel(
[ new Effect.SlideDown( 'imageDataContainer', { sync: true, duration: resizeDuration, from: 0.0, to: 1.0 }),
new Effect.Appear('imageDataContainer', { sync: true, duration: resizeDuration }) ]
);
}
/**
* showImage
* Display image and begin preloading neighbors.
*/
function showImage() {
$('imageloading').hide();
new Effect.Appear('lightboxImage', { duration: resizeDuration, queue: 'end', afterFinish: updateDetails });
}
function checkForPreloadComplete(imgPreloader) {
if (imgPreloader.complete) {
$('lightboxImage').src = imgPreloader.src;
resizeImageContainer(imgPreloader.width, imgPreloader.height);
} else {
setTimeout(checkForPreloadComplete.bind(this, imgPreloader), 100);
}
}
return {
/**
* displayImage
* display an image in a lightbox
*
* @param {String} URL of image
*/
displayImage : function(imageUrl) {
$('imageloading').show();
$('lightboxImage').hide()
$('imageDataContainer').hide()
$('photo').show();
var imgPreloader = new Image();
imgPreloader.src = imageUrl;
// once image is preloaded, resize image container
setTimeout(checkForPreloadComplete.bind(this, imgPreloader), 100);
},
reset : function() {
$('photo').hide();
$('imageloading').show();
$('lightboxImage').hide()
$('imageDataContainer').hide()
$('lightboxImage').src = "";
$('outerImageContainer').style.width = "250px";
$('outerImageContainer').style.height = "250px";
}
};
}();
The only alteration you have to do to your ImageFlow images is to add a call to the
LightBoxLite.displayImage
function in the
longdesc
attribute of your images, which should currently have the address of the original image to display when you click on it in the image flow. So, instead of:
<img src="reflect.php?img=myimage.jpg" longdesc="myimage.jpg" alt="myimage" />
It becomes:
<img src="reflect.php?img=myimage.jpg" longdesc="javascript:LightBoxLite.displayImage('myimage.jpg')" alt="myimage" />
Here is an
example of it being used.
Update January 20: I tweaked a couple CSS rules to correctly center the loading indicator for Internet Explorer.
Update January 23: I received a request to package my modifications. See my
new blog entry where I have done that in addition to demonstrating how to add Ajax to receive the image list.