Column height via Javascript - javascript

I am using
columns: 15em;
to automagically format some images on a page. I would like to put filler images in the empty bottoms of the columns, shorter then the longest column. Can I find out what height these images would need to be?
Also sometimes the columns don't format the images optimally. Am I missing something here?
You can play around with my code here:
http://jsfiddle.net/ygc6r0as/

This should give you a start. It passes through the images and determines which column the image is currently placed in using simple arithmetic, as well as the total height of each column.
var images = document.getElementsByTagName('img'),
cols = [],
colHeights = [],
baseOffset = images[0].offsetLeft;
for (var i=0; i < images.length; i++) {
var img = images[i];
var col = Math.round( (img.offsetLeft - baseOffset) / img.width );
if (!cols[col]) {
cols[col] = [];
colHeights[col] = 0;
}
cols[col].push( img );
var bottom = img.offsetTop + img.offsetHeight;
if (bottom > colHeights[col])
colHeights[col] = bottom;
}
console.log(cols, colHeights);

Related

Javascript scale images to fit container and to equal height

I'm trying to build a gallery. The idea is to fit images into fixed width container, but images must be of the same height and preserve original aspect ratio, so they just need to scale somehow.I came up with a solution of my own, but it, sometimes,gives clunky results for images total width that are too small or too large to fit container.Also resulting widths are, for some reason, floating point values. Could someone help me to figure out more optimal way to do it?
My clunky solution: https://codepen.io/fuzzy-toozy/pen/wvEaorW
function recalcGallery() {
if (uploadedImages.length > 0) {
let min = galleryHeight;
for (let i = 0; i < uploadedImages.length; i++ ) {
let currentUploadedImages = uploadedImages[i];
// find element with smallest height
currentUploadedImages.forEach((val) => { if (min > val.height) { min = val.height; }});
let imgCont = [];
let totalWidth = 0;
// set all elements to same height
for (let j = 0; j < currentUploadedImages.length; j++) {
let imgContainer = document.querySelector(`[image-index${i}="${j + 1}"]`);
imgContainer.style.height = `${min}px`;
imgCont.push(imgContainer);
totalWidth += imgContainer.clientWidth;
}
if (totalWidth > galleryWidth) {
// calculate value to decrease height by based on percent of overflow
let decPx = Math.ceil(min - min * (galleryWidth) / totalWidth);
imgCont.forEach((val, i) => {
val.style.height = `${val.clientHeight - decPx}px`;
});
}
}
}
}
Your solution involves finding the element with the smallest height, setting all elements to the same height, and then checking if the total width of the images is greater than the gallery width. If the total width is greater, you calculate a value to decrease the height by based on the percentage of overflow and then decrease the height of each image container.
One potential issue with your solution is that you are relying on the clientWidth property of the image containers to calculate the total width of the images. This property can include padding and borders, which may not accurately reflect the total width of the images. A more accurate approach would be to use the naturalWidth property of the image elements, which reflects the actual width of the image.
Here is an example of how you could modify your code to use the naturalWidth property:
function recalcGallery() {
if (uploadedImages.length > 0) {
let min = galleryHeight;
for (let i = 0; i < uploadedImages.length; i++ ) {
let currentUploadedImages = uploadedImages[i];
// find element with smallest height
currentUploadedImages.forEach((val) => { if (min > val.height) { min = val.height; }});
let imgCont = [];
let totalWidth = 0;
// set all elements to same height
for (let j = 0; j < currentUploadedImages.length; j++) {
let imgElement = document.querySelector(`[image-index${i}="${j + 1}"] img`);
let aspectRatio = imgElement.naturalWidth / imgElement.naturalHeight;
let imgContainer = document.querySelector(`[image-index${i}="${j + 1}"]`);
imgContainer.style.height = `${min}px`;
imgContainer.style.width = `${min * aspectRatio}px`;
imgCont.push(imgContainer);
totalWidth += imgContainer.clientWidth;
}
if (totalWidth > galleryWidth) {
// calculate value to decrease height by based on percent of overflow
let decPx = Math.ceil(min - min * (galleryWidth) / totalWidth);
imgCont.forEach((val, i) => {
val.style.height = `${val.clientHeight - decPx}px`;
val.style.width = `${(val.clientHeight - decPx) * (val.querySelector('img').naturalWidth / val.querySelector('img').naturalHeight)}px`;
});
}
}
}
}
In this modified code, we calculate the aspect ratio of each image using the naturalWidth and naturalHeight properties, and set the width of each image container accordingly. We then use the clientWidth property of the image containers to calculate the total width of the images, but we use the naturalWidth property of the image elements to calculate the width of each image container when we need to adjust the height of the images.
Note that this code assumes that the images are contained within an tag within each image container. If you are using a different approach to display the images, you may need to modify the code accordingly.

Resize a group of variably sized images both horizontally & vertically - need help optimising

WARNING CODE CRASHES IN EVERYTHING EXCEPT GOOGLE CHROME
I'm trying to create a feature on our website that takes 8 random images and places them in two rows and dynamically resizes the images to take up the full width of the page.
I've created a jsbin for this to try and demonstrate the issue.
https://jsbin.com/yijemazovi/edit?html,css,js,output
The comments in the code should give you an good idea of what I'm doing. What seems to be happening for everything but Google Chrome is that the while condition is never satisfied so it goes on infinitely and crashes the browser.
Perhaps it is something as simple as I am doing the do/while loop incorrectly or I should just be using a while loop???
Any help is appreciated!
/*****
* Get the overall width of the container that we want to match
**********/
var ContainerWidth = $('.feature-inim-collage .col.span_1_of_1').width();
/*****
* Increase the height of the images until the total sum of the width
* if the 4 images + the gutters is larger than ContainerWidth - then
* stop
**********/
/*****
* Increment in jumps of 10px until we get within 80% of the width of
* the ContainerWidth and then go to a more precise increment of 1px.
* We can increase the px from 10 to 20 or 30 so there are less loops
* but this can cause issues when we look at mobile and there is less
* overall width in the containers and jumping by 30px will be too much
**********/
var i = 0;
do {
$('.feature-inims-top-row .growable-container').css('height', i);
var RowWidth1 = CalculateTotalWidth(1);
if(RowWidth1 < (ContainerWidth*0.8)){
i = i+10;
}else{
i++;
}
}
while (RowWidth1 < (ContainerWidth - 3));
/*****
* Repeat above for the 2nd row
**********/
var i = 0;
do {
$('.feature-inims-bottom-row .growable-container').css('height', i);
var RowWidth2 = CalculateTotalWidth(2);
if(RowWidth2 < (ContainerWidth*0.8)){
i = i+10;
}else{
i++;
}
}
while (RowWidth2 < (ContainerWidth - 3));
/*********
* Calculate the combined width of the images + the gutters
****/
function CalculateTotalWidth(Row) {
var Image1Width = $('.growable-container-1').width();
var Image2Width = $('.growable-container-2').width();
var Image3Width = $('.growable-container-3').width();
var Image4Width = $('.growable-container-4').width();
var Image5Width = $('.growable-container-5').width();
var Image6Width = $('.growable-container-6').width();
var Image7Width = $('.growable-container-7').width();
var Image8Width = $('.growable-container-8').width();
var GutterSize = 24; // (3 gutters # 8px each)
if(Row == 1){
var RowWidth = GutterSize + Image1Width + Image2Width + Image3Width + Image4Width;
}else{
var RowWidth = GutterSize + Image5Width + Image6Width + Image7Width + Image8Width;
}
return RowWidth
}
It turns out the issue with this was that in the CalculateTotalWidth() function I was checking the width of the container the image was in rather than the image itself. As soon as I changed this it worked perfectly.
var Image1Width = $('.growable-container-1 img').width();
instead of
var Image1Width = $('.growable-container-1').width();

javascript - How to insert an img several times into a div using a loop

Hello I am trying to insert an img several times into a div, each time my img will have different properties. My Html code will have a div with an example id called ID_DIV.
I will have a style section into the html code like this img position absolute.
I will preset the variable NumberOfTimes according to the number of img I need into the div.
But I can't manage to make the loop work. Every time I refresh my browser my img appears in a different position, but it wont appear a "NumberOfTImes" times.
I have edited my code into this. But the loop wont work anyways. Still without knowing what it is.
function generateImg(){
var numberOfTimes=prompt("how many times?");
var div_id1=document.getElementById("div_id1");
do{
var oImg=document.createElement("img"); // Creates an oimg node
oImg.setAttribute('src', 's0me_s0urce'); // sets the source for img file
div_id1.appendChild(oImg); // append the img to #id Div.
document.querySelector('img').style.top = Math.floor(Math.random()*401)+'px';
document.querySelector('img').style.left = Math.floor(Math.random()*401)+'px';
numberOfTimes--;
}while(numberOfTimes>0);
}
Please Help. I can't find where is the mistake in this logic.
you need to declare "i" outside of the loop otherwise it will not decrement and will only ever be "NumberOfTimes - 1" and therefore your loop will loop repeadeteldy with the image in the same location. This is also assuming that "NumberOfTimes" is in in the same scope to be used in the first place. Note that I have moved the location of "i" and added a decrement to it in the loop.
function RandomPositionImgs(){
var i=NumberOfTimes;
do{
var oImg=document.createElement("img"); // Creates an oimg node
oImg.setAttribute('src', 'some_source'); // sets the source for img file
document.getElementById("ID_DIV").appendChild(oImg); // append the img to leftSide Div.
document.querySelector('img').style.top = Math.floor(Math.random()*401)+'px'; // random positioning
document.querySelector('img').style.left = Math.floor(Math.random()*401)+'px'; // random positioning
i--;
}while(i>0);
}
Thank you all for your answers you made me realize what I was doing wrong. This is the correct code I did after your comments, its working perfect.
function generateImgs(){
var numberOfTimes=prompt("how many times?");
for(i=0;i<numberOfFaces;i++){
var oImg=document.createElement("img"); // Creates an oimg node
oImg.setAttribute('src', 'valid source'); // sets the source for img file
document.getElementById("div id").appendChild(oImg); // append the img to Div.
oImg.style.top = Math.floor(Math.random()*401)+'px';
oImg.style.left = Math.floor(Math.random()*401)+'px';
}
}
My answer is obsolete now. Anyway, here is a way to deal with overlapping images:
var img, i, x, y;
var size = 48, w = 5, h = 3;
var grid = new Array(w * h).map(x => false);
var n = 5; // n > grid.length => infinite loop
var src = 'https://i.stack.imgur.com/6gwfY.gif?s=48&g=1';
var ct = document.getElementById('ct');
ct.style.width = size * w + 'px';
ct.style.height = size * h + 'px';
while (n-- > 0) {
i = next(), x = i % w, y = (i - x) / w;
img = document.createElement('img');
img.setAttribute('src', src);
img.style.left = size * x + 'px';
img.style.top = size * y + 'px';
ct.appendChild(img);
}
function next () {
var l = grid.length;
var i = Math.floor(Math.random() * l);
// as long as this position is not free, try the next one
while (grid[i]) i = (i + 1) % l;
return grid[i] = true, i;
}
img{position:absolute}
#ct{background:#eee}
#ct{position:relative}
<div id="ct"></div>

Can't draw a line on the canvas

I am having trouble drawing a line on the HTML canvas with JavaScript. For the record, I don't want to use any pre-written line-drawing methods, I need to do it using pixel manipulation. I tried drawing a line on a 500x500 pixel canvas that I already gave data with this
function drawBackgtoundAndLine()
{
var cnvs = document.getElementById("cnvs");
var cont = cnvs.getContext("2d")
var imdt = cont.getImageData(0,0,500,500)
//Fill canvas with a color
for ( var i = 0 ; i < imdt.data.length ; i = i + 4)
{
imdt.data[i] = 200;
imdt.data[i+1] = 100;
imdt.data[i+2] = 0;
imdt.data[i+3] = 255;
}
//Draw a horizontal line
var index = 0;
for ( var c = 0 ; c < 500 ; c++)
{
index = (4*c)+488000;
imdt.data[index] = 0;
imdt.data[index+1] = 0;
imdt.data[index+2] = 0;
imdt.data[index+3] = 255;
}
cont.putImageData( imdt , 0 , 0 )
}
You can see it in action in this fiddle. My math, by the way, that gave me the second for loop to draw a line is:
I want to color the whole 245th row. So, to pass over the first 244 rows, I multiply 2000(the number of data points in each row) times 244 rows to get 488000. Then I cycle through the loop 500 times to hit each pixel in the row, and add the 488000 to get to the right row. I'd really appreciate an explanation/fix for the 245th row not turning black.
You did not set the canvas size.
Note that the CSS size is only about display, not the number of pixels in the canvas.
You need to set the real canvas size for example with:
cnvs.width = 500;
cnvs.height = 500;
Remember that when you set the height/width the canvas is cleared (even if the value is the same as the current size), also remember that to get pixel-perfect graphics you need to keep the canvas size the same size as the element on the page (i.e. cnvs.offsetWidth and cnvs.offsetHeight).

Drawing squares with createJS creates rectangles

Apart from the title not being entirely correct I'm having a problem drawing squares with createJs. I'm drawing rectangles with equally big sides which in general generates a square, but not for me, I'm getting this:
The code I'm using is as follows (very much simplified):
function getRandomNumber(max)
{
return Math.floor(Math.random() * max);
}
var colors = ["Red", "Green", "Blue"];
function createTileArea()
{
var stage = new createjs.Stage("tileArea");
stage.name = "stage";
var size = 50;
for (row = 0; row < 10; row++) {
for (col = 0; col < 10; col++) {
var id = row + "_" + col;
var color = colors[getRandomNumber(3)];
var tile = new createjs.Shape();
tile.graphics.beginFill(color);
tile.graphics.drawRect(0, 0, size, size);
tile.graphics.endFill();
tile.x = col * size;
tile.y = row * size;
tile.height = size;
tile.width = size;
tile.name = id;
stage.addChild(tile);
}
}
stage.update();
}
createTileArea();
I have a fiddle here: http://jsfiddle.net/QWP3Z/2/
My question is: I have a canvas that has 500px width and height and I'm generating 10 rectangles that are 50px high and wide, so why am I getting 6 horizontal squares and three vertical squares that are all rectangles?
Is this some sort of scaling problem?
do not use the css style to resize the canvas, but rather change its width and height directly, either in html or in code.
Otherwise createJs will set the width and height, which seems to default to 300X150, and the css will act as a zoom to put it back to -in your example- 500X500.

Categories