How can I add a mouse over event to this function? - javascript

I am working on a slideshow / carousel in HTML with vanilla JS controlling the changing of the slides. I am happy with the current functionality, but I would like the slideshow to pause if the user hovers over the gallery. I understand that I could do this by clearing the timeout function, but I am stuck on how to integrate that into the current function. I am trying to add this functionality to the 'showSlides' function.
HTML
<div class="galleryImages">
<div class="numbertext">1 / 2</div>
<img src="./assets/images/1.jpg" style="width: 100%;" />
</div>
<div class="galleryImages">
<div class="numbertext">2 / 2</div>
<img src="./assets/images/2.jpg" style="width: 100%;" />
</div>
<!-- Next and previous buttons -->
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
</div>
JS
var slideIndex = 0;
showSlides();
// Next/previous controls
function plusSlides(n) {
changeSlides((slideIndex += n));
}
// automatically show slides and change the slide at the set timeout
function showSlides() {
var i;
var slides = document.getElementsByClassName("galleryImages");
let gallery = document.getElementById("gallery");
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
slideIndex++;
if (slideIndex > slides.length) {
slideIndex = 1;
}
slides[slideIndex - 1].style.display = "block";
setTimeout(showSlides, 5000); // Change image every 5 seconds
}
// change the slides based on the user input on the prev and next buttons
function changeSlides(n) {
var i;
var slides = document.getElementsByClassName("galleryImages");
if (n > slides.length) {
slideIndex = 1;
}
if (n < 1) {
slideIndex = slides.length;
}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
slides[slideIndex - 1].style.display = "block";
}

Add a variable which will hold a reference to the timeout to the top:
var currentTimeout = null;
Store the new timeout into this variable when creating:
currentTimeout = setTimeout(showSlides, 5000); // Change image every 5 seconds
Hover event handler:
if (currentTimeout) {
clearTimeout(currentTimeout);
currentTimeout = null;
}
Hoverout event handler:
if (currentTimeout) {
// Should never happen, but to be safe...
clearTimeout(currentTimeout);
}
currentTimeout = setTimeout(showSlides, 5000); // Change image every 5 seconds

In showSlides() set
gallery.addEventListener('mouseover', function() {
// stop timeout here
});
gallery.addEventListener('mouseout', function() {
// restart automatic slides change
});
EDIT: as showSlides() is executed many times you'll need to remove event listeners, or refactor your code, so that those listeners are set once at the beginning only.

Related

how do I reset img to original image after user goes idle

So far this is what I have tried. I cant seem to figure out how to reset the img src to the first image in the folder after the user does not click on a button for 5 seconds.
HTML
<div class="slider">
<div class="img-box">
<img src="images/a.jpg" class="slider-img">
</div>
<button id="first" class="btn" onclick="prev()">Prev</button>
<button id="second" class="btn" onclick="next()">Next</button>
</div>
JavaScript
var slider_img = document.querySelector('.slider-img');
var images = ['a.jpg', 'b.jpg', 'c.jpg', 'd.jpg', 'e.jpg'];
var i = 0;
function prev(){
if(i <= 0) i = images.length;
i--;
return setImg();
}
function next(){
if(i >= images.length-1) i = -1;
i++;
return setImg();
}
function setImg(){
return slider_img.setAttribute('src', "images/"+images[i]);
}
var btnDwn = document.onmousedown
function idk(){
return slider_img.setAttribute('src', "images/"+images[0]);
}
if(btnDwn == false){
setInterval(idk(),5000)
}
I'll define "inactivity/idleness" to if user stops moving mouse AND stops clicking
I do this by making a function that every time you call it, a timeout is set(and the previous timeout deleted) so that the content INSIDE the timeout ONLY activates AFTER 5 seconds of NOT BEING TRIGGERED
Do note that to be idle, stop using your mouse and do not click the functions for about 5 seconds and see it in action :D
var slider_img = document.querySelector('.slider-img');
var images = ['a.jpg', 'b.jpg', 'c.jpg', 'd.jpg', 'e.jpg'];
var i = 0; var timeout=0;
function prev(){
if(i <= 0) i = images.length;
i--; resetImg();
return setImg();
}
function next(){
if(i >= images.length-1) i = -1;
i++; resetImg();
return setImg();
}
function setImg(){
return slider_img.setAttribute('src', "images/"+images[i]);
}
function resetImg(){
clearTimeout(timeout);
timeout=setTimeout(()=>{slider_img.setAttribute('src', "images/"+images[0]);},5000);
}
//every time you click those buttons, you are 'active', now being active would also count as moving your mouse
document.body.addEventListener('mousemove',resetImg)

Could you explain this simple image slider code line by line?

Are you able explain this simple image slider code line by line?
I'm particularly interested in where the n and no values come from in currentSlide(no) + plusSlides(n).
var slideIndex = 0;
var slides = document.getElementsByClassName("mySlides");
var interval;
var pauseButton = document.getElementById("pause");
showSlides();
playSlideshow();
function showSlides() {
var i;
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
slideIndex++;
if (slideIndex > slides.length) {
slideIndex = 1;
}
slides[slideIndex - 1].style.display = "block";
}
// Manual control
function currentSlide(no) {
var i;
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
slideIndex = no;
slides[no - 1].style.display = "block";
}
function plusSlides(n) {
var newslideIndex = slideIndex + n;
if (newslideIndex < 6 && newslideIndex > 0) {
currentSlide(newslideIndex);
}
}
Edited to add rest of the code.
// Pause
var playing = true;
function pauseSlideshow() {
var pauseButton = document.getElementById("pause");
pauseButton.innerHTML = "▸";
playing = false;
clearInterval(interval);
}
function playSlideshow() {
pauseButton.innerHTML = "⏸";
playing = true;
interval = setInterval(showSlides, 5000);
}
pauseButton.onclick = function () {
if (playing) {
pauseSlideshow();
} else {
playSlideshow();
}
};
As per the comments, I have added additional code.
Yes, can do!
The first function showSlides is called. It first makes every element with the mySlides class invisible (basically hides all your slides). Then it increments the slide index and checks to see if the index is over the total amount of slides so it can start from the beginning again. Finally it shows the slide that the index is referring to.
The currentSlide function sets the active slide to the index provided in the no argument. First it hides all the slides and then sets the new slide index to what no is and then shows that slide.
Finally plusSlides goes forward (or backwards if using a negative number) n slides. The if statement checks if the index is between 1 and 5. If it is the slide that corresponds with the new index is shown.
A few notes
for loops can be written without a variable declaration preceding it like this
for(let x = 0; x < 100; x++){
console.log(x);
}
In your plusSides function, you check for a specific range, but you could base it off of the amount of slides with slides.length like in showSlides. Also, I would recommend making sure that if the index does happen to fall out of this range to set the index to a default value.
if (newslideIndex < slides.length && newslideIndex > 0) {
currentSlide(newslideIndex);
} else {
currentSlide(1);
}
That is all!

Image element becoming null on src change? Slideshow

Working on building a library, trying to put in a fading image slider, it shows the first image, but then when it tries to change I get TypeError: document.querySelector(...) is null. Any help would be great!
export let styl = (function() {
let slideIndex = 0;
return {
simpleSlideShow: function() {
//automatic Slider
let i;
let slides = document.getElementsByClassName("mySlides");
console.log("Image change");
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
slideIndex++;
if (slideIndex > slides.length) {
slideIndex = 1;
}
slides[slideIndex - 1].style.display = "block";
},
slideShowImageSetup: function(timeDelay, id, images) {
//Building HTML with given array of images
let i;
for (i = 0; i < images.length; i++) {
let elem = document.createElement("img");
elem.setAttribute("alt", "image");
elem.setAttribute("src", images[i]);
elem.setAttribute("class", "mySlides");
document.querySelector(id).appendChild(elem);
}
setTimeout(styl.simpleSlideShow, 1);
setInterval(styl.simpleSlideShow, timeDelay);
return 1;
},
fadingSlideShow: function(id, images) {
document.querySelector(id).className += "fadeOut";
setTimeout(function() {
document.querySelector(id).src = images[slideIndex];
document.querySelector(id).className = "";
slideIndex++;
if (slideIndex == images.length) {
slideIndex = 0;
}
setTimeout(styl.fadingSlideShow(id, images), 3000);
}, 1000);
},
};
})();
Where I'm calling the function
let images = [
"https://cdn141.picsart.com/297231911148201.jpg?c256x256",
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSQIfOEjoaYJNDHGmdgRa8EQp50VCicpK0R_0QpZLftE2zzgJky"
];
styl.fadingSlideShow("#slider", images);
<img id="slider"></img>
css that makes the fade effect
#slider {
opacity: 1;
transition: opacity 3s;
}
#slider.fadeOut {
opacity: 0;
}
Your second setTimeout is not sending in the id or images to styl.fadingSlideShow.
setTimeout(function(){styl.fadingSlideShow(id, images)}, 3000);
Also, put the second setTimeout inside the first one.

Multiple javascript image carousels - independent controls and automatic movement

I have attempted to find an answer to my question here on Stack Overflow but have been unsuccessful in finding one.
As part of my JavaScript learning I am trying to create my own carousel slider. The problem is I am trying to allow for X number of sliders on the same page, each with their own automatic timers and controls. This is proving to be an issue when I try to control either one of them. For instance if I manually control one of them, the other one then stops playing as the paused variable is set to true.
I'm pretty sure that my issue is either the scope of the variables or not being more specific with targeting the slider elements (e). I may have been looking at this too long and have somewhat lost perspective on it. I would appreciate any advice with this or even just a nudge in the right direction.
Thanks.
HTML
<div id="slider-1" class="slider-wrap">
<div class="slider ">
<div class="slide-wrap" data-slide="0">
<div class="slider-slide" style="background-image: url(image1.png)">
<div class="slide-text text-background">
Slide 1
</div>
</div>
</div>
<div class="slide-wrap" data-slide="1">
<div class="slider-slide" style="background-image: url(image2.png)">
<div class="slide-text text-background">
Slide 2
</div>
</div>
</div>
<div class="slide-wrap current-slide" data-slide="2">
<div class="slider-slide" style="background-image: url(image3.png)">
<div class="slide-text text-background">
Slide 3
</div>
</div>
</div>
</div>
</div>
Javascript
// Setup variables
let helpers = require('./helpers.js')
let sliders = document.getElementsByClassName('slider-wrap')
let paused = false
//Get all sliders on page and start slider function
for (var i = 0; i < sliders.length; i++) {
let slideIndex = 0
let e = sliders[i]
slider(e, slideIndex)
autoChange(e, slideIndex)
}
// Slider function which adds indicator click listeners
function slider (e, slideIndex) {
let element = e
let interval
let indicators = e.getElementsByClassName('slide-indicator')
for (var i = 0; i < indicators.length; i++) {
indicators[i].addEventListener('click', function (e) {
let slideIndex = Number(e.target.dataset.slide)
paused = true
if (helpers.hasClass(e.target, 'current') === false) {
clearTimeout(interval)
sliderChange(element, slideIndex)
}
})
}
}
// Change slider based on index and update classes
function sliderChange (e, slideIndex) {
let slides = e.getElementsByClassName('slide-wrap')
let indicators = e.getElementsByClassName('slide-indicator')
let num = slides.length - 1
let prev = e.querySelector('.current-slide')
for (var i = 0; i < slides.length; i++) {
slides[i].classList.remove('current-slide')
indicators[i].classList.remove('current')
}
slides[slideIndex].classList.add('current-slide')
indicators[slideIndex].classList.add('current-indicator')
if (paused === false) {
autoChange(e, slideIndex)
}
}
// Automatically change slide
function autoChange (e, slideIndex) {
let slides = e.getElementsByClassName('slide-wrap')
let num = slides.length - 1
if (slideIndex === num) {
slideIndex = 0
} else {
slideIndex++
}
interval = setTimeout(function () {
sliderChange(e, slideIndex)
}, 3000)
}
Having paused as global variable is an issue at least. I would recommend you to create a javascript object for each slider so that each slider would have their own "paused" property.
let sliders = document.getElementsByClassName('slider-wrap')
var sliderObjects = []
for (i = 0; i < sliders.length; i++) {
var slider = {slider: sliders[i], paused: false}
sliderObjects[i] = slider
}
Here some useful reference on JavaScript Objects: https://www.w3schools.com/js/js_objects.asp

Jump to top of page in img gallery?

I asked this question before, and the answers I received didn't work for me.
I have an HTML site with a selection of around 50 pictures. When clicking on one of them, a modal site opens with a slideshow (big one on top, small samples beneath it). I wish to add to the JS code that after selecting one of the small samples the window automatically jumps to the top of the page where the sample is shown in bigger size.
Here's my JS code:
<script>
function openModal() {
document.getElementById('myModal').style.display = "block";
}
function closeModal() {
document.getElementById('myModal').style.display = "none";
}
var slideIndex = 1;
showSlides(slideIndex);
function plusSlides(n) {
showSlides(slideIndex += n);
}
function currentSlide(n) {
showSlides(slideIndex = n);
}
function showSlides(n) {
var i;
var slides = document.getElementsByClassName("mySlides");
var dots = document.getElementsByClassName("demo");
var captionText = document.getElementById("caption");
if (n > slides.length) {slideIndex = 1}
if (n < 1) {slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex-1].style.display = "block";
dots[slideIndex-1].className += " active";
captionText.innerHTML = dots[slideIndex-1].alt;
}
</script>
I already tried to add window.scrollTo(0, 0); to the currentSlide(n) function, and just scroll(0,0), but it didn't work.
Here's where the onclick="currentSlide" is. I got this code from somewhere online.
<div class="column"><img class="demo" src="img/gallery/img55.jpg" onclick="currentSlide(55)" alt="Sample 55"></div>
</div> <!-- end div modal_samples -->
</div> <!-- end div modal content -->
Please let me know if you need me to provide something else.
I am not certain how far along you are with the functionality, but you could use something like: "window.location.hash = null; window.location.hash='(the id attribute value of the large image)';" in an existing or new function.
So, basically:
// Reset from any previous setting
window.location.hash = null;
// Set the new SRC for the IMG element containing the large image (at top of page)
largeImageElement.src = (URL to Image OR same as thumbnail image SRC);
// Move to where the large image (IMG) resides on page
window.location.hash = largeImageElement.id;
Let me know if you don't understand.

Categories

Resources