javascript, get size of a background scaled with contain property - javascript

I've seen a few posts here trying to answer this question and I tried using the codes given as answers but haven't been able to get it to work, so I must be doing something wrong. Basically I have a div with a background-image with the CSS property "background-size: contain". I want to get the dimensions of the scaled background. Here is my code, mostly copied from another post here, with some things changed to match my div's names:
var elem = document.querySelector("#enlarged-inner .image-bg");
function getBackgroundSize(elem) {
elem = document.querySelector("#enlarged-inner .image-bg");
//get original background size
var computedStyle = getComputedStyle(elem);
var img = new Image;
img.src = computedStyle.backgroundImage.replace(/url\((['"])?(.*?)\1\)/gi, '$2');
var imgW = parseInt(img.width, 10);
var imgH = parseInt(img.height, 10);
//get scaled size
var newW = parseInt(computedStyle.width, 10);
var newH = parseInt(computedStyle.height, 10);
var scaledW = 0;
var scaledH = 0;
scaledW = imgW / imgH * newH;
scaledH = imgH / imgW * newW;
}
window.onresize = function(){ getBackgroundSize(elem); }
Its able to get the original (unscaled) size of the background image just fine, so I atleast know that the first half of the code is working. But the second part, the important part, doesn't seem to do anything. I've been testing it by changing a test divs innerHTML to the new variables:
document.getElementById("test").innerHTML = newW + " , " + newH;
I'm new to javascript and not great at math so I'm sure theres probably something I'm just not understanding correctly here.
EDIT: the code above has been updated a little and heres some more explanation.
So in this picture the blue box is a scalable div that contains the div with the background. Its height and width are set with vh and vw.
The gray box represents the background image itself, with its size set to contain. In the updated code above, newW and newH give me the dimensions of the blue box, no matter how its scaled. imgW and imgH give me the original unscaled dimensions of the background. I want scaledW and scaledH to return the scaled size of the gray box, but my math doesnt seem to work out.

I can't test it right now but I think that the variables you're modifying (newW and newH) are passed by value. So, you actually don't update your image's size. You'll probably need to use these variables to update your image's size, maybe with:
img.width = newW etc

I figured out a simpler way to achieve what I wanted. Basically what I was trying to do was have a div with an image in it, that I could scale to any size, and the entire image would always fit inside the div (similar to the background-size contain property), and the images would always maintain their original aspect ratio. In my particular case instead of a div, its the size of the full window, and I found it to be easier to work with images in img tags instead of backgrounds. Heres the code:
function getBackgroundSize(elem) {
elem = document.querySelector("#enlarged-inner img");
var imgW = elem.naturalWidth;
var imgH = elem.naturalHeight;
var newW = window.innerWidth;
var newH = window.innerHeight;
var imgRatio = imgW / imgH;
var newRatio = newW / newH;
var scaledW = 0;
var scaledH = 0;
if (imgRatio > newRatio) {
scaledW = newW;
scaledH = imgH * newW / imgW; }
else {
scaledW = imgW * newH / imgH;
scaledH = newH; }
document.querySelector("#enlarged-inner img").style.width = scaledW;
document.querySelector("#enlarged-inner img").style.height = scaledH;
}
I basically just found the unscaled height and width of the image, and the dimensions of the containing div (the window in my case), and then found their ratios of width over height. I'm not so good at math but atleast in the examples I tried to work out, if the W/H of the image was larger than W/H of the window, it would mean the image's width would be defined by the width of the window. And then the correct height of the image could be found with some simple math.

Related

Fill window with divs. Div pixel height displayed incorrectly in google chrome. Width works

I want to fill the window size with divs. For a specified div size in px, the screen will be filled as much as it can be, leaving a remainder edge amount of px on the side and bottom. This remainder amount is then divided by the number of cells in the row (or column) and that is then added to the height (or width) of each cell in the row (or column).
For the width this works perfectly but when the same logic is applied to the height, it breaks. Both width and height work in firefox.
Screenshot: http://i.imgur.com/mpDCM0G.png
JSfiddle of making the divs: https://jsfiddle.net/xb82c4zt/
Live: http://conwaygameoflife.heroku.com/
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var size = 100;
// Calculate the number of cells we can fit in the width
//and height (there will be extra space)
w = Math.floor(windowWidth / size);
h = Math.floor(windowHeight / size);
// Calculate the extra space
var widthDiff = windowWidth % size;
var heightDiff = windowHeight % size;
// Add the needed amount of height and width to each cell to fill the window
var widthSize = size + widthDiff / w;
var heightSize = size + heightDiff / h;
// Begin to alter the DOM
var parentDiv = document.createElement('div');
parentDiv.className = 'grid';
for(var y = 0; y < h; y++) {
for(var x = 0; x < w; x++) {
var cellDiv = document.createElement('div')
cellDiv.className = 'cellDiv'
cellDiv.style.height = heightSize + 'px';
cellDiv.style.width = widthSize + 'px';
parentDiv.appendChild(cellDiv)
}
}
document.body.appendChild(parentDiv)
In Chrome (and probably other browsers), height and width pixel values are truncated! See this stackoverflow answer with the related jsFiddle
Precentage values are truncated too, but not as severely. So, to solve this you can convert pixels to percentages as I did in this jsFiddle.
The main thing I added was:
var widthPercent = widthSize / windowWidth * 100;
var heightPercent = heightSize / windowHeight * 100;
Because we're using percentages now, the parent container must have width/height:
parentDiv.style.height = windowHeight + 'px';
parentDiv.style.width = windowWidth + 'px';
And changed the loop to:
for(var x = 0; x < w*h; x++) {
var cellDiv = document.createElement('div');
cellDiv.className = 'cellDiv';
cellDiv.style.height = heightPercent + '%';
cellDiv.style.width = widthPercent + '%';
parentDiv.appendChild(cellDiv)
}
Now this doesn't always work in chrome perfectly. However, it does make it perfect in some cases... basically depends on when (and how drastic) the truncation of percentages is.
After further reflection, it looks like percentages get resolved to fractional pixel values as well... which still get truncated in Chrome. So, let's make our math better, and figure out the biggest non-fractional pixel value we can use... it's actually really easy. See here
Basically, we just floor the values, then center the grid so that we can make it look nice.
edit: wasn't very happy with this answer, so screwed with it some more. Added a function that found the closest multiple of window size and made it so that it would prefer that number. Makes it work in most screen sizes, and has a fallback to the percentage method if it doesn't perfectly work. See here. However, because it relies on a recursive (naive) algorithm to find the closest multiple, it's really easy to screw your browser performance. Limiting to only 5-10 pixels of search space helps. The gist of it:
function closestMultiple(width, size, n, limit) {
if(n > limit) {
return {m: width/size, s:size};
}
if((width % (size+n)) == 0) {
return {m: width / (size+n), s: size+n};
} else if((width % (size-n)) == 0) {
return {m: width / (size-n), s: size-n};
}
return closestMultiple(width, size, n+1, limit);
}
It's very naive and ignores things like "an odd width will never be divisible by an even number"... so there's a ton of room for improvement. Check out this discussion and this discussion for more on this.

Retrieve a rendered background image's dimensions with jQuery

I have a page with a list of items where each item has a square div containing a background image. This image can have dimensions which are either bigger, or smaller than the div itself. The background centered and contained in the div so it is always shown in the middle of the div.
The css for this is as follows:
.productImage
{
width: 225px;
height: 225px;
background-size: contain;
background-position: center center;
background-repeat: no-repeat;
margin-left:70px;
}
The background-image itself is set using a jQuery call that modifies the css of the div.
This works like charm, however I would like to know the dimensions of the rendered background image. If the rendered is smaller than a specific dimension I would like to set a background color for aesthetic reasons.
I am currently unable to retrieve the dimensions of the rendered images. I have used the following code in a loop to try and retrieve the dimensions of the images, but this returns the original dimensions of the images, before they have been scaled into the div.
images[i] = new Image();
images[i].src = $('#image'+i).css('background-image').replace(/"/g,"").replace(/url\(|\)$/ig, "");
images[i].pos = i;
images[i].onload = function() {
var position = this.pos;
width = this.width;
height = this.height;
console.log("For image "+position+" the height is "+height+" and width is "+ width);
}
How would I be able to find out the dimensions of the rendered background image using jQuery or pure Javascript? Is this even possible?
Thanks in advance.
After playing with Huangism's idea a bit I came to the following solution:
images[i] = new Image();
images[i].src = $('#image'+i).css('background-image').replace(/"/g,"").replace(/url\(|\)$/ig, "");
images[i].pos = i;
images[i].onload = function() {
var position = this.pos;
width = this.width;
height = this.height;
var divwidth = $('#image'+position).width();
var divheight = $('#image'+position).height();
var ratioH = divheight / height;
var ratioW = divwidth / width;
var scaleW = width * ratioH;
var scaleH = height * ratioW;
console.log("For image "+position+" the height is "+height+" and width "+ width +" and ratioH "+ratioH + " and ratioW " + ratioW +" (Scaled width: "+scaleW+")" );
if(scaleW < 120 || scaleH < 100){
$('#image'+position).css('background-color', 'red');
}
}
This code compares the image used as a background image's height and width with the dimensions of the div he is contained in. Based on this I calculate the scaling ratio between the original height and width and the maximum height and width within the div.
This ratio is then multiplied with the opposing dimension (height * width ration, width * height ratio) to calculate the dimensions of the rendered image.
Comparing the values in the console to measurements in Photoshops shows they are a perfect match!
I hope this answer can help other users that want to know the dimensions of a rendered background image.
Give the image an id then:
var width = document.getElementById('myImageID').offsetWidth;
var height= document.getElementById('myImageID').offsetHeight;

Detect percent on screen of an element

I'm trying to detect what % of the element can be seen on the current window.
For example, if the user can only see half the element, return 50. If the user can see the whole element, return 100.
Here's my code so far:
function getPercentOnScreen() {
var $window = $(window),
viewport_top = $window.scrollTop(),
viewport_height = $window.height(),
viewport_bottom = viewport_top + viewport_height,
$elem = $(this),
top = $elem.offset().top,
height = $elem.height(),
bottom = top + height;
return (bottom - viewport_top) / height * 100;
}
But it doesn't seem to be working. Can anyone help me out in achieveing this I seem to be spinning gears.
What you want to get is the amount of pixels that the element extends past the top and bottom of the viewport. Then you can just subtract it from the total height and divide by that height to get the percentage onscreen.
var px_below = Math.max(bottom - viewport_bottom, 0);
var px_above = Math.max(viewport_top - top, 0);
var percent = (height - px_below - px_above) / height;
return percent;
One thing to note is that jQuery's height method won't include padding. You probably want to use .outerHeight for that.
Your $elem = $(this)assignment seems wrong, here function scoping means this refers to the function you're in (ala ~ the function getPercentOnScreen), try referencing by $elem = $('#yourElementId')instead.
if you only want to calculate percent of element then just do this
function getPercentOnScreen(elem) {
$docHeight = $(document).height();
$elemHeight = $(elem).height();
return ($elemHeight/$docHeight)* 100;
}

Is it possible to measure the resulting background image when using background-size: cover with Javascript?

I want to know if it's possible to determine the (new) dimensions of a background image after it has been resized with css3's 'background-size: cover' using Javascript.
(Not working) Example: http://jsfiddle.net/daco/GygLJ/3/
Cheers,
Daco
I don't know enough pure JS to post this without assuming jQuery but it can probably be ported easily.
What you could do is find the src of the background image, then use javascript's built in width / height functions to get its dimensions.
eg:
//jQuery
var imgSrc = $('#test').css('background-image');
//might need to do a bit of parsing on that, returns: url(http://blahblah)
alert(imgSrc);
imgSrc=imgSrc.replace('url("', '').replace('")', '');
alert(imgSrc);
var newImg = new Image();
newImg.onload=function()
{
var h = newImg.height;
var w = newImg.width;
alert('w:'+w+' h:'+h);
};
newImg.src=imgSrc;
Hope this helps
Example here: http://jsfiddle.net/vap8p/
EDIT: updated source and linked to working example
Assuming background-image css for element with ID 'mydiv'. All native JavaScript. Won't interact with other JavaScript on page.
(function (id) {
var img = new Image(), elm = document.getElementById(id);
img.dataset.w = elm.offsetWidth;
img.dataset.h = elm.offsetHeight;
img.addEventListener('load', function () {
var maxw = this.dataset.w,
maxh = this.dataset.h,
aspect = this.width / this.height;
if(maxw > maxh * aspect) alert(maxw + ' x ' + maxw / aspect);
else alert(maxh * aspect + ' x ' + maxh);
}, false);
img.src = window.getComputedStyle(elm).backgroundImage.slice(4, -1);
})('mydiv');​
You might want to round down.
For contain rather than cover, change the compare to the opposite.
if(maxw < maxh * aspect) alert(maxw + ' x ' + maxw / aspect);

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%');
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.
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.
It's not clear from your question, but I'm assuming one your issues is the left-align of the images in the table at the bottom half of your front page at http://www.algarvehouses.com.
The issue here is not your jQuery code, rather it is your CSS.
add a text-align: center to your thumb-inner class. Then make sure that rule is loaded AFTER the "table.dlRandom img, ..." rule - or remove the display:block from that rule. That should center those images.
Generally though - to scale the image, your logic looks correct up to the point of the div. Don't quite understand that logic. You don't need to set the auto size though, just restrain the dimension that is required.
One tangential tip - in the code above you reference $(this) no less than 16 times. Do this at the top of the function, and use it from there on:
var $this = $(this);
I really didn't get your question but this maybe be help you.
function resizer(imgCls, maxWidth, maxHeight) {
var img = $('img'), imgWidth, imgHeight;
img.each(function () {
imgWidth = this.width;
imgHeight = this.height;
if (imgWidth > maxWidth || imgHeight > maxHeight) {
var widthFact = maxWidth / imgWidth;
var heightFact = maxHeight / imgHeight;
var chooseFact = (widthFact > heightFact) ? heightFact : widthFact;
imgWidth = imgWidth * chooseFact;
imgHeight = imgHeight * chooseFact;
}
})
}
this code gets the images matches the provided className and looks your arguments. pass maxWidth to your maxWidth value such as 300 px, and pass maxHeight to your images maxHeight such as 300.
then the function will loop for every image and checks its width and height. If its width or height is larger than your max values then it will be resized by keeping the aspect ratio.
Please let you free to ask more question about the issue and please be more clear.
This script will shrinks, and align image depending of their orientation. Image is rounded with div ho has fixed width and hight, and also a style set to overflow:hidden. The script actual recognize the image orientation and ad to image a margin-left or margin-top in minus atribute to style depending of a image vertical or horizontal orientation.
CSS:
<style type="text/css">
.thumb {
width:160px;
height:160px;
overflow:hidden;
}
</style>
jquery with javascript:
window.onload = function() {
var images = $(".image_center");
for(i=0; i<images.length; i++)
images[i].onload = centerImage(images[i]);
function centerImage(img) {
if (img.width > img.height ) {
var y = 160;
var x = img.width/img.height*y;
var marx = (x-y)/2;
img.style.height = y+"px";
img.style.marginLeft = -(marx) + "px";
}
if (img.width < img.height ) {
var x = 160;
var y = img.height/img.width*x;
var mary = (y-x)/2;
img.style.width = x+"px";
img.style.marginTop = -(mary) + "px";
}
}
}
HTML:
<div class="thumb"><img class="image_center" src="sa.jpg" alt="#" /></div>
<div class="thumb"><img class="image_center" src="sb.jpg" alt="#" /></div>
You can see demo here: Link
Another useful plugin which achieves this is jQuery Center Image which supports two modes. One to fill the entire space by cropping and resizing the image and another which emulates max-width/max-height to resize to fit within the space.

Categories