Multiple javascript image carousels - independent controls and automatic movement - javascript

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

Related

jQuery infinite slideUp and slideDown without clicking

I have a title that is in the h3 tag. My code works using slideUp but slideDown looks so bad. I want the slideDown animations smooth like in slideUp. Basically, slideDown from the last array to the first array, and then the cycle continues (an infinite). Here is my code: HTML:
<div class="services-slide-up">
<h3 class="services-it-consulting">IT Consulting</h3>
<h3 class="services-web-dev">Web Development</h3>
<h3 class="services-mobile-app-dev">Mobile App Development</h3>
<h3 class="services-ui-ux-design">UI/UX Design</h3>
<h3 class="services-team-dev">Team Development</h3>
<h3 class="services-software-testing">Software Testing</h3>
</div>
jQuery
$(document).ready(function() {
var divs = [$(".services-it-consulting"), $(".services-web-dev"), $(".services-mobile-app-dev"), $(".services-ui-ux-design"), $(".services-team-dev"), $(".services-software-testing")];
var i = 0;
function animateDivs() {
divs[i].slideDown(1000, function() {
divs[i].slideUp(1000, function() {
i++;
if (i >= divs.length) {
i = 0;
}
animateDivs();
});
});
}
animateDivs();
});
loop();
function loop()
{
let divs = [$(".services-it-consulting"), $(".services-web-dev"), $(".services-mobile-app-dev"), $(".services-ui-ux-design"), $(".services-team-dev")];
let counter = 0;
for(let i = 0; i < divs.length; i++) {
setTimeout(function(){ divs[i].slideUp('slow') }, 1000 * counter);
counter++;
}
var down=1;
for(let j = divs.length-1; j > 0; j--) {
setTimeout(function(){
divs[j].slideDown('slow');
down++;
// base case
if (down == divs.length) {
loop();
}
}, 1000 * counter);
counter++;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="services-slide-up">
<h3 class="services-it-consulting">IT Consulting</h3>
<h3 class="services-web-dev">Web Development</h3>
<h3 class="services-mobile-app-dev">Mobile App Development</h3>
<h3 class="services-ui-ux-design">UI/UX Design</h3>
<h3 class="services-team-dev">Team Development</h3>
<h3 class="services-software-testing">Software Testing</h3>
</div>
I have used to setTimeout to slide up and slide own to call function in looping.see in the code
You have semantic issues and I find the nested slide up / down event very confusing. What you can do is to place a setTimeout on each event and multiply it by a counter. This counter should be consistent also for the slideDown event. A solution could look like the following.
However be aware of memory allocation issues since the setTimeout is executed immediately. So this will create 8 timeout functions in total. Not a big deal at this point but can become an issue, so please be aware of that.
let divs = [$(".services-it-consulting"), $(".services-web-dev"), $(".services-mobile-app-dev"), $(".services-ui-ux-design"), $(".services-team-dev")];
let counter = 0;
for(let i = 0; i < divs.length; i++) {
setTimeout(function(){ divs[i].slideUp('slow') }, 1000 * counter);
counter++;
}
for(let j = divs.length-1; j >= 0; j--) {
setTimeout(function(){ divs[j].slideDown('slow') }, 1000 * counter);
counter++;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="services-slide-up">
<h3 class="services-it-consulting">IT Consulting</h3>
<h3 class="services-web-dev">Web Development</h3>
<h3 class="services-mobile-app-dev">Mobile App Development</h3>
<h3 class="services-ui-ux-design">UI/UX Design</h3>
<h3 class="services-team-dev">Team Development</h3>
<h3 class="services-software-testing">Software Testing</h3>
</div>

Overlapped slide still getting clicked

The slide that I turned the opacity to 0 on is still clickable even though I set pointer events to none. Basically I have 2 slides on this slideshow and even if i'm on the first slide when I click on it, it goes to the 2nd slides hyperlink. Image This image shows the code is changing the pointer event and also the opacity correctly but for some reason when I click on the first slide on the website it still sends me to the second slides hyperlink.
//programming slideshow
$(function () {
var slide_index = 1;
displaySlides(slide_index);
function nextSlide() {
displaySlides(slide_index++);
}
function prevslide() {
displaySlides(slide_index--);
}
function displaySlides() {
var i;
var slides = document.getElementsByClassName("programming-slides");
if (slide_index > slides.length) { slide_index = 1 }
if (slide_index < 1) { slide_index = slides.length }
for (i = 0; i < slides.length; i++) {
slides[i].style.opacity = 0;
}
slides[slide_index - 1].style.opacity = 1;
for (var i = 0; i < slides.length; i++) {
// If the slide is not visible, set its pointer-events to none
if (slides[i].style.opacity === '0') {
slides[i].style.pointerEvents = 'none';
} else {
// Otherwise, set its pointer-events to auto
slides[i].style.pointerEvents = 'auto';
}
}
}
var next = document.getElementById('programming-next');
next.addEventListener('click', nextSlide);
var prev = document.getElementById('programming-prev');
prev.addEventListener('click', prevslide);
})
Started to fix it by adding in z index to the code in the slides js and also to some other css elements that fixed the overlapping problem and now all the features are working
for (var i = 0; i < slides.length; i++) {
// If the slide is not visible, set its pointer-events to none
if (slides[i].style.opacity === '0') {
slides[i].style.pointerEvents = 'none';
slides[i].style.zIndex = 0;
} else {
// Otherwise, set its pointer-events to auto
slides[i].style.pointerEvents = 'auto';
slides[i].style.zIndex = 1;
}

Anchor tags in overlay jack-scroll approach

I am trying to implement anchor points to scroll to certain "Views" on my Jack-Scrolling home page. I have used an approach shown on CodePen or below. However, because of this approach any <a name="xyz"></a> tags in my code when referenced by www.domain.com#xyz just show the first "page" of my website. How can I work around this, or produce comparable results with an alternative tagging method?
<div id="projects">
<section id="project-0" class="slide active"> Test 1</section>
<section id="project-1" class="slide active"> testing 2</section>
<section id="project-2" class="slide active"> This is testing 3</section>
</div>
JS:
var delta = 0;
var currentSlideIndex = 0;
var scrollThreshold = 30;
var slides = $(".slide");
var numSlides = slides.length;
function elementScroll (e) {
console.log (Math.abs(delta));
// --- Scrolling up ---
if (e.originalEvent.detail < 0 || e.originalEvent.wheelDelta > 0) {
delta--;
if ( Math.abs(delta) >= scrollThreshold) {
prevSlide();
}
}
// --- Scrolling down ---
else {
delta++;
if (delta >= scrollThreshold) {
nextSlide();
}
}
// Prevent page from scrolling
return false;
}
function showSlide() {
delta = 0; // reset
slides.each(function(i, slide) {
$(slide).toggleClass('active', (i >= currentSlideIndex));
});
}
function prevSlide() {
currentSlideIndex--;
if (currentSlideIndex < 0) {
currentSlideIndex = 0;
}
showSlide();
}
function nextSlide() {
currentSlideIndex++;
if (currentSlideIndex > numSlides) {
currentSlideIndex = numSlides;
}
showSlide();
}
$(window).on({
'DOMMouseScroll mousewheel': elementScroll
});
Thanks very much, just to help you read the code, the approach is to place each of the slides on top of each other and then only show the one that is defined by the scroller index (which is incremented and decremented if the scroll is greater than our scroll threshold). - Possibly something using JQuery? Thanks for your help.

Javascript - Mouse Wheel Go to Class

Every time I use the mouse wheel (you know normal scrolling) I want the JS (jquery or whatever) to scroll to a specific class (or id doesn't matter).
I have multiple divs so code like $('body').scrollTo($nextdiv) is not an option.
I just want to make every wheel cycle to move to a next div with a specific class/id. The same for the reverse scroll. To move one div (with a specific class) up.
I found mouse wheel event and how to move to a specific div but can't manage to make it work together.
Animated scroll would be cool.
Simple question. Can I have class AND id in the same div? ex <div class="a" id="b"> ?
Quick example, this code can be improved. Better to test on jsfiddle. Point mouse over list and scroll.
Note: I didn't use class but if you understand what I did it's easy to use classes.
Note 2: I just change color but logic can be replace with anything you want.
demo
demo 2 (with classes)
var i = 0;
var list = document.getElementById("list"), length = list.children.length;
list.addEventListener("wheel", ColorLi);
function ColorLi(e) {
//reset colors
for(var j = 0; j < length; j++)
list.children[j].style.color = "black";
//calculate index
if(e.wheelDelta > 0)
i++;
else
i--;
//fix index out of range
i = i < 0 ? 0 : i;
i = i > length-1 ? length-1 : i;
//set color
list.children[i].style.color = "red";
}
<ul id="list">
<li style="color: red">A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
You could use the following plugins: jquery.mousewheel and jquery.scrollTo plugin, like:
/*!
* jQuery Mousewheel 3.1.13
*
* Copyright 2015 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})});
// The actual code:
$(document).ready(function () {
var targets = $('.scroll'); // List of elements to scroll to
var index = 0;
var duration = 500;
var canScroll = true;
var cache;
function limit(x, min, max) {
return Math.min(max, Math.max(min, x));
}
$(window).mousewheel(function (ev) {
if (canScroll) {
cache = index;
if (ev.deltaY < 0) {
index = index + 1; // Scrolling down, so increase index
} else {
index = index - 1; // Scrolling up, so decrease index
}
// Make sure the index is between 0 and (targets.length - 1)
index = limit(index, 0, targets.length - 1);
console.log(index);
// Make sure to scroll if and only if the value has changed
if (index !== cache) {
// Scroll to the target element:
$(window).scrollTo(targets.get(index), {
duration: duration,
easing: 'swing'
});
canScroll = false;
setTimeout(function () {
canScroll = true;
}, duration);
}
}
ev.preventDefault();
return false;
});
});
div {
content: ' ';
height: 500px;
background-color: #f2f2f2;
}
div:nth-child(even) {
background-color: #d0d0d0;
}
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="//cdn.jsdelivr.net/jquery.scrollto/2.1.0/jquery.scrollTo.min.js"></script>
<div class="scroll">div1</div>
<div class="scroll">div2</div>
<div class="scroll">div3</div>
<div class="scroll">div4</div>
<div class="scroll">div5</div>
<div class="scroll">div6</div>

Uncaught TypeError: Cannot set property 'src' of undefined

url: http://www.gws-mbca.org
The slide show works in Firefox. It used to work in IE and Chrome. Now I get the following error in both IE and Chrome:
Uncaught TypeError: Cannot set property 'src' of undefined
The script is linked using a <script type="...> in the document head.
The code in the web page is as follows:
<section style="margin: 0 auto; text-align: center;">
<img src="./rPix/rp1.jpg" id="slide" width="900" height="200" alt="slide show images" />
</section>
<body onload="runShow();">
The function runShow is part of slideshow.js - Code is as follows:
/* An automatically rotating slide show using Javascript and the DOM.
This script cobbled together by Paul D.J. Vandenberg */
var j = 1;
var pix = new Array(11);
for (i = 0; i < pix.length; i++) {
pix[i] = "rPix/rp"+j+".jpg";
j++;
}
var index = Math.floor(Math.random() * 11) + 1;
var limit = pix.length - 1;
function runShow() {
if (index > limit) {
index = 0;
}
document.slide.src = pix[index];
setTimeout("runShow()", 10000);
index++;
}
Make sure you call runShow() after the id="slide" element has been added to the DOM.
document.slide is shorthand for document.getElementById("slide"). The latter will return null when no element with that id is defined.
The DOM must be loaded before the document can access any elements. Usually an onload event is used when the script is in the <head>
window.onload = function(){
var j = 1;
var pix = new Array(11);
for (i = 0; i < pix.length; i++) {
pix[i] = "rPix/rp"+j+".jpg";
j++;
}
var index = Math.floor(Math.random() * 11) + 1;
var limit = pix.length - 1;
window.runShow = function() {
if (index > limit) {
index = 0;
}
document.slide.src = pix[index];
setTimeout("runShow()", 10000);
index++;
}
};
"The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images and sub-frames have finished loading." -MDN
Suggested improvements
I thought I would throw this part in because there are few things I think you can improve here as far as your approach and decided to offer some suggestions.
Lets remove body onload="runShow()" from your code and make it just <body> or whatever other class etc you might have on there.
Lets also go in and use an interval instead of a timeout because for longrunning processes they are more accurate.
Also, lets try to remove all strings from the callbacks.
Example:
<html>
<head>
window.onload = function(){
var pix = [];//array to hold image source strings
var limit = 10;//0 based count for images
for( var i = 0; i < limit+1; i++ ){//runs 11 times
pix.push("rPix/rp"+(i+1)+".jpg";//push incrementally adds to pix array
}
var index = limit;//last index for image source in pix array
var slide = document.getElementById("slide");//cache slide image element
function runShow(){
if( index > limit ) index = 0;//cycle images by array length
slide.src = pix[index++];//change slide image using cached element
}
runShow();//run on load
setInterval(runShow,10000);//run every 10 seconds
};
</head>
<body>
<section style="margin: 0 auto; text-align: center;">
<img src="./rPix/rp1.jpg" id="slide" width="900" height="200" alt="slide show images" />
</section>
</body>
</html>
So here's what the code looks like now.
/* An automatically rotating slide show using Javascript and the DOM.
This script cobbled together by Paul D.J. Vandenberg with a nice
assist from stackoverflow */
window.onload = function() {
var j = 1;
var pix = new Array(11);
for (i = 0; i < pix.length; i++) {
pix[i] = "rPix/rp"+j+".jpg";
j++;
}
var index = Math.floor(Math.random() * 11) + 1; // Start at a random slide
var limit = pix.length - 1;
var slide = document.getElementById("slide"); // Cache slide image element
function runShow() {
if (index > limit) {
index = 0;
}
slide.src = pix[index++];
}
setInterval(runShow, 10000); // Interval more reliable than timeOut
runShow();
}

Categories

Resources