Scale images match css selector relative to their size - javascript

I have to scale down images which match the following selectors:
img.math
div.math img
The problem is that I have to scale images down twice their own size — that is relative to their own size. It seems that it is only possible with javascript:
css tricks with width scale images relative to the current line witdth
css tricks with transform leave empty space
I found a js function which scales an image down here:
function Resize(imgId)
{
var img = document.getElementById(imgId);
var w = img.width, h = img.height;
w /= 2; h /= 2;
img.width = w; img.height = h;
}
the problem now is to apply that function to image matching the above mentioned selectors.
I use jQuery 1.11 and something like this is due:
// resize all math images:
$(document).ready(function() {
$("img.math").each(function() {
// ???
});
$("div.math img").each(function() {
// ???
});
});
(this is a part of the larger (function ($) { }(window.$jqTheme || window.jQuery));)
Edit:
img.math is just an inline image. While div.math img is a numbered math equation: it also contains the equation number, which is span floated to the right.
Edit 2: Complete html section sample
The html involved is pretty basic:
<div id="math" class="section">
<span id="id1"></span><h1>Math</h1>
<p>In-line equation: <img alt="a^2+b^2=c^2" src="_images/math/ee657daf07808119b97144fc459a5dc8839eb9c9.png" class="math">.</p>
<p>Numbered equation:</p>
<div id="equation-pythag" class="math">
<p><span class="eqno">(1)</span><img alt="a^2 + b^2 = c^2" src="_images/math/53158707cc080d32d0d2f081e4bf5c6988f437ca.png"></p>
</div><p>Link to equation: (1).</p>
</div>
All images staically positioned: img.math is just an inline image, while div.math img is horizontally centered in a div.

This is not enough information to post in a comment, but it isn't enough for an answer.
Still, I will answer it.
Your code has to be rewritten to the following:
// resize all math images:
$(function() {
$("img.math, div.math img").each(function() {
this.width/=2;
this.style.height='auto'; //ensures proportion
this.style.verticalAlign='middle';
});
});
All that boilerplate code can be safely eliminated.
I've removed the line this.height/=2; because the O.P. stated that it was causing his images to deform.
I've added the line this.style.height='auto'; as suggested by #MorganFeeney.
It helps to ensure proportion to the image resize, in case an height it set.
Also, as the O.P. pointed out, it was needed to set this.style.verticalAlign='middle';.
If you are having problems with alignments, this might help. Or you can try the values inherit or top.
This method can be a little inaccurate in some situations.
For that, I recommend reading How do I get natural dimensions of an image using javascript or jquery? to get the original width and height of your image.
Also, you can read this interesting comment for a cross-browser solution.
As a side note:
$(function(){});
Is equivalent to:
$(document).ready(function(){});

Related

How to size images loaded from other users such that dimensions are maintained yet a max width and height are set with css? (HTML/JS/CSS)

I want to know how, within say a div element, I can load an image from an API (where the user may post whatever size image they want) and I can then format that image to meet the following requirements with CSS.
1) the original dimensions are maintained
2) given a max width and max height that I specify, the attribute of the image out of my control that differs greatest from the corresponding attribute in my specification will be shrunk down to match it, with the other attribute shrinking to maintain dimension. If the image is in fact smaller on both dimensions than my specifications than the dimension of the image that differs the LEAST from its corresponding specification should grow to match it, with the other one again moving to maintain dimension.
3) The image should center itself in it's parent node depending on whether it is the width or the height specification that is not maxed out (ie: if max_width was 200px and images width was only 180 then it should center itself along the x axis).
I suppose I could do it with JS, but I imagine its a common enough desire that there is an easier way to do it than logically inputting it. (Also how with JS can I get access to the height and width attributes of the user uploaded images coming in from the JSON file, and how in JS can I center an image within it's parent node?):
JS/Pseudo code mix looks like this, but I want to know how to do it in CSS if possible:
var body = document.getElementsByTagName('body')[0];
$(document).ready(function(){
var maxHeight = whateEverWeSpecify;
var maxWidth = whateverWeSpecify;
$.getJSON('jsonFileWithPropertyImagePointingToUserUploadedImage', formatImg);
});
function formatImg(json){
var div document.createElement('div');
var img = document.createElement('img');
img.setAttribute('src', json.image);
**//this is the part I dont know how to read dimensions of** incoming image so ill use img.height and width.height to refer to dimensions of incoming JSON img here
var heightDifference = img.height - maxHeight;
var widthDifference = img.width - maxWidth;
if (widthDifference < 0 && heightDifference < 0){
if (heightDifference < widthDifference){
img.style.height = img.height + heightDifference;
}
else{
img.style.width = img.width + widthDifference;
}
}
else{
if (heightDifference > widthDifference){
img.style.height = img.height - heightDifference
}
else{
img.style.width = img.width - widthDifference
}
/*sizes are adjusted to fit specifications at this point. I have no idea
how to center the image along the y or x axis depending on which one is
required other than that we can determine which to change based on which
attributes difference from the specification is greater than 0 (in
essence, which attribute was updated), so if you could help me with this
too for future reference I would greatly appreciate it */
}
}
Try setting a div with the 'background-image' property, and use 'background-size:contain'.
I had this same kind of problem when trying to handle profile pictures in a dating website I was building. You never know if the user is gonna upload a tall or wide picture.
HTML:
<div class="outer">
<div class="image_container"></div>
</div>
CSS:
.outer {
background:lightgray;
width:800px;
height:500px;
}
.image_container {
position:relative;
height:80%;
width:80%;
left:10%;
top:10%;
background-image:url('http://icatcare.org/sites/default/files/kcfinder/images/images/aggressive-cat_0.jpg');
background-repeat:no-repeat;
background-size:contain;
background-color:darkgray;
background-position:center;
}
Here's the codepen. Un-comment the second background-image line to see how this works with a tall image: centered background image.
I put a darker grey background on the inner div just to show you that the div stays at the proportions you set, the CSS handles images of varying sizes within. This solution at least keeps your layout from floating or wrapping oddly based on changing image sizes.
Don't use an <img> tag. Instead, use the background-image property in CSS. This gives you access to background-size:contain;, which will do exactly what you're talking about.
https://developer.mozilla.org/en-US/docs/Web/CSS/background-size
For example:
<style>
.userpic{
width:400px;
height:400px;
background-size:contain;
background-position:center center;
background-repeat:no-repeat;
}
</style>
<div class="userpic" style="background-image:url(myimage.jpg)"></div>
Maybe you will not need this anymore but... to get the original dimensions of the image:
var imgWidth = img.naturalWidth;
var imgHeight = img.naturalHeight;
The answers before me pretty much solved the adjusting image problem with css... except for the code to put the image into the container's background via javascript:
function formatImg(json){
var node = document.getElementById('yourNodeId'); // This is the node where you want to put the image (a div maybe, or the document's body)
var div = document.createElement('div'); // This will be the image's container
div.classList.add('image_container');
div.style.backgroundImage = "url(json.image)";
node.appendChild(div);
}
Just add the styles mentioned before me and problem solved

Dynamic image alignment with Javascript

I've got a Javascript curiosity that I must satisfy. Before I begin I should let you know that I am very aware of the fact that this can be handled with CSS alone, but I want to improve my Javascript skills so humor me :)
For reference to what I'm trying to get at: http://codepen.io/cmegown/pen/CGhpa
Let say we have a potentially infinite number of images, each wrapped inside of a figure set to display: inline-block so that it is the same size as the image inside. Each of these images can be any dimension, and the desired result is that the bottom of every image is perfectly aligned. The kicker here is that this is responsive, so the images may scale up or down. Here's my thinking of how this might be accomplished:
Loop through every image and find the tallest one (outerHeight), then grab that same image's width (outerWidth). Subtract the outerWidth from the outerHeight to get the "master" difference. Loop again through each image to calculate the difference for each specific image and subtract that from the "master" difference, then apply that number to the top margin. Rinse and repeat until each image is aligned to the bottom of the tallest image.
Right? I think the logic is sound, I just lack the skills to put this together properly in Javascript. Sorry for the super long post, but any and all help/advice is appreciated!
function alignImages() {
// caching selectors
var imgs = document.getElementsByTagName('img'),
maxHeight = 0;
for (idx in imgs) {
var img = imgs[idx];
if (img.height > maxHeight) {
maxHeight = img.height;
}
}
for (idx in imgs) {
var img = imgs[idx];
img.style.marginTop = (maxHeight - img.height) + "px";
}
}

Get XY coords & Height/Width of div background image, when using background-size:contain

I'm designing a web page that has a photo for a background image of the main page.
The image must cover as much of the available window size as possible, whilst maintaining the correct aspect ratio.
To that end, I have a "container" div with the following CSS:
div.background {
background-image: url('/Content/Images/Home/main-bg.png');
background-repeat:no-repeat;
background-size:contain;
background-position:center;
float:left;
width:100%;
}
which is working perfectly.
However, I now need to position additional dom elements at specific places on the image, which are also scaled to the same as background image.
I initially thought that using JQuery and reading the "background-image-x","background-image-y", "background-image-x", "background-position-x", and "background-position-y" CSS properties might give me the information I need to position the additional elements.
However, these are not returning the needed information (for example, image-x and image-y both return "50%").
Is there some nice and simple(ish) way to achieve what I need... or am I going to have to resort to using Javascript and math to manually set the position and size of the background image (thus giving me the answers I need)?
I hate math. Please don't make me use it :)
You could work this out with some quite simple comparative ratios, of the image width vs image height compared to container width vs container height. To work out whether the image will be scaled horizontally or vertically.
img_ratio = img_width / img_height;
container_ratio = $(elm).width() / $(elm).height();
Following that you can work out the offset quite simply as you can work out by what percentage the image has been scaled. And apply that to the opposite mesasurement, and compare it to the container.
if(container_ratio > img_ratio){
//centered x height 100%
var scale_percent = $(elm).height() / img_height;
var scaled_width = img_width * scale_percent;
var x_offset = ($(elm).width() - scaled_width) / 2;
offset = [x_offset, 0];
}else{
//centered y width 100%
var scale_percent = $(elm).width() / img_width;
var scaled_height = img_height * scale_percent;
var y_offset = ($(elm).height() - scaled_height) / 2;
offset = [0, y_offset];
}
I've wrapped this up in an example fiddle at: http://jsfiddle.net/y2LE4/
I hope to help.
Try with:
$(document).ready(function(){
var something = background.offset();
}
or
$(document).ready(function(){
var something = $('.background').outerWidth(true);
}
Or just the width feature: http://api.jquery.com/width/

CSS Display affects jQuery/Javascript?

I have run into a strange phenomena I believe and I was wonder if anyone has a the answer to why this occurs. I have been doing a lot of manipulation of images for a photography site using a custom jQuery slideshow I created and have run into some problems.
I have a gallery here: http://www.daemondeveloper.com/photography/gallery.php
I have been adding some functions that resize the images in this gallery so that they scale to the size of the preview image size. As you can see, the very last image is panoramic and does not fill up the entire height of the div even though I have javascript telling it to resize.
If you refresh the page, the javascript seems to work all of a sudden and the pictures scales how it should.
Now try clicking on the panoramic picture of the girl and my slideshow will appear displaying the image scaled and centered vertically using jQuery. The function below is what handles clicking on the small image previews in the gallery.
If you look at where the commented changeSize() function is, that is where I USED to have the function and the scaling did not work. Then I moved it after the .show() functions which show my slideshow and now it works. So it appears that the display:none; affected how the javascript fired because when I debugged, the currentImg object was null, as if the .slides selector did not exist when it was set to display:none;. Is this really happening or am I just seeing a side effect of something else?
If this is really happening it may have something to do with the cause of the first problem I stated about the panoramic image not scaling on the first load of the gallery.php page.
$('.imgHolder').click(function(){
currentPosition = $('.imgHolder').index(this);
$('#slideShow').width(slideWidth);
// Remove scrollbar in JS
$('#slideContainer').css('overflow', 'hidden');
// Wrap all .slides with #slideInner div
slides.css({
'float' : 'left',
'width' : slideWidth
});
// Set #slideInner width equal to total width of all slides
$('#slideInner').css('width', (slideWidth * numberOfSlides));
// Hide left arrow control on first load
manageControls(currentPosition);
$('#slideInner').css('margin-left' , slideWidth*(-currentPosition));
//changeSize(); used to be here
$('#filter').show();
$('#photoWrap').show();
//Change image scale and center
changeSize();
});
And here is the changeSize() function that does the scaling and centering
function changeSize(){
currentSlide = $('.slide').get(currentPosition);
currentImg = $(currentSlide).children('img:first')[0];
imgRatio = $(currentImg).height() / $(currentImg).width();
if(imgRatio < slideRatio)
{
$(currentImg).addClass('landscape');
//Vertically align
var thisHeight = $(currentImg).height();
$(currentImg).css('margin-top', ($('#slideShow').height()/2)-(thisHeight/2));
}else{
$(currentImg).addClass('portrait');
}
}
$('#gallery ul li').each(function() {
var img = $(this).children('div').children('img').first();
var ratio = img.height() / img.width();
var goal = img.parent('div').height() / img.parent('div').width();
if (ratio < goal) {
img.addClass('portrait');
img.css('margin-left', -(img.width() / 2) + ($(this).children('div').width() / 2));
} else {
img.css('width', '100%');
}
});
Here I removed the unnecessary $() instances from your code, as you have already selected the element that you wish to call your methods on when you set the img variable. I doubt that this redundancy is the ultimate issue, but it is a good place to start.
Update your code to this and let's debug from there.
EDIT:
I think I found your error (well, I found one at least):
function configGallery()
{
var currentPosition;
var slides = $('.slide')
var currentSlide;
var currentImg;
var slideWidth = 720;
var numberOfSlides = slides.length;
...
}
Do you see what's wrong here? You forgot a semi-colon after var slides = $('.slide') and that could be your issue. Honestly, I'm surprised any of your scripts ran at all. Missing semi-colons usually crash the whole thing.
UPDATE:
Here are a few more selectors for you to remove the $() from when you get a chance:
function changeSize(){
currentSlide = $('.slide').get(currentPosition);
currentImg = $(currentSlide).children('img').first();
imgRatio = $(currentImg).height() / $(currentImg).width();
if(imgRatio < slideRatio)
{
$(currentImg).addClass('landscape');
//Vertically align
var thisHeight = $(currentImg).height();
$(currentImg).css('margin-top', ($('#slideShow').height()/2)-(thisHeight/2));
}else{
$(currentImg).addClass('portrait');
}
}
UPDATE:
Okay I wrote you a little fiddle to help you re-write your image-sizing function. I'll work on prettying it up and putting it in a plugin for you.
UPDATE:
Here's the same function again in a quick and dirty plugin: http://jsfiddle.net/Wj3RM/3/
I didn't pretty it up though - I figured it would be easier for you to adapt and modify like this.

Javascript doesn't work correctly when css class is used more than once?

Previously, I asked how to center align an image (w/ dynamic width) within a div and someone replied with this code:
http://jsfiddle.net/WDzx4/6/
It's working correctly. However, when I try using the same class for another image, the other image is no longer vertically centered:
http://jsfiddle.net/b4Bbd/
You see, now, the 50x50 black image is slightly higher than it should be. I noticed that only the first image gets aligned correctly. If I add other images with a different width and height (using the same class) after that, they will be misaligned.
Could somebody help me find the problem as I'm not really familiar with javascript.
You need to wrap the JavaScript to do everything for all matching elements, instead of calculating the height for one and applying to all:
$('div.container_img img').each(function() {
var $img = $(this);
var h = $img.height();
$img.css('margin-top', +h / -2 + "px");
});
Try this: http://jsfiddle.net/timothyclifford/b4Bbd/7/

Categories