CJ Object Scaler 2.0.1

A JQuery Plug-In to Scale Objects to Fit or Fill Within Another Object

Project Description

CJ Object Scaler will scale an object to either fit or fill within the boundaries of a destination object. I based this plug-in off another JavaScript project I made awhile back, you can read what it does in the CJ Image: Easily Calculate Image Scaling blog enry. It was a nice little function that would help you calculate the size and offsets to use when scaling an image to fit (or fill) within another element. It didn't actually do any scaling, per say, it merely provided you with the numeric amounts to use. The function introduced two scaling methods, Scale To Fit and Scale To Fill.

Example Usage

As always, I've tried to keep things simple. To use the CJ Object Scaler v2.0, you first need to include the script in your page header. Once you do this, you need to have something to scale and something to scale into. Let's assume you have some product images displayed in a grid on a page. It might look something like this:

<ul id="productGrid">
    <li class="product"><img src="images/jacket.jpg" alt="Jacket" /></li>
    <li class="product"><img src="images/hat.jpg" alt="Hat" /></li>
    <li class="product"><img src="images/coat.jpg" alt="Coat" /></li>
    <li class="product"><img src="images/bunnySlippers.jpg" alt="Bunny Slippers" /></li>
</ul>

The plug-in will try it's best to determine what the object dimensions are. So it's not really necessary to provide this information, but I'm not sure how older browsers handle this with images. It might be good practice to include the width and height on those. Also, the plug-in is going to automatically center the object within the destination object. To do this it will apply an absolute positioning to the it. To work properly, the destination object must have it's positioning set to either relative or absolute. The CJ Object Scaler will try to determine if this is set. If not, it will set the positioning to relative. Here's the CSS for this example:

ul#productGrid {
    display: block;
    width: 100%;
    height: auto;
    margin: 0;
    padding: 0;
    list-style: none;
}

ul#productGrid li {
    position: relative;
    display: block;
    width: 190px;
    height: 150px;
    border: 1px solid #ccc;
    float: left;
    margin-right:
    10px; margin-bottom:
    10px; overflow: hidden;
}

And here's how you would call the plug-in to begin your scaling:

$("#productGrid li img").cjObjectScaler({
    destObj: $("#productGrid li img").parent("li"), // must be a jQuery object (required)
    method: "fit", // can either be fit or fill (default fill)
    fade: 800 // if a positive integer, will hide and fadeIn object n duration (default 0)
});

If you notice, I am passing the parent of the current image to the function. The destObj must be a jQuery object. If you are using selectors to choose your objects, be sure you are passing the objects parent. Since in our example, all the <li>'s are the same size, you could in theory pass the first occurrence of one to the plug-in and everything would still look the same. You can also specify which scaling method to use. Your options are "fit" and "fill" (fill is the default). The last option, fade, determines if you would like to hide your object(s) and then do a fadeIn once the scaling is complete. If you provide a positive integer, this will determine the fadeIn duration in milliseconds. The default value is 0, which does not do the effect.

14 responses to "CJ Object Scaler 2.0.1"

rouademunte
Just wanted to say great job with the blog, today is my first visit here and Ive enjoyed reading your posts.
Doug
Doug responds:
@rouademunte - Thanks! I appreciate it. I'm currently working on a new blog, that I think everyone is going to like even more. I haven't posted on this one in awhile, because I'm hoping to launch shortly. Check back in about a week or so. I hope to have it completed and I have a new JQuery Plug-In that everyone is going to love!
Uday Kari
Hi. Your online demo was not working today in Firefox 3.5.7. First (left-most: jacket) image does not load in IE version 7.0. Worked in Safari 4.0.3, Chrome 3.0.195.

I wrote a similar script. The problem I faced was that Safari, Chrome and Firefox have to cache an image FIRST and only then you are able to determine the size (height, width) of the image object. Otherwise, the sizes are zero in the "first-access". Microsoft IE is able to determine the size without caching. I solved (hacked) this issue by leveraging the fact that those three non-IE browsers understand CSS directives for max-width and max-height and so "fitting" is easy.

Does this make sense? Did you find a workaround to this in your package?
Doug
Doug responds:
@Uday Kari - Yeah, this is a problem that you'll run into with any older browser. I'm sure there's hacks out there, but I've been focusing on the "modern" browsers lately.

If you look at the code, you'll see this block towards the bottom:

// run our scale function. Special case for images, we need
// to make sure the image has loaded in order to get the width & height
if ($(self)[0].nodeName === "IMG") {
// check to see if the image is already loaded
if ($(self).attr("complete")) {
scale($(self)[0]);
} else {
$(self).load(function () {
scale($(self)[0]);
});
}
} else {
scale($(self)[0]);
}

What I'm doing here, is that if you are using the scale function on IMG tags, then it will try to wait until the image is loaded, it looks for the "complete" attribute, if it's not there then it will try to "load" the image and then call the scale function.

Like I said, there's some hacks out there, so you could actually change this block that does some more checks.

Hope this helps.
cedricn
Very useful plugin! But is there a way to keep the image quality when it's resized (smaller or larger)?
Ved
Ved says:
The examples dont work on FF 3.5, 3.6 or 3.7 or minefield alpha. Works only with Chrome.
Its a pity that such a great plugin does not work with the most latest browsers. Can you please give a workaround to fix this?
Doug
Doug responds:
@Ved - Hey now, I try to take pride in making everything cross-browser compatible. I design everything in Safari (Webkit) and then test in FireFox and IE.

Can you be more specific as to what's going on? i.e. Are you getting any errors or console messages?
tperri
tperri responds:
@Doug - In FireFox 3.5.7, I am not seeing any images load into the boxes.
Doug
Doug responds:
@tperri - yeah, something weird is going on. I'm going to try and take a look at it this weekend.

It might be because I was dynamically loading the images from Google, which really has nothing to do with the CJ Image Scaler code. I might have to take that out and just use some images off of the server.

Has anyone downloaded the code and tried using your own images?
Doug
Doug says:
Ok, I removed the code that was dynamically pulling the Google images. I think this was causing the problems.

Please take a look at the demo again and let me know if its working now.

Thanks
Justin
Justin responds:
@Doug - First off, great little plugin! Man this is a killer tool to have in your arsenal when you don't want to directly monitor your customers image sizes, or reuse images throughout the whole site...

Quick Q though, I am fairly new to jquery, but I noticed that for some reason when i include a "resized" image in a div, the "containing" div doesn't seem to acknowledge the existance of the images. My page grows and expands all fine and good, but if i put a border around that containing div, it seems to only be like a pixel tall.

I am chalking this up to inexperience, but does this have something to do with the containing div being built in HTML and the images themselves afterwards in the Ready function of jquery?

Thx and great plugin!

PS: FF 3.0.18 - no images in your demo ... :D
Slavi
Slavi says:
with FF 3.6. no images either.
Doug
Doug says:
For people having problems with the images not loading in the demo, try forcing a reload of the iframe page. There seems to be a caching problem going on.

Not 100% what it is, but it's happening on a couple of my demos.
cphilippsen
If there a way to deactive the function, thinking of using this for a click-function use.
Doug
Doug responds:
@cphilippsen - Sure, open up the file and wrap the follow:

// if the user supplied a fade amount, hide our image
if (settings.fade > 0) {
$(self).hide();
}

// run our scale function. Special case for images, we need
// to make sure the image has loaded in order to get the width & height
if ($(self)[0].nodeName === "IMG") {
// check to see if the image is already loaded
if ($(self).attr("complete")) {
scale($(self)[0]);
} else {
$(self).load(function () {
scale($(self)[0]);
});
}
} else {
scale($(self)[0]);
}

with this:

$(sys.elem).bind("click", function() {

... the above code goes here.

});

That should do the trick. Let me know if that doesn't work.
Edwood
Edwood says:
IE8 sqaushed the images and had a thick white border around it. I suggest the following fix in the css

.msie ul#productGrid li { /* fOR IE **************/
margin: 0;
}
innstudio
One thing I noticed, and it gave me a few seconds to figure out, is that since the function resets the parents position to relative, if you have this set in any complex layering or an overflow, it can run into issues, especially in IE.
Doug
Doug responds:
@innstudio - It will check to see if the parent element has it position set to either absolute or relative, if it's not one of those it will set it to relative.

Pretty much any "complex" layouts are going to be positioned with absolute or relative. So all you have to do is make sure you set the element in your CSS. (Unless you are doing fixed, in which case, just create another wrapper inside for the object scaler)

I forget why I did this, but I'm pretty sure because if the element was not set to either of these it failed miserably in IE.

EDIT: If your still having issues, post an example of the problem and I'll take a look.
Abhijit
Really great plugin & nice blog. I would love to use this on my website.

How to show loading animation while image is loading? This will keep users interested if loading image is big in size.

Please help me on this. Many Thanks.
Doug
Doug responds:
@Abhijit - I would just do this with CSS. Maybe add a animated GIF as the background image. Once the image loads, it should cover it up.
Abhijit
Abhijit responds:
@Doug - Thank you for the pointer. If possible can you show some example. Keep the good work going.
Matt
Matt says:
Is it possible to have this appear in two spots in the same page, with each being displayed at a different size? I believe I've set up everything properly, but the second one's still retaining the first's new dimensions.
Doug
Doug responds:
@Matt - Yeah, it should work on multiple objects. Do you have a link where I can look at what your doing?
camnz
Great plug-in, got it integrated really quickly and it looks good. Just a quick questions, if I wanted <a> tags around the <img>, what would the javascript function change to, I cannot work it out. Thanks in advance
Doug
Doug responds:
@camnz - The problem is that the script is creating an array of img src's and using two <div> blocks to do the manipulation. The images are then hidden after they are all read in. What you are going to need to do is add another array that captures any links you might have around your images. You should do this in the init() function. Then once an image is read in and placed in the <div>, you will need to set an onClick handler on the "cjFancyTransition" block that handles the user click. Something like:

$(sys.elem).click(function(){
   if(sys.links[sys.current_blocks] !== null) {
      document.location.href = sys.links[sys.current_blocks];
   }
});


You will need to create the "links" array and place it in the "sys" var up top. Hope that makes sense.

In the init() you could loop through all the "found" imgs and check to see if it's parent has a <a href=""> parent... something like:

for (i=0; i<sys.imgs.length; i++) {
   var pn  = $(sys.imgs[i]).parent().get(0);
   if (pn.nodeName === "A") {
      sys.links.push($(pn).attr("src"));
   } else {
      sys.links.push(null);
   }
}


I haven't tested anything above, so it might not work exactly, but hopefully that makes sense.
Funger
Doug,
Great plugin! I am running into a problem though when I try to use it more than once.

I have the following code:

CSS:
#ParticipantPhoto{
width:320px;
height:230px;
border:solid 1px black;
}

HTML:
<div id="ParticipantPhoto">
<img src="" alt="Participant Photo" />
</div>
<button id="MyButton">Click Me</button>

JAVASCRIPT:
$("#MyButton").click(function(){
$("#ParticipantPhoto img").attr("src", newPhotoPath);
$("#ParticipantPhoto img").cjObjectScaler({
destObj: $("#ParticipantPhoto"),
method: "fit"
});
});

For simplicity, I didn't include the logic that changes the value of the newPhotoPath variable, but assume that the value of it changes before each time the user clicks the button.

When the user clicks on the button the first time, the plugin works like a charm. Any subsequent clicks, and jquery throws an error.

Any ideas?

Thanks!

-Funger
Doug
Doug responds:
@Funger - Take a look at v2.1. This one should take care of any issues you might have been having.

Comments are closed.