Agile Partners logo
HomeAboutOur WorkTechnologyWeblog
iPhoto-like image resizing using Javascript
Wednesday, December 7th, 2005 at 11:41 pm by jb

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=”track1″ style=”width: 200px; height:18px;”>
  <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.

function scaleIt(v) {
  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.

var demoSlider = new Control.Slider(’handle1′,’track1′,
{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 style=”border: 1px solid #ddd; width: 424px; overflow: auto;”>
  <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)

85 Responses to “iPhoto-like image resizing using Javascript”

You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.
  1. Russell Says:

    John this tutorial on something I’ve been dying to figure out myself. Thanks for sharing!

  2. Lsv Says:

    Nice work, I can’t wait to start playing with this :).

  3. dharh Says:

    The resize stutters for me in firefox. I am running XP on a AMD XP 2000+.

  4. Brian Spaid Says:

    I’m sure we’ll start seeing this a lot. Personally, I’m trying to think of where I could use it…

  5. thewebguy Says:

    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

  6. jb Says:

    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.

  7. Joey Says:

    Thanks for sharing. I’m going to add this to my site.

  8. Jeffrey Says:

    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…)

  9. CW Says:

    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.

  10. Vance Dubbelry Says:

    oh wonderful idea. thank you for sharing!

  11. Steve Says:

    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.

  12. Jan Says:

    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?

  13. jb Says:

    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.

  14. greenup Says:

    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.

  15. Jan Says:

    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

  16. Jan Says:

    Damn, it didn’t seem to post right. Here we go again:

    images = getElementsByClassName(document,'scale-image');
    for(var i = 0; i

  17. Jan Says:

    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’;
    }

  18. anon Says:

    Congratulations.. just don’t merge my account with Yahoo! like Flickr was forced to do!

  19. Son Nguyen Says:

    This is really nice, work for me in FF 1.5 and IE6. Thanks for posting the code.

  20. drofnas Says:

    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.

  21. Alain Says:

    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

  22. jb Says:

    Alain: It looks like you need to download and include the Prototype and scriptaculous libraries. See the first step for links to these files.

  23. Steve Says:

    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?

  24. Jeremy A Says:

    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

  25. Jeremy A Says:

    Whoops, that link should be:
    http://www.bajilives.com/test.html

  26. Anouar Says:

    thanks ;)

  27. bugeyedmonster Says:

    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.

  28. leifm Says:

    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?

  29. leifm Says:

    Damn… wrong link…

    Try this one.

  30. leifm Says:

    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?

  31. George Moschovitis Says:

    Very nice, thanks for sharing ;-)

  32. jof Says:

    leifm

    You should set the width to 450 in the css inside the scale-image.

  33. Edmond Says:

    Fantastic ! Thanks for give us those tips :)

  34. mefi Says:

    Nice trick, grat.

  35. leifm Says:

    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?

  36. Jeremy A Says:

    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.

  37. Josh Weihnacht Says:

    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.

  38. leifm Says:

    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.

  39. leifm Says:

    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”.

  40. Max Erickson Says:

    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.

  41. Steve Says:

    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.

  42. Julian Robichaux Says:

    Another fun little image resizing variation to play with:

    http://www.nsftools.com/tips/ImageResize.htm

  43. porto Says:

    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.

  44. Tristan Says:

    Applied in a Zenphoto theme with gradual image loading based on size.

    Thanks a lot for this, it’s very cool.

  45. jb Says:

    Very cool stuff Tristan.

  46. Thomas Boesgaard Says:

    Cool! and thanks.

    /t

  47. Andy Says:

    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/

  48. Josh Weihnacht Says:

    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
    });

  49. Andy Says:

    You’re a star, Josh! Many thanks for your help — it worked perfectly!

  50. Steve Ryan Says:

    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?

  51. Josh Weihnacht Says:

    Well, its possible. In Firefox you can use the max-width/max-height styles to limit the size of an individual image. Unfortunately, IE ignores this super-useful style.

    I haven’t tried this, but if you want to support IE and you don’t mind something a little less elegant, you can pursue this approach. Remove the width=”100%” from the images and scale the images themselves. While scaling the images either give them the scaled width or their max width, whichever if smaller. This implies that you will need to store their max width somewhere (in the ID as a previous poster suggested, in the image name, in a JS arrary, etc). You will likely still need to scale the DIVs themselves to keep the images nicely arranged in a grid.

    Happy coding!

  52. Sten Says:

    Alright everyone,

    I’m making a picture viewer for my personal website at the university.

    I’ve no real knowledge of javacript other than what people have prepackaged. (I can change the target and links but creating the script… not gonna happen.)

    ANyway, I’m wondering if there is a way that a picture can be put into a table so that it will be as big as possible without being bigger than the window. (Like the auto resize option in IE when only veiwing an image… and one can expand it if one wants.

    Is it possible to make the value of the window size to be the value of the picture slider?

  53. Jay Says:

    Could you possibly link a zip file with all the required pages and a simple example of the post? The same prototype file and the same scriptaculous file that you used? I have tried following your instructions as well as making copies of some of the other posted test pages but cannot get this example to work. All I get when I click on the slider is a circle with a line through it. I have all of the appropriate files linked and in the correct directory but cannot figure out why the slider is not activated. I would appreciate any help that you could provide. Also, thanks much for the great article.

  54. Kasper Schoonman Says:

    I’ve got it working, but I’ve got a problem, in FireFox (or any other Gecko based browser) the pictures do not align correct when using pictures with different heights, see screendump:
    http://www.shrani.si/pics/photo-re214009.jpg

    Is there an ‘easy’ solution?

    Thanks,
    Kasper

  55. Jamie Longstaff Says:

    Here’s another working example, this time using images of mixed width and height (some landscape some portrait).

    There are a few bugs like the fact that until the images have all loaded the layout is distorted but other than that it seems to be working fine.

    http://www.photostream.info/image-scaler/

  56. Jamie Longstaff Says:

    After a lot of tweaking, I’ve partially integrated the image scaler into my personal website and added a cookie function to save the previously set image size:

    http://www.interplod.com/

  57. Josh S Says:

    Here is my code and I would really appreciate if someone can enlighten me why my slider is not working?
    It does load all the pic however I can’t move the slider towards my right. Its just static does not move at all. I am new to this and yours HELP would be great.

    Also I am going to load lots of pictures. Is there any way I can seperate pictures according to specific evenets? Such as NewYears Eve (this will have all the pictures from New years Eve 2006). Then Baseball events for Spring 2006 etc.

    Please need yours help.

    Thanks
    ________________________________________________________________________

    Vertical Images Demo

    Vertical Images: Demo

    _______________________________________________________________________________

    Do I need to create this slider_test.css file? If so what would be the content of this file.

    Thank you

  58. Cal Evans Says:

    This is awesome. Thank you so much. I’ve got just the palce for this in my bag-of-tricks.

    =C=

  59. Travis Says:

    I thought the same thing after seeing the fluxiom movie, i figured it all out in my head though.

  60. Screwtape Says:

    This is excellent. I may add this to one of my blogs just to say that I did it =).

  61. Frank Mash Says:

    Thanks John for a wonderful tutorial.

    Can’t wait to try it out.

    Frank

  62. Sumeet Wadhwa Says:

    very interesting stuff…thanks for the resource

  63. James Clark Says:

    I’m having a problem
    THe images are added to the page dynamically using ajax. Everything works fine in firefox but in ie6 only the very first image is resized
    Any ideas, Thanks

    My code:

    function resize(v){

    floorSize = .3;
    ceilingSize = 1.0;
    v = floorSize + (v * (ceilingSize - floorSize));
    for (i=0; i

  64. James Clark Says:

    Rest of code:
    for (i=0; i = scalePhotos.length; i++) {
    var prev = container[i].style.height;
    scalePhotos[i].style.height = (v*190)+’px’;
    var scale = container[i].style.height/prev;
    container[i].style.width = container[i].style.width/scale+’px’;
    }
    }

    //The below code is only run after the page has been updated//
    var demoSlider = new Control.Slider(’handle1′,’track1′,
    {axis:’horizontal’, minimum: 0, maximum:200, alignX: -5, increment: 1, sliderValue: 1});

    container = document.getElementsByClassName(’photocontainer’);
    scalePhotos = document.getElementsByClassName(’photo’);
    demoSlider.options.onSlide = function(value){
    resize(value);
    }
    demoSlider.options.onChange = function(value){
    resize(value);
    }

  65. Guy Heath Says:

    Great stuff.

    I did a version of my own, which can be seen on my site (link below).
    It can deal with images of different sizes (thanks to Jamie Longstaff’s demo for giving me the idea on how to do that) and works in the three major browsers.

    I wrote the slider script myself (for the sense of satisfaction :P).

    Thanks for the inspiration.

    http://www.theejit.com/slider/

  66. Suraj Says:

    Amazing stuff Really good one

  67. Sarge Says:

    I know you didn’t invent this control style exactly but you inspired my Flash version here:
    http://pixelfumes.blogspot.com/2006/04/tray-style-resizer.html. Thought I’d share.
    -Sarge

  68. Matt Says:

    I wanted to do an image resizing site, and I started thinking about how to do it. Then, I remembered this technique.

    Your ideas helped me make my idea better.

    thank you.

  69. Jake Says:

    Nice example! I like it a lot but why not just resize the images instead of having them resized by divs?

    Nonetheless good work…

    Anyone know how to do something to select divs like this?

    http://blog.fluxiom.com/2006/3/29/assets-selected

  70. image resizer Says:

    This powerful and flexible, yet easy to use utility will help you to resize thousands of your pictures. Media Resizer quickly and easily prepares your image collections to be published on the web.

    http://www.purchaseshareware.com/multimedia-design-media-management/media-resizer5201-1.htm

  71. 隔膜压力表 Says:

    I wanted to do an image resizing site, and I started thinking about how to do it. Then, I remembered this technique.

    Your ideas helped me make my idea better.

    thank you.

  72. FP Image Says:

    Thank you very much for this script resource.
    Is it possible to place a link to this resource at
    http://www.featurepics.com/news/PhotographyTips.aspx?
    (Photography tips)

  73. DesignStage.Net Says:

    nice resource…thanks!

  74. Virender Sundriyal Says:

    Very nice and amazing effort. Keep it up.

  75. epeaksoft Says:

    Nice example! I like it a lot.
    http://www.epeaksoft.com/service/odc.htm

  76. Pi Says:

    for some reason i got the error msg:

    this.track has no properties

    in the slider.js on row 175
    anyone know why?

  77. Web Marketing Mentor Says:

    Great tutorial, worked well for me on my new site.

  78. Aamir Says:

    well i have implemented that on my site, offering free image hosting… altered bit of the code to fix the portrait and landscape images to fix in a specific space…

    very beautiful code

    http://www.aalaphotos.com

  79. Angel Says:

    Excelent

  80. Muhammad Qaiser Mughal Says:

    hello nice work keeptup

  81. rami kantari Says:

    great site and interesting too.

  82. contactos Says:

    Very nice! Thanks a lot

  83. Andrew Says:

    Works great on Firefox 2 , but slow on IE7…

    Good Stuff !! Thanks for sharing.

  84. suan Says:

    hey
    cool tut
    does this work for videos as well??
    thx

  85. ciuli Says:

    looks great and working allmost perfectly becose it has some bugs , on Opera 9.20 the slider is working in mirror mode and on IE7 Mozzila and Opera the small image inside the slider it cannot go to full right
    maybe you can help with this issue?!
    thanks

© 2005 Agile Partners Corporation