Upon seeing the Fluxiom intro video, I was compelled to figure out how they pulled off iPhoto-like image scaling in a browser. Leveraging the work of others, it’s actually very simple.
If you use the script.aculo.us slider control to capture input values, it’s really just a matter of converting those values into something useful and modifying styles.
Note: OS X folks using Firefox will likely get some stutter, due to a crippling, 3 year old bug.
A simple demo.







Here’s how.
1. Install and reference the Prototype and script.aculo.us libraries.
2. Create the track and slider HTML nodes. (CSS inline for simplification)
<div id=”handle1″ style=”width: 18px; height: 18px;”>
<img src=”/images/content/blog/scaler_slider.gif”/>
</div>
</div>
3. Create a function to be called when the slider value changes. This collects all nodes for resizing, remaps the 0-1 scale to a definable range, and then scales.
var scalePhotos = document.getElementsByClassName(‘scale-image’);
floorSize = .26;
ceilingSize = 1.0;
v = floorSize + (v * (ceilingSize – floorSize));
for (i=0; i < scalePhotos.length; i++) {
scalePhotos[i].style.width = (v*190)+’px’;
}
}
4. Create the slider and map the two events to our function (either inline, or as part of the body onload event). See the Slider docs for usage details.
{axis:’horizontal’, minimum: 0, maximum:200, alignX: 2, increment: 2, sliderValue: 1});
demoSlider.options.onSlide = function(value){
scaleIt(value);
}
demoSlider.options.onChange = function(value){
scaleIt(value);
}
5. Finally, create the HTML for our images.
<div class=”scale-image” style=”width: 190px; padding: 10px; float: left;”>
<img src=”/images/content/blog/scaler_1.jpg” width=”100%”/>
</div>
<div class=”scale-image” style=”width: 190px; padding: 10px; float: left;”>
<img src=”/images/content/blog/scaler_2.jpg” width=”100%”/>
</div>
</div>
There are definitely some areas to clean up (redundant div width specifications, for example), but for a quick demo it will suffice. Tested with Firefox, Safari and Win IE 6.
Update: There appears to be a small issue in IE; the slider disappears when you start dragging.
Update: Fixed. Moved the handle image to an actual img.
Update: Corrected a typo. (Fluxium != Fluxiom)





John this tutorial on something I’ve been dying to figure out myself. Thanks for sharing!
Nice work, I can’t wait to start playing with this
.
The resize stutters for me in firefox. I am running XP on a AMD XP 2000+.
I’m sure we’ll start seeing this a lot. Personally, I’m trying to think of where I could use it…
badass, i’m going to start using this hopefully. i just wish i didn’t have to find and replace all of the funky quotes ( ” ) haha
This was initially created as part of a photo blog admin interface. The slider allows me to see a small subset of images in detail, or scale them down to see the full list of posts. I initially figured it would just be a novel experiment, but I’ve found it to be pretty useful. The full admin app also scales blog post text by calculating “em” sizes based on the slider value.
The scaling quality at smaller sizes is suspect, but at that zoom level I’m not too concerned with fidelity.
Thanks for sharing. I’m going to add this to my site.
Works fine for me on a P4 – Firefox 1.5 full release. Silky smooth, Intel chipset graphics (no hot-shot graphics card here).
Suggestion – extend this to dynamically change images with small byte size thumbnails initially, swapping out to larger images as scaling reaches a certain threshold with background image loading (after the thumbnails) for quick response
Yes, I’ll work on that if you don’t (assuming I have time someday during the holiday break…)
No really new, it’s the same mechanism for DnD, just that you’re forcing the image to be automatically re-rendered to a different size. We did something similar for moving images over buttons (enter events). Still, it’s a great example showing the potential for web apps capable of fat client behavior.
oh wonderful idea. thank you for sharing!
This is a great trick, but how would you do it with a mix of horizontal and vertical images? The vertical ones scale to 100% width, which throws off the grid. The script needs to recognize that vertical images shouldn’t scale beyond 100% of the horizontal.
Doesn’t work for me under FireFox 1.5 (but IE). What happens under FireFox for me, is that the image width is simply cropped, but the image isn’t scaled. Looking at the code, that actually makes sense. The containing div-element is cropped, why should that affect the *scaling* of the contained image? I guess, the width of the actual image should be change in order to work consistently, right?
Jan: FF1.5 works fine for me, not sure what the difference is. My understanding is that by specifying width=”100%” in the img tag, the image will scale to fill its parent.
Yeah, changing the images directly also works (not sure if it would fix the FF issue you’re seeing), it was just an arbitrary decision to wrap them in this case.
Steve: Agreed that logic needs to be added to constrain tall images.
been there, done that, but your slider is smoother under IE than I managed to do. (stupid thing always wanted clicks, rather than drags, and was INSANELY slow for large numbers of images)
Here’s another thought to add: use a cookie to store the position of the slider where the user last felt he had a “comfortable size”.
It took me too long to figure out how to do (debug) all of the features I wanted, & I wandered on to other projects before I got around to re-doing my whole site that way… probably a good thing, I was too addicted to liquid layouts at the time, my distaste for rectangular, grid-like layouts caused me to make something REALLY ugly.
Here’s the solution I came up with (and it works in FF1.5 and IE):
images = getElementsByClassName(document,’scale-image’);
for(var i = 0; i
Damn, it didn’t seem to post right. Here we go again:
images = getElementsByClassName(document,'scale-image');
for(var i = 0; i
Ah, it’s the less equal sign:
images = getElementsByClassName(document,’scale-image’);
for(var i = 0; i LE images.length; i++) {
var image = images[i].getElementsByTagName( ‘img’ );
image[0].style.width = (v*190)+’px’;
image[0].style.height = ‘auto’;
}
Congratulations.. just don’t merge my account with Yahoo! like Flickr was forced to do!
This is really nice, work for me in FF 1.5 and IE6. Thanks for posting the code.
Here’s a quick optimization for this code… just make the “scalePhotos” array global, then only call “getElementsByClassName” if it’s null… such as this:
…
var scalePhotos;
function scaleIt(v) {
if(scalePhotos == null){scalePhotos = document.getElementsByClassName(“scale-image”);}
…
This should make it run a little smoother, instead of calling that function every time the slider moves.
Hi,
I created aa test file http://suncafe.us/windchilltest/test1.html
it doesn’t work. what am I doing wrong
scaler.js :
function scaleIt(v) {
var scalePhotos = document.getElementsByClassName(“scale-image”);
// Remap the 0-1 scale to fit the desired range
floorSize = .26;
ceilingSize = 1.0;
v = floorSize + (v * (ceilingSize – floorSize));
for (i=0; i
Alain: It looks like you need to download and include the Prototype and scriptaculous libraries. See the first step for links to these files.
Was the script above meant to solve the vertical image problem? If so, I can’t seem to make it work. And, I replaced “LE” with “[=” (with the open bracket being the less than sign so as not to break the markup). Is this snippet supposed to replace a portion of the original script, or just added on?
Thanks for the great technique.
I’ve given it a try. In firefox there are some funny line breaks mixed in with the images, although in IE everything works as it should. I think that the problem has to do with “float: left;” but I’m having a hell of a time trying to fix it. If anyone familiar with firefox and floating with css would take a look, I’d be much obliged.
http://www.bajilives.com
Whoops, that link should be:
http://www.bajilives.com/test.html
thanks
I did this a few months back using some Walter Zorn magic, plus some ImageMagick stuff on the back side in Zope to actually save the images.
check out http://walterzorn.com
I actually implemented a solution where you could hold-and-drag the corners and resize that way, but I suppose the slider is nice too.
Walter Zorn is a JavaScript GOD.
I’ve done a test page but I’d really like it to load with the pictures zoomed all the way out. Jeremy A, you seem to have accomplished this, but I can’t figure out how. Any advice?
Damn… wrong link…
Try this one.
All right… after a lot of tinkering I’ve managed to get it so that the page loads with the pictures zoomed all the way out. See here. My next problem is that while zooming in, the images jump around a bit. (Looks like this. In the original demo on this page the images flow much more smoothly. Anyone know how to fix that?
Very nice, thanks for sharing
leifm
You should set the width to 450 in the css inside the scale-image.
Fantastic ! Thanks for give us those tips
Nice trick, grat.
jof:
You should set the width to 450 in the css inside the scale-image.
Thanks for the idea. Unfortunately, I tried that and it doesn’t seem to make much difference. See here. It still has the same gaps when zooming in on the images. Any other ideas?
leifm —
I had the same problem as you and it took me a long time to figure out the problem. Fortunately there is a very easy and intuitive fix. You are really dealing with a list of images here, not a whole mass of divs. So why not hold the pictures in a list? It solved all my problems. For a full example, check out:
http://www.bajilives.com/galleries/Mazatlan/index.html
Look at the page source and the css.
Best of luck.
OK, trying this again with escaped < and >….
Hi leifm. Your problems are happening because not all your images are the same size. Image #3 is one pixel shorter than the rest. Image #7 is one pixel taller. As the images scale, there can be times when that one extra pixel difference allows a single image to start off in that 1 pixel gap while everything else is forced to start on the next row (which is now much farther down).
The solution (short of making all your images the same size) is to specify a height for the <div>’s as well, such as:
<div class=”scale-image” style=”padding: 10px; float: left; width: 300px; height: 200px;”>
You will also need to adjust this div height in the JS when you adjust the slider. Thus the scaleIt() function becomes:
function scaleIt(v) {
if(scalePhotos == null){scalePhotos = document.getElementsByClassName(‘scale-image’);}
floorSize = .226;
ceilingSize = 1.0;
v = floorSize + (v * (ceilingSize – floorSize));
for (i=0; i < scalePhotos.length; i++) {
scalePhotos[i].style.width = (v*450)+’px’;
scalePhotos[i].style.height = (v*300)+’px’;
}
}
Note that this assumes a 3:2 width to height ratio. The numbers would need to be adjusted for images with a different aspect ratio.
Finally, this is 1/2 of the way to allowing vertical images. But for the rest of it you’ll have to wait just a little bit longer.
Jeremy A:
You are really dealing with a list of images here, not a whole mass of divs. So why not hold the pictures in a list? It solved all my problems.
I get the feeling that keeping all the images in their own seperate divs is going to be integral to the integration of vertically-oriented images. I like the way that you got around this issue on your site. Unfortunately, I just don’t think square images would work for me; I’m much too hooked on the 2:3 (or 3:2) ratio.
Josh Weihnacht:
Your problems are happening because not all your images are the same size.
Thank you so much for this! I wouldn’t have even thought to check that. After resizing the images, everything works much more smoothly.
Note that this assumes a 3:2 width to height ratio. The numbers would need to be adjusted for images with a different aspect ratio.
I can kind of see where you’re going with this, but I don’t have the Java skills to go there myself.
Finally, this is 1/2 of the way to allowing vertical images. But for the rest of it you’ll have to wait just a little bit longer.
You can count on it! I really like this method of displaying a gallery of images. I’ll check back regularly to see what you’ve come up with.
Thanks.
Oh, and if anyone wants to see what a gallery of vertically-oriented images looks like using this slider method, I put one up here”.
Similar to what drafnas said, but saving the starting image width and using a closure instead of a global to store the array of images
function makeScaler(className) {
var scalePhotos = document.getElementsByClassName(className);
var photos=[]
for (var i=0; i < scalePhotos.length; i++){
// horrible, ugly, works
im=scalePhotos[i].getElementsByTagName(‘img’)[0]
var thisPhoto=[scalePhotos[i],im.width,im.height]
photos[i]=thisPhoto
}
return function (v) {
floorSize = .26;
ceilingSize = 1.0;
v = floorSize + (v * (ceilingSize – floorSize));
for (var i=0; i < photos.length; i++) {
photos[i][0].style.width = (v*photos[i][1])+”px”;
}
}
}
scaleIt=makeScaler(“scale-image”)
Needs some cleanups and I guess the closure can be scary, but it has the advantage of not needing the image width specified in the html source and works fine with a mix of horizontal and vertical images. To be clear, it works fine if the image size is specified in the source, it just doesn’t need it.
leifm – the point of “allowing” vertical images is in a mix of horizontal and vertical images (in fact, it should allow for various sizes, regardless of orientation). Your demo is all vertical images, which is how the current system works anyway.
Another fun little image resizing variation to play with:
http://www.nsftools.com/tips/ImageResize.htm
Best solution I see is to use the native width as the basis for sizing. One way of doing this is to store the width in the id tag of th image and call it in script like so.
scalePhotos[i].style.width = (v*scalePhotos[i].id)+”px”;
no arrays or anything this is the only change to the original code provided in the article, well I did away with the divs around the images like so
well this works great for me.
Applied in a Zenphoto theme with gradual image loading based on size.
Thanks a lot for this, it’s very cool.
Very cool stuff Tristan.
Cool! and thanks.
/t
Thanks for sharing the article – gives me something fun to play with for a while!
I have a problem, though… For some reason I cannot get my slider to go all the way to the right. It’s bound to be something very easy, but I just can’t spot it this late into the week.
Can anyone check it out and spot the problem?
http://www.sussex.ac.uk/USIS/test/andy/web2/examples/slider/
Hi Andy,
It looks like the version of slider.js that you have is a little different than the one that is used in this demo. That seems to be the source of the problem. However, if you tweak your settings for the slider, you can adapt. Change your “alignX” parameter to -5 so that the function call looks like this and things should work correctly for you.
demoSlider = new Control.Slider(‘slider-handle’, ‘slider-bar’, {
axis:’horizontal’, minimum: 0, maximum: 200, alignX: -5, increment: 2, sliderValue: 0.5
});
You’re a star, Josh! Many thanks for your help — it worked perfectly!
This works great, but some of my images are quite small. Is there a way to keep them from scaling to greater than 100% of their actual size?