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"
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?
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.
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?
Can you be more specific as to what's going on? i.e. Are you getting any errors or console messages?
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?
Please take a look at the demo again and let me know if its working now.
Thanks
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
Not 100% what it is, but it's happening on a couple of my demos.
// 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.
.msie ul#productGrid li { /* fOR IE **************/
margin: 0;
}
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.
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.
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:
I haven't tested anything above, so it might not work exactly, but hopefully that makes sense.
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