Reputation: 6154
Good morning.
First, thanks in advance! I've been a stack overflow spectator for quite a while, and you guys are great.
I am looking to create a photo layout for my webpage www.eden-koru.com, where photos are presented in rows. Due to cropping, and different cameras, each photo may have different aspect ratios and therefor there are many uneven gaps when just placed in a row.
A perfect example of what I want to do is www.flickr.com/childe-roland. Those are my photos, all laid out perfectly despite aspect ratio.
On a different, but similar question I found an 80% solution with this JSFiddle http://jsfiddle.net/martinschaer/aJtdb/:
var container_width = $('#container2').width();
var container_width_temp = 0.0; // must be float!
var container_height = 100.0; // random initial container heigth for calculations
$('#container2 img').each(function(){
var newwidth = (this.width / this.height) * container_height;
this.width = newwidth;
$(this).data('width', newwidth);
container_width_temp += newwidth;
});
$('#container2 img').each(function(){
this.width = $(this).data('width') * (container_width / container_width_temp);
});
Now, that only works for one row. I have no experience with JQuery, but I was able to see the math and create a "row_counter" variable that counted the number of image wrapper divs... That got me to 90%. I just multiplied the final width by that row count, then subtracted a few pixels to make up for margins.
it looks like this:
$('.imageWrapper').each(function(){
rows +=1;
});
My div layout looks like this:
<div class="mainWrapper">
<div class="imageWrapper">
<img width="326" src="images/_DSC4434.jpg"></img>
<img width="276" src="images/_DSC4537.jpg"></img>
<img width="254" src="images/_DSC4483.jpg"></img>
</div>
<div class="imageWrapper">
<img width="276" src="images/_DSC0253.jpg"></img>
<img width="306" src="images/The_Alaska_RangeIR.jpg"></img>
<img width="275" src="images/DSC_9111.jpg"></img>
</div>
<div class="imageWrapper">
<img width="276" src="images/_DSC4689.jpg"></img>
<img width="276" src="images/_DSC4718.jpg"></img>
<img width="276" src="images/_DSC4738.jpg"></img>
</div>
</div>
and my CSS like this:
.mainWrapper {
background-color: black;
margin: 0 auto 50px auto;
width: 70%;
height: auto;
border: 2px solid white;
border-radius: 10px;
clear: both;
padding: 7px 7px 7px 7px;
text-align: center;
overflow: hidden;
}
.mainWrapper .imageWrapper {
overflow: hidden;
width: 100%x;
margin: 0px auto 0px auto;
}
.mainWrapper .imageWrapper img {
display: inline-block;
border: 1px solid #fff;
}
Now, it looks better than it did, but there is still a lot of unevenness that I can't account for with styling. Additionally I can no longer use width: 100%
to make my images shrink as the viewport changes.
I hope that I have given enough detail. Please keep in mind that I know nothing about JQuery and haven't touched JavaScript in 5 years. I was an IT major who joined the navy after graduation and never coded again until last week.
Cheers! Wes
Upvotes: 0
Views: 739
Reputation: 1560
This is something quite complex. I managed to make a jQuery plugin that almost achieves what you want, I'm having some issues with making it dynamic when a user resizes their browser window, but ignoring this, it should do what you're asking for.
jQuery Plugin
(function ( $ ) {
$.fn.gallery = function( options ) {
var settings = $.extend({
imgs: [],
row_height: 300,
margin: 10
}, options);
var container = $(this);
//create a div for each image
for(var i=0;i<settings.imgs.length;i++){
$(this).append("<div class='imgwrapper'></div>");
}
//setup the css for the imgwrappers
$("head").append("<style type='text/css'>.imgwrapper{ float: left; margin-left: "+settings.margin+"px; margin-top: "+settings.margin+"px; height: 261px; background-repeat: no-repeat; background-position: center; background-size: cover;}</style>")
//define some global vars
var imgs_aspect = [];
var imgs_rows = [0];
var tot = 0;
var loaded = 0;
function setup(){
var imgs = settings.imgs;
var row_width = 0;
$(".imgwrapper").each(function(index){
var imgwrapper = $(this);
var img = new Image();
img.src = imgs[index];
img.onload = function(){
//determine the aspect ratio of the image
var img_aspect = img.height/img.width;
imgs_aspect.push(img_aspect);
//work out a rough width for the image
var w = settings.row_height*img_aspect;
row_width += w;
//check if there is still space on this row for another image
if(row_width >= container.width()){
imgs_rows.push(1);
row_width = 0;
}
else{
imgs_rows[imgs_rows.length-1]++;
}
//set some of the css vars
imgwrapper.css("width",w+"px");
imgwrapper.css("height",settings.row_height+"px");
imgwrapper.css("background-image","url("+imgs[index]+")");
loaded++;
checkIfLoaded();
}
});
}
function checkIfLoaded(){
//make sure all images are loaded
if(loaded == $(".imgwrapper").length){
setHeight();
}
}
function setHeight(){
for(var r=0;r<imgs_rows.length;r++){
if(r==0){
var y = 0;
}
else{
var y = 0;
for(var j=0;j<r;j++){
y += imgs_rows[j]
}
}
if(imgs_rows[r] == 0){
}
else{
tot = 0;
for(var i=y;i<(y+imgs_rows[r]);i++){
tot += imgs_aspect[i];
}
//work out optimum height of image to fit perfectly on the row
var h = ((container.width()-(settings.margin*(imgs_rows[r]+1)))/tot);
$(".imgwrapper").each(function(index){
if(index >= y && index < (y+imgs_rows[r])){
//work out width using height
var w = h*imgs_aspect[index];
$(this).css("width",w+"px");
}
});
}
}
}
setup();
};
}( jQuery ));
How To Use
var images = ["http://lorempixel.com/300/300",
"http://lorempixel.com/250/250",
"http://lorempixel.com/200/200",
"http://lorempixel.com/210/220",
"http://lorempixel.com/210/230",
"http://lorempixel.com/260/230",
"http://lorempixel.com/410/830",
"http://lorempixel.com/300/200",
"http://lorempixel.com/250/250",
"http://lorempixel.com/200/200",
"http://lorempixel.com/210/220",
"http://lorempixel.com/210/230",
"http://lorempixel.com/260/230",
"http://lorempixel.com/410/830"];
$(".container").gallery({imgs:images, margin: 0, row_height: 300});
images is an array which should contain the images url that you wish to use. The container can have any width desired (define in the css). The margin value allows you to have a similar white border around the images. Since I saw in your code that you had a row height, this is also implemented, by just changing the row_height value.
Demo: http://codepen.io/motorlatitude/pen/iHgCx
This is far from perfect, but it might give you an idea of what you need to do.
Hope it helps!
Upvotes: 1