Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resize and Center image with jQuery

Looks like I haven’t explained myself well. I do apologize for that.

I have edited this question to make it more clear.


The scenario

We have a website that doesn’t host the images. What it does is a reference to an image in other server.


The plan

  • Resize images keeping proportions.
  • Center resized images.
  • Flexible so it can fit in several sizes.

The bug

My code works as intended, however there is a Bug that only happens sometimes.

If you go to the search page of the website, and swap between page 1, 2, 3 and 4 a couple of times, you will notice that sometimes the images are good… other times they appear aligned left, and do not take up the full container area.


The links

The full website (in beta)

The JavaScript File

The jQuery plugin that helped me (jThumb)


The plan (detailed version)

Let’s say that the image is 600x400 pixels (remember they are not hosted on this server), and with jQuery and CSS, I want to resize the image (keeping proportions) in to a container of 310x200 pixels.

The other challenge is to center the image.

All this has to be flexible because there are several different containers sizes in the website.


What I have done so far (you can find this in the link above)

To resize the image I'm doing:

var img = new Image();
img.src = $(this).attr("src");
var width = $(this).css('width');
var height = $(this).css('height');

var photoAspectRatio = img.width / img.height;
var canvasAspectRatio = width.replace("px", "") / height.replace("px", "");

if (photoAspectRatio < canvasAspectRatio) {
    $(this).css('width', width);
    $(this).css('height', 'auto');

    var intHeight = height.replace("px", ""); //tirar o PX
    $(this).css('marginTop', (-Math.floor(intHeight / 2)));
}
else {
    $(this).css('width', 'auto');
    $(this).css('height', height);
}

$(this).wrap('<div class="thumb-img" style="width:' + width + ' ;height:' + height + ';"><div class="thumb-inner">' + '</div></div>');

To center the image I’m doing:

jQuery(this).css('position','absolute');
jQuery(this).left( '-' + ( parseInt( $(this).width() ) / 2 ) + 'px' );
jQuery(this).top( '-' + ( parseInt( $(this).height() ) / 2 ) + 'px' );
jQuery(this).css('margin-left', '50%' );
jQuery(this).css('margin-top', '50%');

like image 872
Marco Avatar asked Oct 21 '10 12:10

Marco


2 Answers

There's a far simpler solution to determine how to resize and position the image. It will work with all image and container sizes.

var canvasWidth = parseInt(width);
var canvasHeight = parseInt(height);

var minRatio = Math.min(canvasWidth / img.width, canvasHeight / img.height);
var newImgWidth = minRatio * img.width;
var newImgHeight = minRatio * img.height;

var newImgX = (canvasWidth - newImgWidth) / 2;
var newImgY = (canvasHeight - newImgHeight) / 2;

Now just position the image using newImgX, newImgY, and resize it to newImgWidth, newImageHeight.

like image 165
Scott S Avatar answered Nov 20 '22 21:11

Scott S


This is probably a race condition. You are setting the img src and then immediately trying to get its width and height attributes. But there is no guarantee that the web browser has downloaded the image or pulled it from the browser cache yet, and if it hasn't, your code will lead to unexpected results.

You need to do something like this:

var img = new Image();
var $thumb = $(this);

img.load(function() {
  /* .....[image calculation and resize logic]..... */
});

img.src = $thumb.attr("src");

Note that the order of the above statements is very important -- you must attach the img.load event handler first, then assign the img.src second. If you do it in the other order, you will end up with an opposite race condition (the image may already be loaded after the img.src assignment, in which case the event handler will not be called in all browsers -- by setting the event handler first you ensure that it will be called after the img.src assignment even if the image is already loaded).

Also, note the $thumb definition at the top. This is because "this", inside the img.load function, will be a reference to the new "img", not the thumbnail element. So your logic will have to reference "$thumb" for the DOM element and "this" (or "img") for the in-memory image.

Also, for the actual logic take a look at the answer "Scott S" provided above. His suggestion looks simpler than what you have.

like image 1
Ben Lee Avatar answered Nov 20 '22 21:11

Ben Lee