I am trying to create an image carousel and I want the images to loop through the array. The code is clearly working because the "no click" alert shows but I don't understand what I am doing wrong.
Here is JS. I know the problem is most likely the if statement. I'm a beginner in JS and haven't quite understood how to code that bit properly. In some sort of pseudo code, it would ideally be "if btn is clicked, then show the next image".
let images = ["img1.jpg", "img2.jpg", "img3.jpg"];
let img = images.length;
let x = 0;
function whenClicked(e) {
for (let i = 0; i < img; i++) {
if (x == 0) {
document.getElementById("img1").style.backgroundImage = ++img;
} else alert("no click!")
}
}
const btnLeft = document.getElementById("btn-left");
const btnRight = document.getElementById("btn-right");
btnLeft.addEventListener("click", whenClicked);
btnRight.addEventListener("click", whenClicked);
And here HTML.
<div class="slide-container">
<div class="slide" id="img1">
<i class="fas fa-arrow-circle-left fa-3x" id="btn-left" ></i>
<i class="fas fa-arrow-circle-right fa-3x" id="btn-right" ></i>
</div>
</div>
CSS.
.slide-container {
}
.slide {
height: 789px;
width: 100%;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.slide:nth-child(1) {
background-image: url(../img/img1.jpg);
}
.slide:nth-child(2) {
background-image: url(../img/img2.jpg);
}
.slide:nth-child(3) {
background-image: url(../img/img3.jpg);
}
#btn-left {
position: absolute;
top: 400px;
}
#btn-right {
position: absolute;
left: 1380px;
top: 400px;
}
Suggestions on what to do to improve would be deeply appreciated!
You might be overcomplicating your approach. Try to keep track of which image is currently being shown and what image should be next. You are almost doing this, with I assume is your intent, with the x variable. This is a great way to select an image from the array by simply doing images[x], which translates to images[0] at the start.
So if you want to develop a system which changes the background image of the slide, then your buttons would have to change the value of the x variable. Let's give that variable a more clear name, like currentIndex which represents the current index in the images array. Or to be clear, the current image we are seeing.
When your right button is clicked, you'll want the next image. The next images in the images array is images[1]. All you have to do is update the currentImage value with +1 or ++ and select the next image with images[currentIndex] to get the next one.
Same goes for the left button which should remove 1 from the currentImage with either -1 or -- to go back one index in the images array. Then select the image the same way with images[currentIndex].
Now for both these buttons you'll need to check if you go past the start or the end of the images array. currentIndex cannot be lower than 0 and with 3 images in the array, the currentIndex value should not be higher than 2, since we are counting with [0, 1, 2] in the images array.
Below I've made an implementation of this system. I hope this is what you intended to make. If I haven't been clear or you have question, then don't hesitate to ask.
let images = ["img1.jpg", "img2.jpg", "img3.jpg"];
let amountOfImages = images.length;
let currentIndex = 0;
const slide = document.getElementById("img1");
const btnLeft = document.getElementById("btn-left");
const btnRight = document.getElementById("btn-right");
function prevImage() {
if (currentIndex > 0) { // Can't go lower than 0.
currentIndex--;
updateImage();
}
}
function nextImage() {
if (currentIndex < amountOfImages - 1) { // Can't go higher than the amount of images present.
currentIndex++;
updateImage();
}
}
function updateImage() {
slide.style.backgroundImage = images[currentIndex];
}
btnLeft.addEventListener("click", prevImage);
btnRight.addEventListener("click", nextImage);
let currentImage = 0;
let images = ["img1.jpg", "img2.jpg", "img3.jpg"];
function whenClicked(e) {
if(e.target.id == 'btn-left') {
currentImage--;
} else {
currentImage++;
}
if(currentImage > images.length-1) {
currentImage = 0;
}
if(currentImage < 0) {
currentImage = images.length-1;
}
document.getElementById("img1").style.backgroundImage = url('img/'+images[currentImage]);
}
Related
I'm trying make this image move 16px every click, but it's not moving. I've tried this:
But that only moves it once. So I tried something different that I found online.
Here is my code:
Html:
document.getElementById('player').style.left += "-16px";
function left() {
var left = parseInt(player.style.left);
player.style.left = (left +16) + "px";
}
<img id="player" src="characters/prisoner-down.png"></img>
<img id="leftbtn" src="icons/left.png" onclick="left();"></img>
Edit: if it's useful to know, there are gonna be three more buttons for the other directions and the image I want to move is in another DIV from the image that moves it. On my editor it says that the symbol ` is invalid, so I'd like to avoid it.
You can create a function that get the direction of the translation and the number of pixels to increment, then return a function that set style.transform of the element clicked, using a closure you can update the amount of pixels to translate, try this:
function transform(side, n) {
let translatePixels = 0;
if (side == 'right') {
return function(e) {
translatePixels += n;
e.target.style.transform = `translate(${translatePixels}px)`;
}
}
if (side == 'left') {
return function(e) {
translatePixels -= n;
e.target.style.transform = `translate(${translatePixels}px)`;
}
}
}
const translateRight = transform('right', 16);
const translateLeft = transform('left', 16);
<img onclick="translateRight(event);" src="https://images.rappi.com.ar/products/2311265-1622567743906.png?d=200x200&e=webp"></img>
<img onclick="translateLeft(event);" src="https://cdn.domestika.org/c_fill,dpr_auto,f_auto,h_256,pg_1,t_base_params,w_256/v1499705651/avatars/000/536/178/536178-original.jpg?1499705651" style="right: 0; position:absolute"></img>
Give position property to the img which you want to move.
Like position: relative;, position: absolute; etc.
By positioning them you can use top, left, right and top properties.
don't use position: static; on that img cause above property has no effect on static element.
document.getElementById('player').style.left = "-16px";
function left() {
let left = parseInt(player.style.left);
player.style.left = `${parseInt(left+16)}px`;
}
img{
/*important for using left, right, top and bottom properties*/
position: relative;
}
<img id="player" src="https://i.postimg.cc/44pXvSwD/pngwing-com.png"></img>
<img id="leftbtn" src="https://i.postimg.cc/FRkMDYvr/Pngtree-right-arrow-flat-multi-color-3777297.png" onclick="left();"></img>
I would like to build an image gallery like this where pictures keep looping automatically but at the same time, it's possible to interact through the gallery using the mouse wheel as well. I would also achieve an effect like that where images, instead of scrolling out of the screen shrink on the side.
So I was trying to understand where to start and I couldn't find any library for the task so I tried from scratch using vanilla js, this is my attempt.
var testArray = document.querySelectorAll(".image");
var totImg = testArray.length;
var contIterazioni = 0;
var test = testArray[contIterazioni];
var bounding = test.getBoundingClientRect();
function LoopFunction() {
setInterval(galleryScroll, 20);
}
function galleryScroll() {
test = testArray[contIterazioni];
bounding = test.getBoundingClientRect();
if (bounding.left == 0) {
//console.log("immagine bordo sx");
if (test.width > 0) {
test.width = test.width - .25;
} else {
contIterazioni = contIterazioni + 1;
if (contIterazioni >= totImg){
contIterazioni = 0;
}
}
}
}
LoopFunction();
body{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 100vw;
height: 100vh;
display: flex;
overflow: hidden;
}
<div class="container">
<img src="https://media-cdn.tripadvisor.com/media/photo-s/0e/eb/ad/3d/crazy-cat-cafe.jpg" alt="" class="image">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Chairman_Meow_Bao.jpg/1200px-Chairman_Meow_Bao.jpg" alt="" class="image">
<img src="https://static.scientificamerican.com/sciam/cache/file/92E141F8-36E4-4331-BB2EE42AC8674DD3_source.jpg" alt="" class="image">
<img src="https://cdn.britannica.com/91/181391-050-1DA18304/cat-toes-paw-number-paws-tiger-tabby.jpg" alt="" class="image">
<img src="https://www.orlandocatcafe.com/wp-content/uploads/2020/07/14.png" alt="" class="image">
</div>
Unfortunately, I couldn't figure out how to loop the images. Can you help me understand how to do it? Do you think my approach can be a good one? or would you recommend other ways to get that effect?
Thanks!
Use for loop when you go through all images to set their width to their initial value. Also add extra three images from start of the carousel so there wouldn't be empty space when it comes to an end.
var testArray = document.querySelectorAll(".image");
var totImg = testArray.length;
var contIterazioni = 0;
var test = testArray[contIterazioni];
var bounding = test.getBoundingClientRect();
var imgsWidths = []
window.onload = () => {
for(i = 0; i < testArray.length; i++) {
imgsWidths[i] = testArray[i].width
}
}
function galleryScroll() {
test = testArray[contIterazioni];
bounding = test.getBoundingClientRect();
if (bounding.left == 0) {
if (test.width > 0) {
test.width = test.width - 2;
} else {
contIterazioni = contIterazioni + 1;
if (contIterazioni >= totImg - 3){
for(i = 0; i < testArray.length; i++) {
testArray[i].width = imgsWidths[i]
}
contIterazioni = 0;
}
}
}
window.requestAnimationFrame(galleryScroll)
}
window.requestAnimationFrame(galleryScroll);
body{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 100vw;
height: 100vh;
display: flex;
overflow: hidden;
}
<div class="container">
<img src="https://media-cdn.tripadvisor.com/media/photo-s/0e/eb/ad/3d/crazy-cat-cafe.jpg" alt="" class="image">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Chairman_Meow_Bao.jpg/1200px-Chairman_Meow_Bao.jpg" alt="" class="image">
<img src="https://static.scientificamerican.com/sciam/cache/file/92E141F8-36E4-4331-BB2EE42AC8674DD3_source.jpg" alt="" class="image">
<img src="https://cdn.britannica.com/91/181391-050-1DA18304/cat-toes-paw-number-paws-tiger-tabby.jpg" alt="" class="image">
<img src="https://www.orlandocatcafe.com/wp-content/uploads/2020/07/14.png" alt="" class="image">
<img src="https://media-cdn.tripadvisor.com/media/photo-s/0e/eb/ad/3d/crazy-cat-cafe.jpg" alt="" class="image">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Chairman_Meow_Bao.jpg/1200px-Chairman_Meow_Bao.jpg" alt="" class="image">
<img src="https://static.scientificamerican.com/sciam/cache/file/92E141F8-36E4-4331-BB2EE42AC8674DD3_source.jpg" alt="" class="image">
</div>
While keeping your same approach, this should work similarly as the example you provided. If you want the slideshow to keep it's width, all images should have the same width. Your error was not adding back the image that dissapeared to the container, at the end and with it's original width, or as in this case expanding again.
// From https://www.javascripttutorial.net/javascript-queue/
function Queue() {
this.elements = [];
}
Queue.prototype.enqueue = function(e) {
this.elements.push(e);
};
Queue.prototype.dequeue = function() {
return this.elements.shift();
};
Queue.prototype.isEmpty = function() {
return this.elements.length == 0;
};
Queue.prototype.peek = function() {
return !this.isEmpty() ? this.elements[0] : undefined;
};
Queue.prototype.length = function() {
return this.elements.length;
}
let images = new Queue();
document.querySelectorAll(".image").forEach(img => images.enqueue(img));
var totImg = images.length();
var first = images.dequeue();
var last;
var firstWidth = first.width;
var lastWidth = 0.0;
var bounding = first.getBoundingClientRect();
var originalWidth = first.width;
var lastOriginalWidth = 0.0;
var step = 1.0;
var lastStep = 0.0;
function LoopFunction() {
setInterval(galleryScroll, 20);
}
function galleryScroll() {
bounding = first.getBoundingClientRect();
if (bounding.left == 0) {
//console.log("immagine bordo sx");
if (first.width > 0) {
firstWidth -= step;
if (firstWidth < 0) {
firstWidth = 0;
}
first.style.width = firstWidth + 'px';
} else {
if (last && last.width != lastOriginalWidth) {
last.width = lastOriginalWidth;
}
let container = document.querySelector('.container');
container.removeChild(first);
last = first;
lastOriginalWidth = originalWidth;
last.width = 0.0;
lastWidth = 0.0;
images.enqueue(last);
container.appendChild(last);
first = images.dequeue();
originalWidth = first.width;
firstWidth = originalWidth;
lastStep = step * lastOriginalWidth / originalWidth;
}
}
if (last && last.width <= lastOriginalWidth) {
lastWidth += lastStep;
last.style.width = lastWidth + 'px';
if (last.width > lastOriginalWidth) {
last.width = lastOriginalWidth;
}
}
}
LoopFunction();
body {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 100vw;
height: 100vh;
display: flex;
overflow: hidden;
}
<div class="container">
<img src="https://media-cdn.tripadvisor.com/media/photo-s/0e/eb/ad/3d/crazy-cat-cafe.jpg" alt="" class="image">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Chairman_Meow_Bao.jpg/1200px-Chairman_Meow_Bao.jpg" alt="" class="image">
<img src="https://static.scientificamerican.com/sciam/cache/file/92E141F8-36E4-4331-BB2EE42AC8674DD3_source.jpg" alt="" class="image">
<img src="https://cdn.britannica.com/91/181391-050-1DA18304/cat-toes-paw-number-paws-tiger-tabby.jpg" alt="" class="image">
<img src="https://www.orlandocatcafe.com/wp-content/uploads/2020/07/14.png" alt="" class="image">
</div>
Update #1
As requested by OP, here is some further explenation of the changes I made:
I used a simple queue from javascripttutorial to have a data structure that reflects the objective, i.e. having images that move from right to left, and once they "exit" the scene, can get enqueued again.
Following this concept, we need pointers to both head and tail of the queue in order to update their animation, in particular first, firstWidth and originalWidth are used respectively to point to the head, keep track of its current width during the animation and the originalWidth to which it should return when re-entering the scene. Similarly, this happens for the last as well.
Once this is in place, our loop will be made of two parts, one that handles the head animation and moves the images in the queue when the head image reaches width == 0 and one that handles the tail re-entering the scene and expanding. To achieve continuity, we use a simple proportion after we have our new queue: step : originalWidth = lastStep : lastOriginalWidth, which we use to determine at each frame how much respectively the head and tail images compress and expand. as step is a fixed parameter, lastStep is easily computed through simple arithmetics: lastStep = step * lastOriginalWidth / originalWidth.
The code:
let container = document.querySelector('.container');
container.removeChild(first);
last = first;
lastOriginalWidth = originalWidth;
last.width = 0.0;
lastWidth = 0.0;
images.enqueue(last);
container.appendChild(last);
first = images.dequeue();
originalWidth = first.width;
is just a contextual switch over the changing the queue, where the pointers and respective data get update to reflect the changes in the data structure. So the first becomes last, the next image in the queue is the new compressing first, as such originalWidth shifts.
Let's go further
Now, to achieve your desired implementation, this still needs some work. First of all, the queue should only reflect the actual carousel, not all the images you have, so ideally you would have a first static data structure with all the images and respective metadata, in this case we mainly need their original width. then you would have a queue representing the images that are being animated.
Now, you can either reuse this code and change the width of the images to be all equal and fit the viewport you are using for your animation, which should work fine. The other option is to mirror the code for the head image to the tail, have a fixed step, so while the head compresses of step pixels, the tail expands of the same step pixels, and when the tail reaches maximum width, introduce a new image at the end of the queue which becomes the new tail.
To go in further detail on the last, the algorithm would look something like this:
initialize static list of image containers with their respective width (imgList);
initialize an empty queue (imgQueue);
initialize a pointer pointing to the last image introduced in the queue (listPtr);
get the width of the viewport your carousel should fill (vpWidth);
while you have not filled such width, keep adding images to the queue and moving the listPtr left in the imgList;
have looping function similar to the one above but where the if over last replicates similar steps to the first ones;
This should be everything, I will work on the code in a while, now I need some sleep ;).
Update #2
Okay! Worked out something that actually works decently. If you have suggestions please let me know, in the meanwhile, here it is:
// From https://www.javascripttutorial.net/javascript-queue/
function Queue() {
this.elements = [];
}
Queue.prototype.enqueue = function(e) {
this.elements.push(e);
};
Queue.prototype.dequeue = function() {
return this.elements.shift();
};
Queue.prototype.isEmpty = function() {
return this.elements.length == 0;
};
Queue.prototype.first = function() {
return !this.isEmpty() ? this.elements[0] : undefined;
};
Queue.prototype.length = function() {
return this.elements.length;
};
// Added function to peek last element in queue
Queue.prototype.last = function() {
return !this.isEmpty() ? this.elements[this.elements.length - 1] : undefined;
};
// Added function that pops the head, enqueues it and returns it
Queue.prototype.shift = function() {
const head = this.dequeue();
this.enqueue(head);
return head;
}
// Returns a queue of HTMLElements based on the given class
function loadQueue(className) {
const rQueue = new Queue();
document.querySelectorAll('.' + className).forEach(image => rQueue.enqueue(image));
return rQueue;
}
// Queue of images to be added to the animation queue
const imgQueue = loadQueue('image');
// Images being animated inside the div
const imgAnimQueue = new Queue();
// To limit calls to the carousel
const carousel = $('.container');
function init() {
// Width of the viewport being used for the animation
// TODO: this shoud update whenever the page is resized, or at least the div
const vpWidth = carousel.width();
// Keeps track of the width of the images added to the animation queue
var currentFilledWidth = 0;
// Now that we have loaded the static information, let's clear the div
// that will be used as carousel, so that we can add the correct number
// of images back in
carousel.empty();
// Filling the animation queue
while (currentFilledWidth < vpWidth) {
// In order not to change the static data, we clone the image HTMLElement
const img = $(imgQueue.shift()).clone();
// Enqueuing the new image in the animation queue
imgAnimQueue.enqueue(img);
// Adding this image into the carousel
img.appendTo(carousel);
currentFilledWidth = currentFilledWidth + img.width();
// If we overflow the carousel width, we set the tail image to fill
if (currentFilledWidth > vpWidth) {
const overflow = currentFilledWidth - vpWidth;
img.width(img.width() - overflow);
currentFilledWidth -= overflow;
}
}
const step = 1;
var firstWidth = imgAnimQueue.first().width();
var lastWidth = imgAnimQueue.last().width();
// Now the loop can start
window.requestAnimationFrame(animateCarousel);
// Main function that animates the carousel
function animateCarousel() {
let first = imgAnimQueue.first();
let last = imgAnimQueue.last();
// If the image is still not disappeared, keep compressing it
if (firstWidth > 0) {
firstWidth -= step;
if (firstWidth < 0) firstWidth = 0;
first.width(firstWidth);
// Otherwise, remove it from the carousel and update all the data structs
} else {
first.remove();
imgAnimQueue.dequeue();
if (imgAnimQueue.first() != last) {
first = imgAnimQueue.first();
firstWidth = first.width();
} else {
first = last;
firstWidth = lastWidth;
imgAnimQueue.enqueue($(imgQueue.shift()).clone());
last = imgAnimQueue.last();
lastWidth = last.width();
last.appendTo(carousel);
}
}
if (lastWidth <= last.attr("data-original-width")) {
lastWidth += step;
// The image has completely expanded, let's introduce the next one
if (lastWidth >= last.attr("data-original-width")) {
last.width(last.attr("data-original-width"));
imgAnimQueue.enqueue($(imgQueue.shift()).clone());
last = imgAnimQueue.last();
last.width(0);
lastWidth = last.width();
last.appendTo(carousel);
// Otherwise just keep expanding it
} else {
last.width(lastWidth);
}
}
window.requestAnimationFrame(animateCarousel);
}
}
body {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 100vw;
height: 100vh;
display: flex;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
var loadedImages = 0;
const count = 4;
function loadImage(img) {
if (loadedImages != count) {
$(img).attr("data-original-width", $(img).width());
loadedImages += 1;
if (loadedImages == count) init();
}
}
</script>
<div class="container">
<img onload="loadImage(this)" src="https://media-cdn.tripadvisor.com/media/photo-s/0e/eb/ad/3d/crazy-cat-cafe.jpg" alt="1" class="image">
<img onload="loadImage(this)" src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Chairman_Meow_Bao.jpg/1200px-Chairman_Meow_Bao.jpg" alt="2" class="image">
<img onload="loadImage(this)" src="https://cdn.britannica.com/91/181391-050-1DA18304/cat-toes-paw-number-paws-tiger-tabby.jpg" alt="3" class="image">
<img onload="loadImage(this)" src="https://www.orlandocatcafe.com/wp-content/uploads/2020/07/14.png" alt="4" class="image">
</div>
i have this code here for sliding images but i wanted to do the same thing for sliding text instead of images but it is not working with me when i tried it , so any one can do it for me text slider moving from left to right instead of image slider without mouse click? and thanks in advance
var mainImage = document.getElementById("mainImage");
//Create image array
var imageArray = ["Life is what happens to us while we are making other plans","Life is what happens to us while we are making other plans","Life is what happens to us while we are making other plans"];
//Set up array index
var imageIndex = 0;
function changeImage() {
mainImage.setAttribute("src",imageArray[imageIndex]);
imageIndex++;
if(imageIndex >= imageArray.length) {
imageIndex = 0;
}
}
//Create function to cycle through images
mainImage.onclick = changeImage
//Call cycle function
var intervalHandle = setInterval(changeImage,3000);
mainImage.onclick = function () {
clearInterval(intervalHandle);
}
h1 {
text-align: center;
}
#mainImage {
padding-left: 350px;
padding-top: 40px;
}
//<img id="mainImage" src="images/D.png" />
You need to use HTML DOM innerHTML Property.
Create an element with id="text" change document.getElementById("text").innerHTML
var textElement = document.getElementById("text");
//Create image array
var imageArray = ["Life is what happens to us while we are making other plans","Life is what happens to us while we are making other plans2","Life is what happens to us while we are making other plans3"];
//Set up array index
var imageIndex = 0;
function changeImage() {
textElement.innerHTML = imageArray[imageIndex]
imageIndex++;
if(imageIndex >= imageArray.length) {
imageIndex = 0;
}
}
//Create function to cycle through images
textElement.onclick = changeImage
//Call cycle function
var intervalHandle = setInterval(changeImage,3000);
textElement.onclick = function () {
clearInterval(intervalHandle);
}
h1 {
text-align: center;
}
#mainImage {
padding-left: 350px;
padding-top: 40px;
}
<p id="text"></p>
I got this thing over here:
function duplicateElement() {
const holder = document.querySelector('.holder');
let elements = document.querySelectorAll('.item');
let firstEl = elements[0];
//let lastEl = elements[elements.length - 1];
console.log(elements.length);
let dimensions = firstEl.offsetWidth;
let reducedDimensions = dimensions / 1.45;
elements.forEach(element => {
let duplicate = element.cloneNode(true);
holder.appendChild(duplicate);
element.style.width = `${reducedDimensions}px`;
element.style.height = `${reducedDimensions}px`;
});
}
let callCount = 1;
let repeater = setInterval(function() {
if (callCount < 5) {
duplicateElement();
callCount += 1;
} else {
clearInterval(repeater);
}
}, 5000);
.bg-black {
background: black;
}
.item {
border-radius: 50%;
}
.square::after content: "";
display: block;
padding-bottom: 100%;
}
<div class="holder">
<div class="bg-black square item"></div>
</div>
What this does is that it runs the function duplicateElements n times.
In duplicateElements() i double the number of elements in each iteration. The parent starts with just 1 item, which become 2, 4, 8, 16, etc (depending on callCount). This works as i want.
Additionally, i want to reduce the size of every element. So i check for the dimensions of the first item, divide the number by a factor and apply the new dimensions as width and height to every item.
That however does not work, as it applies the new dimensions only to the newly duplicated items, leaving the items created in the previous iteration with their old values. (You can check this in the console, as it applies that values as well)
What i am missing here? My train of thought was that since i check for all items with let elements = document.querySelectorAll('.item') anew in EVERY ITERATION, i would also apply my new dimensions to each element.
console.log(elements.length); gives me the correct number of items in each iteration so why don't the dimensions apply?
Hey, thanks!
The problem is: you select all elements before the loop in
let elements = document.querySelectorAll('.item');
Which is correct, but then inside the loop you duplicate the current element and append it to the DOM before setting the dimensions, so this duplicated element is not getting the new dimensions before beign appended...
So, the solution is: just move the part that duplicate the element to below the part that set the dimensions, see below, inside the loop (I reduced to 1 second to faster example)
function duplicateElement() {
const holder = document.querySelector('.holder');
let elements = document.querySelectorAll('.item');
let firstEl = elements[0];
console.clear()
console.log(elements.length);
let dimensions = firstEl.offsetWidth;
let reducedDimensions = dimensions / 1.45;
elements.forEach(element => {
element.style.width = `${reducedDimensions}px`;
element.style.height = `${reducedDimensions}px`;
let duplicate = element.cloneNode(true);
holder.appendChild(duplicate);
});
}
let callCount = 1;
let repeater = setInterval(function() {
if (callCount < 5) {
duplicateElement();
callCount += 1;
} else {
clearInterval(repeater);
}
}, 1000);
.bg-black {
background: black;
}
.item {
border-radius: 50%;
}
.square::after {
content: "";
display: block;
padding-bottom: 100%;
}
<div class="holder">
<div class="bg-black square item"></div>
</div>
Also, I fixed the CSS, there was missing a {
I'm trying to fade in/out and fix the blue div on the left when scrolled relative to the image blocks on the right.
http://www.warface.co.uk/#/testing/
pass: squared
.meta { /*This is the block I'm trying to stick/*
background: blue;
position: fixed;
width: 372px;
float: left;
z-index: 3;
right: 100%;
}
Here is the basics in JavaScript:
function controlMeta() {
var meta = document.querySelector("div.meta");
console.log(meta);
if (window.scrollY > 500) {
meta.style.display = "none";
} else {
meta.style.display = "block";
}
}
window.addEventListener("scroll", function () {
controlMeta();
})
You can get your elements scroll position with something like this:
document.getElementById("57513a9220c6475fb77061c5").getBoundingClientRect().top+window.scrollY
EDIT 1
Here is a method for associating elements with the meta box, based upon the previous:
//Load elements that affect the meta box
var meta = [];
var images = document.querySelector('.sqs-gallery').getElementsByTagName('img');
for (var i = 0; i < images.length; i++) {
meta.push({
node : images[i],
height : images[i].height,
//top is used with scroll position to determine which element we are looking at
top : images[i].getBoundingClientRect().top + window.scrollY
});
}
function controlMeta() {
meta.filter(function (el) {
//You might need to pad your filter a little
return window.scrollY < el.top && window.scrollY > el.top - el.height;
}).forEach(function (el) {
//These are the matching elements. I'm just fetching the src as an example
document.querySelector("div.meta div.body").innerHTML = el.node.src;
});
}
window.addEventListener("scroll", function () {
controlMeta();
});