JS Slideshow with Next button - javascript

I want my code to act like a slideshow. If I click the next button it will hide the previous image and show the other image. It will show the first image, but it doesn't' go through the loop . I also have an error that say
"Uncaught TypeError: Cannot read property 'style' of undefined".
<!DOCTYPE html>
<html lang ="en">
<head>
<title> VIS</title>
<meta charset="utf-8"/>
</head>
<body>
<div style="position: relative; visibility: hidden;">
<img src="http://vignette4.wikia.nocookie.net/mrmen/images/5/52/Small.gif/revision/latest?cb=20100731114437"
alt="Pumpkins" id="Pum"/>
</div>
<div style="position: relative; visibility: hidden;">
<img src="http://vignette4.wikia.nocookie.net/mrmen/images/5/52/Small.gif/revision/latest?cb=20100731114437"
alt="Pumpkins" id="Straw"/>
</div>
<div style="position: relative; visibility: hidden;">
<img src="http://vignette4.wikia.nocookie.net/mrmen/images/5/52/Small.gif/revision/latest?cb=20100731114437"
alt="Pumpkins" id="Ras"/>
</div>
<button onclick="removeVisibility()">Next</button>
</body>
<script type="text/javascript" >
function removeVisibility(){
var imgs=document.getElementsByTagName('img');//get all the images
for(var i=0;i< imgs.length;i++){
imgs[i].style.visibility= 'visible'; //hide them
imgs[i-1].style.visibility= 'hidden';
}
}
</script>
</html>

jsBin demo
You have your DIV (!!!) elements set to visibility: hidden; but you're trying desperately to change the visibility to IMG.
Now that you know your main issue, you should better go with display none/block if you use position:relative (or rather use position: absolute for your overlaying elements...) Any way,
don't use inline CSS styles! That's why we invented stylesheets!
don't use inline JS! Use addEventListener to attach any desired event to your elements. Don't mix your application logic with (view) teplating.
var imagesHolder = document.getElementById("imagesHolder");
var images = imagesHolder.getElementsByTagName('img');
var imagesTot = images.length;
var button = document.getElementById("nextImage");
var counter = 0; // We'll use it to get the image index
function showNext(){
counter = ++counter % imagesTot; // Increment and loop counter
for(var i=0; i<imagesTot; i++){
if(i != counter) images[i].style.display = "none"; // Hide all but `counter` one
}
// Finally show the 'counter' one!
images[counter].style.display = "block";
}
button.addEventListener("click", showNext);
#imagesHolder img+img{ /* SHOW ALL BUT FIRST!*/
display:none;
}
<div id="imagesHolder">
<img src="http://lorempixel.com/400/200/sports/1" alt="1"/>
<img src="http://lorempixel.com/400/200/sports/2" alt="2"/>
<img src="http://lorempixel.com/400/200/sports/3" alt="3"/>
</div>
<button id="nextImage">Next</button>
...but wait!
Welcome to the world of responsive web design!
so let's add some animations and responsiveness:
var imagesHolder = document.getElementById("imagesHolder"),
images = imagesHolder.getElementsByTagName('div'),
n = images.length,
c = 0;
function showNext(){
c = ++c % n;
for(var i=0; i<n; i++) images[i].classList[i!=c?"add":"remove"]("fadeaway");
}
document.getElementById("nextImage").addEventListener("click", showNext);
showNext(); // Initial kick
*{margin:0;}
html, body{height:100%;}
#imagesHolder{
position:relative;
overflow:hidden;
width:100%;
height:90vh;
}
#imagesHolder div{
position: absolute;
width:inherit;
height:inherit;
background:50% / cover;
transition: 1s 0s ease;
/* Default when visible: */
opacity: 1;
transform: scale(1);
}
#imagesHolder div.fadeaway{
opacity:0;
transform: scale(1.2);
}
<div id="imagesHolder">
<div style="background-image:url(http://lorempixel.com/400/200/sports/1);"></div>
<div style="background-image:url(http://lorempixel.com/400/200/sports/2);"></div>
<div style="background-image:url(http://lorempixel.com/400/200/sports/3);"></div>
</div>
<button id="nextImage">Next</button>

Related

adding a classList to each element at a time in a array - plain js

I'm new to javascript and I've been trying something that although basic i can't really seem to understand why it isn't working.
I have three images and one button. Everytime I click that same button i want one of the images to disappear (using classList to add a Css class of display: none).
I'm trying to use the for loop but when I click the button they disappear at the same time. I've tried to create a variable inside the loop to store the index value but it returns an error.
Help please !!! Thanks
\\ Js
window.onload = function(){
var button = document.querySelector("button");
var imgs = document.querySelectorAll("#imagens img");
button.addEventListener("click",function(){
for(var i=0; i<imgs.length; i++){
imgs[i].classList.add("hidden");
//var currentImg = this.imgs[i];
//currentImg.classList.add("hidden");
}
})
};
\\\ CSS
.hidden{
display:none;
}
#images{
width:400px;
height:200px;
margin:0 auto;
}
#images img{
width:110px;
height:100px;
}
button{
margin:100px auto;
}
\\\ HTML
<div id="images">
<img src="https://media.defense.gov/2018/Jul/11/2001941257/780/780/0/180711-F-EF974- 0115.JPG" alt="">
<img src="https://live.staticflickr.com/3267/2590079513_12e2c73226_b.jpg" alt="">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Poinsettia_tree.jpg/360px-Poinsettia_tree.jpg" alt="">
<div>
<button type="button">change</button>
</div>
</div>
You can use setTimeout for this requirement and update the for loop inside button click like:
for (var i = 0; i < imgs.length; i++) {
(function(index) {
setTimeout(function() {
imgs[index].classList.add("hidden");
}, i * 1500);
})(i);
}
This way hidden class would be added to one image at a time after a delay of 1500 ms.
The problem is that every time the button is clicked, you loop through all the images so you add to all of them the hidden class. What you need to do is to create a global variable that can store the index of the last image you hid.
And when you click the button, you add the hidden class to the image at the index + 1 then increment that index for the next image. You don't need to have a for loop for that.
You also mistyped in your query selector, it should be
var imgs = document.querySelectorAll("#images img");
instead of
var imgs = document.querySelectorAll("#imagens img");
So here's what you should have :
let index = -1;
window.onload = function(){
var button = document.querySelector("button");
var imgs = document.querySelectorAll("#images img");
button.addEventListener("click",function(){
index++;
imgs[index].classList.add("hidden");
})
};
.hidden {
display: none;
}
#images {
width: 400px;
height: 200px;
margin: 0 auto;
}
#images img {
width: 110px;
height: 100px;
}
button {
margin: 100px auto;
}
<div id="images">
<img src="https://media.defense.gov/2018/Jul/11/2001941257/780/780/0/180711-F-EF974- 0115.JPG" alt="">
<img src="https://live.staticflickr.com/3267/2590079513_12e2c73226_b.jpg" alt="">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Poinsettia_tree.jpg/360px-Poinsettia_tree.jpg" alt="">
<div>
<button type="button">change</button>
</div>
</div>

JavaScript - periodically change "active" image

I have 4 pictures and want them to periodically change class (I have .active class, which is similar to hover).
.active,
.pic:hover{
position: absolute;
border: 1px solid black;
transform: scale(1.1);
transition: transform .2s;
}
Basically I need the first picture to have the class active and after some time change it so the next picture has the class and the first one lose it.
Is something like that even possible?
Picture in HTML:
<div class="products">
<a href="http://example.com/produkt1">
<img class="pic" src="image.jpg" alt="image" width="75" height="75">
</a>
</div>
and JS:
productIndex = 0;
slideshow();
function slideshow(){
var i;
var pic = document.getElementsByClassName("pic");
for(i = 0; i < pic.length; i++){
pic[i].className = pic[i].className.replace("active", "");
}
productIndex++;
if(productIndex > pic.length){
productIndex = 1;
}
pic[productIndex-1].className += active;
setInterval(slideshow, 2000);
}
You can use setInterval to run a function periodically that will change the active class. Something like this (psuedo-code):
var imageArray = [];
var activeIndex = 0;
setInterval(function(){
imageArray[activeIndex].removeClass('active');
activeIndex++;
activeIndex %= 4;
imageArray[activeIndex].addClass('active');
}, 5000);
The number value passed in as a parameter is how many milliseconds to wait before running the function again. In this example, 5 seconds will pass between the classes are changed.
setInterval Reference
This is ugly but it could work for super basic ... You just need to update the div blocks with images if necessary. Uses jquery...
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<style>
div {
width:50px;
height:50px;
background-color: black;
margin-bottom:10px;
}
.active {
background-color: red;
}
</style>
</head>
<body>
<div id="pic1"></div>
<div id="pic2"></div>
<div id="pic3"></div>
<div id="pic4"></div>
<script>
let lastActive = 0;
setInterval(()=>{
$('div').removeClass('active');
if(lastActive === 0){
$('#pic1').addClass('active');
lastActive = 1;
}
else if(lastActive === 1){
$('#pic2').addClass('active');
lastActive = 2;
}
else if(lastActive === 2){
$('#pic3').addClass('active');
lastActive = 3;
}
else if(lastActive === 3){
$('#pic3').addClass('active');
lastActive = 4;
}
else if(lastActive === 4){
$('#pic1').addClass('active');
lastActive = 1;
}
}, 500)
</script>
</body>
</html>
Matt L. has a good point here. Your code has the setInterval inside your slideshow function, otherwise it's fine.
productIndex = 0;
slideshow();
function slideshow(){
var i;
var pic = document.getElementsByClassName("pic");
for(i = 0; i < pic.length; i++){
pic[i].className = pic[i].className.replace("active", "");
}
productIndex++;
if(productIndex > pic.length){
productIndex = 1;
}
pic[productIndex-1].className += active;
}
setInterval(slideshow, 2000);
could probably work. Matt's answer is a lot better, and I came up with something similar, which is testable on jsfiddle.
You could do it like this for example:
$(document).ready(function() {
setInterval(function() {
var active = $('.active');
active.nextOrFirst().addClass('active');
active.removeClass('active');
}, 3000);
});
$.fn.nextOrFirst = function(selector)
{
var next = this.next(selector);
return (next.length) ? next : this.prevAll(selector).last();
};
.active,
.pic:hover{
border: 1px solid black;
}
.pic {
width: 150px;
margin: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="image-container">
<img class="pic active" src="https://via.placeholder.com/350x150">
<img class="pic" src="https://via.placeholder.com/350x150">
<img class="pic" src="https://via.placeholder.com/350x150">
<img class="pic" src="https://via.placeholder.com/350x150">
</div>
Edit:
This, instead of most other solutions, will work with any amount of items. To use it only on pictures just specify via selector in the function.
Checkout this working example. I've made use of a combination of setInterval and setTimeout.
$(window).ready(()=>{
// get all the images inside the image-container div
let $images = $('.image-container').find('.image');
let currImage = 0;
// execute this code every 2 seconds
window.setInterval(()=>{
// add the active class to the current image
$($images[currImage]).addClass('active');
setTimeout(()=>{
// execute the code here after 1.5 seconds
// remove the active class from the previous image
$($images[currImage-1]).removeClass('active');
}, 1500);
// make sure we don't go over the number of elements in the collection
currImage = currImage >= $images.length ? 0 : currImage + 1;
}, 2000);
});
.image.active {
border: thin solid blue;
}
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<div class="image-container" class="">
<img src="https://via.placeholder.com/200x200" class="image active">
<img src="https://via.placeholder.com/200x200" class="image">
<img src="https://via.placeholder.com/200x200" class="image">
<img src="https://via.placeholder.com/200x200" class="image">
</div>
Do make sure that the code in setTimeout will execute before the next interval. Meaning, the time set for setTimeout is always less than setInterval's :)
Yes it is possible:
function carousel() {
var images = document.querySelectorAll(".container img");
for(var i = 0; i < images.length; i++) {
if(images[i].classList.contains("active")) {
images[i].classList.remove("active");
if(i == images.length - 1) {
images[0].classList.add("active");
} else {
images[i + 1].classList.add("active");
}
break;
}
}
}
setInterval(carousel,1000);
img {
width: 100px;
margin-left: 10px;
transition: .2s;
}
.active {
transform: scale(1.1);
}
<div class="container">
<img src="https://i.stack.imgur.com/cb20A.png" class="active"/>
<img src="https://i.stack.imgur.com/cb20A.png"/>
<img src="https://i.stack.imgur.com/cb20A.png"/>
<img src="https://i.stack.imgur.com/cb20A.png"/>
</div>
You can then replace the .active class by whatever you want.

z-Index slide show using the next button

So I have to code a button that uses z-index to go to the next picture in the slideshow. I am having difficulty trying to get it to work and I feel as though I am doing something wrong. It has to have a count of 0, 1, 2, 0, 1, 2
<!DOCTYPE html>
<html lang = "en">
<head>
<title>Lab 5, Part 1</title>
<meta charset = "utf-8"/>
<script type = "text/javascript">
function Next() {
document.getElementById('anime1').style.zIndex = 0;
document.getElementById('anime2').style.zIndex = 1;
document.getElementById('anime3').style.zIndex = 2;
}
</script>
<style type = "text/css">
.anime1 {position: absolute;
top: 150px; left: 250px; z-index: 10;}
.anime2 {position: absolute;
top: 200px; left: 300px; z-index: 15;}
.anime3 {position: absolute;
top: 250px; left: 350px; z-index: 20;}
</style>
</head>
<body>
<h1 style= "text-align: center">Lab 5, Part 1</h1>
<p>
<div class="slideshow">
<img class = "anime1" id = "anime1" height = "300"
width = "450" src = "http://images5.fanpop.com/image/photos/29300000/Megurine-Luka-megurine-luka-29391390-1680-1050.jpg"
alt = "First Image"/>
<img class = "anime2" id = "anime2" height = "300"
width = "450" src = "http://orig06.deviantart.net/a28f/f/2015/079/9/a/hinata_final_lr_by_artgerm-d8me6vb.jpg"
alt = "Second Image"/>
<img class = "anime3" id = "anime3" height = "300"
width = "450" src = "http://images6.fanpop.com/image/photos/35700000/Hatsune-Miku-snowangel_-35736242-1600-1200.jpg"
alt = "Third Image"/>
</p>
<input type="button" value="Next" onclick="Next();">
</body>
</html>
I have looked every where online to see if anything could help me but I can't find anything
If you're willing to take a more programmatic approach, you can use an array to hold the order and iterate it to set the z-indexes.
Using this method you can
pop() the item from the end of the array and unshift() it onto the beginning, or
shift() the item from the beginning of the array and push() it onto the end.
Which allows you to easily handle any number of elements while keeping your code DRY.
I've taken the liberty of making a back button as well as the next button, to show you how easy it is when approaching it this way. I've also generalized the class names and used different placeholder images for the demo.
(function(){ // keep it safe
var slideshow = document.querySelector('.slideshow'); // store the parent
var controls = slideshow.querySelector('.controls'); // store the controls
var els = slideshow.querySelectorAll('.slide'); // store the slides
var order = Object.keys(els); // store the order
var cn; // make the class holder
// assign a click handler to the parent
controls.onclick = function(e) {
// if the class is back or next, store it, otherwise stop here
if(!(cn = (e.target.className.match(/back|next/)||[false])[0])) return;
// if back clicked, move the last element to the beginning
if(cn === "back") order.unshift(order.pop());
// if next clicked, move the first element to the end
if(cn === "next") order.push(order.shift());
// iterate the order, set the z-index of each element sequentially
for(var i in order) els[order[i]].style.zIndex = i;
}
})();
.slides { position: relative; margin-top: 5px; }
.slide { position: absolute; }
.slide2 { top: 25px; left: 25px; }
.slide3 { top: 50px; left: 50px; }
<div class="slideshow">
<div class="controls">
<button class="back">Back</button>
<button class="next">Next</button>
</div>
<div class="slides">
<img class="slide slide1" src="http://placehold.it/150x150/f9fd42/fff">
<img class="slide slide2" src="http://placehold.it/150x150/42f9fd/fff">
<img class="slide slide3" src="http://placehold.it/150x150/fd42f9/fff">
</div>
</div>
Further Reading
Array.prototype.pop() (MDN)
Array.prototype.unshift() (MDN)
Array.prototype.shift() (MDN)
Array.prototype.push() (MDN)
Don't Repeat Yourself (Wikipedia)
Are you looking for something like this: https://jsfiddle.net/5L7jk73g/
var cnt = 0;
function Next() {
if (cnt == 0) {
document.getElementById('anime1').style.zIndex = 0;
document.getElementById('anime2').style.zIndex = 1;
document.getElementById('anime3').style.zIndex = 2;
cnt++;
} else if (cnt == 1) {
document.getElementById('anime1').style.zIndex = 1;
document.getElementById('anime2').style.zIndex = 2;
document.getElementById('anime3').style.zIndex = 0;
cnt++;
} else {
document.getElementById('anime1').style.zIndex = 2;
document.getElementById('anime2').style.zIndex = 0;
document.getElementById('anime3').style.zIndex = 1;
cnt = cnt - 2;
}
}

How to stop my images loading before the javascript slideshow loads?

I am new to this and have a quick question. I have a very simple slideshow on my home page. The problem I am having is the first second or so of loading the page, the slideshow images show up 1 on top of the other. Once the first second or so of loading the page is over, everything works fine. Here is my code for the javascript:
<script type="text/javascript" language="javascript">
window.onload = function () {
var rotator = document.getElementById("slideshow_content");
var images = rotator.getElementsByTagName("img");
for (var i = 1; i < images.length; i++) {
images[i].style.display = "none";
}
var counter = 1;
setInterval(function () {
for (var i = 0; i < images.length; i++) {
images[i].style.display = "none";
}
images[counter].style.display = "block";
counter++;
if (counter == images.length) {
counter = 0;
}
}, 3000);
};
</script>
Here is the body code:
<div id="slideshow">
<div id="slideshow_content" style="padding-top:10px; padding-bottom:10px;">
<img alt="" src="/images/slide1.jpg" />
<img alt="" src="/images/slide2.jpg" />
</div>
</div>
Here is the CSS for the 2 divs:
#slideshow {position:relative; top:0; left:0; max-width:1680px; height:342px; margin:0 auto; padding:0; background-color:#070707;}
#slideshow_content {width:960px; max-height:322px; margin:0 auto; padding:0;}
How would you recommend fixing this?
I would set the CSS to hide the slideshow on page load, and then when the slideshow starts it could be unhidden.
This would also mean that if someone had javascript disabled they wouldn't get a weird looking pile of images.
Alternatively you could hide all but the first image using CSS, so that even if someone had javascript disabled they would see the first image.

Onclick switch from one to two images then back to one

Trying to figure out how to switch from one to two images then back to one with an onlick.
So far I have below which works no problem for switching to one image and back to original image. Ultimately I'm trying to get the first onclick event to be two images vertically and then click again back to the first single image.
var play = false;
function toggle() {
var image = document.getElementById('image')
var scan = document.getElementById('scan');
play = !play;
if (play) {
image.src = "pause.png";image.width="182";image.height="182";image.border="0";
scan.play();
}
else {
image.src = "play.png";image.width="182";image.height="182";image.border="0";
scan.pause();
}
}
and in body:
<img onclick="toggle()" id="image" src="play.png" alt="image" width="182" height="182" style="margin:auto; position:absolute; top: 0; right: 0; bottom: 0; left: 0; border: 0;">
This should work fine except, take out the width, height and border from the javascript, they're not changing so why have it there and risk some browsers freaking out on them?
I just put this together real quick to test and it works a treat.. I've commented out scan.play and pause of course but I'm assuming you've checked the console in your browser to see if those are throwing any errors?
I took the <a> out and used style cursor=pointer instead for the click-able element as well.. either way works but this is neater and works from ie6 I think, ie7+ definately.
edit: removed source block didn't achieve goal of question
After discussion in comment there's heaps of ways to do it, and I'd probably use jQuery but since you're not here's one not
<!doctype html>
<html>
<head>
<script type="text/javascript">
var play = true;
function toggle() {
//var scan = document.getElementById('scan');
var playpause = document.getElementById('playpause');
var btnplay = playpause.getElementsByClassName('play');
var btnpause = playpause.getElementsByClassName('pause');
play = !play;
if (play) {
btnplay[0].className = 'btn play active';
btnpause[0].className = 'btn pause';
//scan.play();
}
else {
btnplay[0].className = 'btn play';
btnpause[0].className = 'btn pause active';
//scan.pause();
}
}
</script>
<style>
.btn {
width: 182px;
height: 182px;
cursor: pointer;
position: absolute;
visibility: hidden;
}
.btn.active { visibility: visible; }
.btn.play { background: url('play.png') no-repeat 0 0; }
.btn.pause {
background: url('pause.png') no-repeat 0 0;
padding: 182px 0 0 0;
}
</style>
</head>
<body>
<div id="playpause">
<div class="btn play active" onclick="toggle()">
</div>
<div class="btn pause" onclick="toggle()">
<img src="other.png" alt="other" />
</div>
</body>
</html>

Categories