jQuery gallery code only works after refresh - javascript

I'm having trouble implementing a gallery/portfolio, just like the ones pictured in the portfolio templates of Wix. In my HTML I have set up three div columns, in which I add images, and my thought process was to create a script which adds each image (from a list of images) to the column which currently has the smallest height.
I've already used CSS to ensure that the images are full width in the columns and have margins between each other.
The problem I've been having is that the script seems to work but only after I refresh the page--otherwise the heights returned are nonsense values like 0px and 20px, where they should be 356.2px, 306.4px, etc, or arbitrary image height values. Since 0px is being returned, the images go into the same column.
Some visuals to better describe what I mean:
What I get after the first refresh
vs What I get before the first refresh
I've looked at some questions with similar problems, and many explain that the image might not have been loaded yet. I've tried $(window).on('load', function... , $(img).onload, $('#gallery-holder-1').ready, ... and a bunch of other random stuff but nothing seems to work.
My code looks like the following:
/* List of images */
const images = ["img1.png", "img2.png", "img3.png", "img4.png", "img5.png"];
$(document).ready(function() {
var holder = 0; // to determine which holder to add to
var height1 = 0; // heights of each gallery-holder
var height2 = 0;
var height3 = 0;
// add all the images to the holders
for (const image of images) {
// get height of each holder
height1 = $('#gallery-holder-1').css("height");
height2 = $('#gallery-holder-2').css("height");
height3 = $('#gallery-holder-3').css("height");
// find smallest height
if(height3 < height2) {
if (height3 < height1) { holder = 3; }
else { holder = 1; }
}
else {
if (height2 < height1) { holder = 2; }
else { holder = 1; }
}
// create image and append
var img = document.createElement("img");
img.src = image;
$(`#gallery-holder-${holder}`).append(img);
}
});
Does anyone know what might be the problem or, alternatively, a better way to implement a portfolio like the kind on Wix?

Related

How can I animate a recently created DOM element in the same function?

I'm working to create an image gallery where the images will be composed by progressively fading in layers one on top of the other to form the final image.
I have many such layers so instead of loading them into many different <img> elements all at once (which would slow load time) I want to start off with a single <img id="base"> and then progressively add image elements with the jQuery .after() method, assign them the relevant sources and fade them in with a delay.
The problem is that I can't attach animations to the newly created elements because (I'm assuming) they don't exist yet within the same function. Here is my code:
HTML
<div id="gallery">
<img id="base" src="image-1.jpg">
</div>
CSS
#base {
opacity: 0;
}
.layers {
position: absolute;
top: 0;
left: 0;
opacity: 0;
}
JavaScript
$(document).ready(function () {
$("#base").animate({opacity: 1}, 300); //fade in base
for (var i = 1; i <= numberOfLayers; i++, gap += 300) {
// create a new element
$("#base").after("<img class='layers' src='" + imgName + ".png'>");
// fade that new element in
$("#gallery").children().eq(i).delay(gap).animate({opacity: '1'}, 300);
}
}
Please note that I've altered my actual code to illustrate this better. I'm fairly new at JavaScript but I'm a quick learner so I'd appreciate if you could tell me what I'm doing wrong and what solution I should pursue.
EDIT: I've included my code inside your JSFiddle (all you need to do is add the library-X.jpg images) : http://jsfiddle.net/pgoevx03/
I've tried to replicate the intent of the code in a cleaner/more flexible way. Please let me know if I can do anything else to help.
I'm not saying this is the best way to do it, but it should be easy enough to understand and use.
The code is untested, but should work just fine. The comments should help you out if there's any compilation error.
Note that I removed the first image in the gallery (with ID "base") from the HTML file. It will be appended the same way as the rest.
// Array storing all the images to append to the gallery
var galleryImages = [
"image-1.jpg",
"image-2.jpg",
"image-3.jpg",
"image-4.jpg",
"image-5.jpg",
"image-6.jpg",
"image-7.jpg",
"image-8.jpg",
"image-9.jpg",
"image-10.jpg"
];
// Index of the image about to be appended
var imgIndex = -1;
var baseID = "base";
$(document).ready(function() {
// Start appending images
appendAllImages();
});
// Append the images, one at a time, at the end of the gallery
function appendAllImages() {
//Move to the next image
imgIndex++;
//We've reached the last image: stop appending
if (imgIndex >= galleryImages.length) return;
//Create image object
var img = $("<img>", {
src: galleryImages[imgIndex],
});
if (imgIndex === 0) { // It's the base!
//Give the base ID to the first image
img.attr("id", baseID);
//Append the image object
$("#gallery").append(img);
} else { // It's a layer!
//Give the base ID to the first image
img.attr("class", "layers");
//Append the image object
$("#" + baseID).after(img);
}
//Fade in the image appended; append the next image once it's done fading in
img.animate({
opacity: 1,
}, 300, appendAllImages);
}

Is Javascript an Effective Method of Creating Fluid Layouts?

I'd like opinions on whether or not Javascript is a still a viable and relatively effective method of producing fluid website layouts. I know that it is possible to create fluid layouts with Javascript, but relative to other methods (e.g. CSS3/HTML5) how does it stand up in terms of performance and complexity? The function below represents what I mean. In the function, javascript is being used to find the dimensions of various elements and place other elements accordingly. To see it working, follow this link.
function onPageResize() {
//center the header
var headerWidth = document.getElementById('header').offsetWidth; //find the width of the div 'header'
var insideHeaderWidth = (document.getElementsByClassName('header')[0].offsetWidth + document.getElementsByClassName('header')[1].offsetWidth + document.getElementById('logoHeader').offsetWidth); //find the combined width of all elements located within the parent element 'header'
document.getElementsByClassName('header')[0].style.marginLeft = ((headerWidth - insideHeaderWidth) / 2) + "px"; //set the margin-left of the first element inside of the 'header' div
/////////////////////////////////////////////////////////////////
//justify alignment of textboxes
var subtitleWidth = document.getElementsByClassName('subtitle'); //assign the properties of all elements in the class 'subtitle' to a new array 'subtitleWidth'
var inputForm = document.getElementsByClassName('inputForm'); //assign the properties of all elements in the class 'inputForm' to a new array 'inputForm'
for (i = 0; i < inputForm.length; i++) { //for every element in the array 'inputForm' set the margin-left to dynamically place the input forms relative to eachother
inputForm[i].style.marginLeft = (subtitleWidth[4].offsetWidth - subtitleWidth[i].offsetWidth) + "px";
}
/////////////////////////////////////////////////////////////////
//place footer on absolute bottom of page
if (window.innerHeight >= 910) { //when the page is larger than '910px' execute the following
var totalHeight = 0; //initialize a new variable 'totalHeight' which will eventually be used to calulate the total height of all elements in the window
var bodyBlockHeight = document.getElementsByClassName('bodyBlock'); //assign the properties of all elements in the class 'bodyBlock' to a new array 'bodyBlockHeight'
for (i = 0; i < bodyBlockHeight.length; i++) { //for every instance of bodyBlockHeight in the array, add the height of that element into the 'totalHeight'
totalHeight += bodyBlockHeight[i].offsetHeight;
}
totalHeight += document.getElementById('header').offsetHeight; //finally, to add the height of the only element that has yet to be quantified, include the height of the element 'header' into the 'totalHeight'
/*Set the margin-top of the element 'footer' to the result of subtracting the combined heights of all elements in the window from the height of the window.
This will cause the footer to always be at the absolute bottom of the page, despite whether or not content actually exists there. */
document.getElementById('footer').style.marginTop = (window.innerHeight - totalHeight) - document.getElementById('footer').offsetHeight + "px";
} else {
//if the page height is larger than 910px (approx the height of all elements combined), then simply place the footer 20px below the last element in the body
document.getElementById('footer').style.marginTop = "20px"
}
/////////////////////////////////////////////////////////////////
}
Again, the result of the above function can be viewed at this link.
Thank you to any and all who offer their opinions!
You should be using CSS rather than JavaScript because that is what CSS is designed to do. If you want a fluid layout play around with using percentage widths, floats and media queries.

Change image in html keeping size javascript

I am experimenting an issue while changing an image in a img tag of html.
I did an example in fiddle which works as my webpage with images I found on internet so they are not equal:
http://jsfiddle.net/kZp7V/
This is the script code:
var counterImage = 0;
var ccI = new Array('http://tiendas.fnac.es/la-canada/files/2010/12/Peque%C3%B1a-orquesta-mediterr%C3%A1neo-300x286.jpg',
'http://muack.es/wp-content/uploads/2013/04/smalldata1.jpg',
'https://pbs.twimg.com/profile_images/604644048/sign051.gif'
);
window.image = function(element){
if(counterImage < 3){
document.getElementById("EJ_test").setAttribute('src', ccI[counterImage]);
counterImage++;
}
else{
document.getElementById("EJ_test").setAttribute('src', ccI[0]);
counterImage = 1;
}
}
I want that all images to have the same aspect of the first one, I mean, same hight and width. Is is possible?
I was asked to do it with photoswipe but I find it a little bit difficult so I want to do this now and then, read carefully everything about photoswipe for next week.
EDIT: I changed the class="cropTest" to the div instead of the image and now all images are "resized". I use "" because they are smaller. The img tag adjust to the image but I don't want this happends. I want to have a diferent image but keeping the size. I don't mind the image looks blur or pixelated.
you can use getComputedStyle to get the current size of the image, and use that information once, for example by checking if the width style has already been set by you. Example:
window.image = function(element){
if (!document.getElementById("EJ_test").style.width) {
var currentStyle = window.getComputedStyle(document.getElementById("EJ_test"));
document.getElementById("EJ_test").style.width =
currentStyle.width;
document.getElementById("EJ_test").style.height =
currentStyle.height;
}
if(counterImage < 3){
document.getElementById("EJ_test").setAttribute('src', ccI[counterImage]);
counterImage++;
}
else{
document.getElementById("EJ_test").setAttribute('src', ccI[0]);
counterImage = 1;
}
}

Problems calculating the actual height of web page elements with Javascript and JQuery?

I am modifying some code I found for paginating HTML content into a div. The code is from the jQuery rain site found on this page:
http://www.jqueryrain.com/?HtS47Rzc
The intent of this code is to take a large chunk of HTML, scan the top level child elements, and create a page object for each group of child elements that fit within a desired height (E.g. 400px). Once all the pages are built, each page is wrapped in a new div. The problem I'm having is that the calculated pages aren't close to the desired height once rendered to the page. So instead of each page having a nice block of text that neatly bumps into but does not exceed the bottom of the containing div, some pages have text falling far short of the desired page bottom and some exceed the page bottom. Actually they no longer exceed the page bottom since I added code that scans the pages array after each page has been wrapped with a div and sets the container div to the maximum div height found.
One thought I had is that the wrapping of the div was causing the variance so I explicitly added CSS rules to set the margins and padding to 0px. That had no effect. Can anyone tell me how to adjust the code so that the page height calculations work properly?
UPDATE: I'm showing the CSS for the div that holds a page and the DIV that contains it.
.example{
background:#FFF;
width:410px;
border:1px #000 solid;
margin:20px auto;
padding:15px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px
}
The page divs all have the class of "page":
#content .page {
position:absolute;
margin: 0px 0px 0px 0px;
padding: 0px 0px 0px 0px;
top:0px;
}
Here is my Javascript modified code. Note, the object being processed by the function is the main div that shows the paginated content:
(function ($) {
$.fn.extend({
MyPagination: function (options) {
var defaults = {
height: 400,
fadeSpeed: 400
};
var options = $.extend(defaults, options);
//Creating a reference to the object
var objContent = $(this);
// The array of pages we will build.
var fullPages = new Array();
// The array of elements for each page, used during pagination calculations.
var pageElements = new Array();
// The height for each page, reset after each page is built.
var height = 0;
var lastPage = 1;
var paginatePages;
// initialization function
init = function ()
{
// Build the array of pages by creating a new page when the sum of the child elements
// height values for each page exceeds the desired page height.
//
// NOTE: This is only an approximation. Haven't figured out why yet. When the
// operation is done there is large variance in the DIV height away from our desired
// height, many of them larger than our desired height.
objContent.children().each(function (i)
{
// Some browsers don't support clientHeight. In those cases, use offsetHeight.
var childHeight = this.clientHeight == 0 ? this.offsetHeight : this.clientHeight;
// If the height of all the children in the page elements array exceeds the desired
// page height, start a new page.
if (height + childHeight > options.height)
{
// Start a new page.
fullPages.push(pageElements);
// Reset the page elements array by initializing it to a new array.
pageElements = new Array();
// Reset the page height accumulatore. for the next page.
height = 0;
}
// Accumulate the child element's height into the height aggregator variable.
height += childHeight;
// Add the child element to the child elements array for the page currently being built.
pageElements.push(this);
});
if (height > 0) {
fullPages.push(pageElements);
}
// wrapping each full page
// $(fullPages).wrap("<div class='page'></div>");
// Wrapping each full page with a DIV. Give the DIV an ID that contains the page number.
$(fullPages).wrap(
function (ndx) {
return "<div class='page' name='pages' id='page_" + (ndx + 1) + "'></div>"
});
// Find the DIV with the maximum height.
var maxDivHeight = 0;
for (var ndx = 1; ndx <= fullPages.length; ndx++) {
var pageN = document.getElementById('page_' + ndx);
// Some browsers don't support clientHeight. In those cases, use offsetHeight.
var divHeight = pageN.clientHeight == 0 ? pageN.offsetHeight : pageN.clientHeight;
if (divHeight > maxDivHeight)
maxDivHeight = divHeight;
}
// Set the height of the content DIV to the maximum height we found plus a little padding.
objContent.height(maxDivHeight);
// hiding all wrapped pages
objContent.children().hide();
// making collection of pages for pagination
paginatePages = objContent.children();
// show first page
showPage(lastPage);
// draw controls
showPagination($(paginatePages).length);
};
// update counter function
updateCounter = function (i) {
$('#page_number').html(i);
};
// show page function
showPage = function (page) {
i = page - 1;
if (paginatePages[i]) {
// hiding old page, display new one
$(paginatePages[lastPage]).fadeOut(options.fadeSpeed);
lastPage = i;
$(paginatePages[lastPage]).fadeIn(options.fadeSpeed);
// and updating counter
updateCounter(page);
}
};
// perform initialization
init();
}
});
})(jQuery);
You can maybe use getBouningClientRect on your element. This will give you the position and size of that element:
var clientRect = element.getBoundingClientRect();
And now you can get the size and position:
var leftPos = clientRect.left;
var topPos = clientRect.top;
var width = clientRect.width;
var height = clientRect.height;
Hope this helps!
Here is a link to more information: https://developer.mozilla.org/en-US/docs/Web/API/element.getBoundingClientRect

Script that makes all floating divs the same height

Hey there, I have 20 divs floated left with different height. I use this script to resize them. It worked perfect when my website was designed using pixels.
When i have changed my website to % design (percentage design), the script stopped working that reliable, sometimes it does not resize.
can you take a look, see if there are any adjustments needed for liquid layouts?
maybe it's the way i call the script?
Ty very much
Here it is:
var currentTallest = 0;
var currentRowStart = 0;
var rowDivs = new Array();
function setConformingHeight(el, newHeight) {
// set the height to something new, but remember the original height in case things change
el.data("originalHeight", (el.data("originalHeight") == undefined) ? (el.height()) : (el.data("originalHeight")));
el.height(newHeight);
}
function getOriginalHeight(el) {
// if the height has changed, send the originalHeight
return (el.data("originalHeight") == undefined) ? (el.height()) : (el.data("originalHeight"));
}
function columnConform() {
// find the tallest DIV in the row, and set the heights of all of the DIVs to match it.
$('div.column').each(function(index) {
if(currentRowStart != $(this).position().top) {
// we just came to a new row. Set all the heights on the completed row
for(currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) setConformingHeight(rowDivs[currentDiv], currentTallest);
// set the variables for the new row
rowDivs.length = 0; // empty the array
currentRowStart = $(this).position().top;
currentTallest = getOriginalHeight($(this));
rowDivs.push($(this));
} else {
// another div on the current row. Add it to the list and check if it's taller
rowDivs.push($(this));
currentTallest = (currentTallest < getOriginalHeight($(this))) ? (getOriginalHeight($(this))) : (currentTallest);
}
// do the last row
for(currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) setConformingHeight(rowDivs[currentDiv], currentTallest);
});
}
$(window).resize(function() {
columnConform();
});
$(document).ready(function() {
columnConform();
});
Well if you change it to fluid layout (% design) then you are going to have to add a window resize listener, basically when the resize event is done or while it's running you need to recall the script so it can recalculate with new dimensions, you did not need to doo that with pixels because it was a fixed size and once assigned will not change no matter how many times you resize the actual screen.
If you use styles like this:
<style>
.parent{
background:#F00;height:300px
}
.parent div{
float:left;height:100%;width:33.33%;
}
</style>
<div class="parent">
<div style="background:#FED"></div>
<div style="background:#EDF"></div>
<div style="background:#DFE"></div>
</div>
You just have to set the height of the parent div, and the width of the children div

Categories

Resources