I'm using a function from W3Schools as a starter point to make a draggable gallery slider (.slider-all-items in my code). Few lines have been removed from the original, to prevent dragging vertically.
I'm trying to achieve something very similar to this jsfiddle example, a draggable slideshow, and:
.item { width: 100vw || 100%})window.resizeAdded 3 slides, each slide is taking 100% of the window (responsive).
<div data-item="slider-full" class="slider-container">
<div class="slider-all-items">
<div class="slider-item slider-item1"></div>
<div class="slider-item slider-item2"></div>
<div class="slider-item slider-item3"></div>
</div>
</div>
Now, I don't need the infinite mode, but the animation that toggles between the slides is a part of the Draggable Slider.
If you tried dragging the slides (the direction doesn't matter) in the jsfiddle example just a few px it won't get the (next or prev) slide and center it, in short the function is prevented.
To animate the left and right .items, I did something like this:
/* If the user is dragging to -1 (no slide), it'll set the slider `left` to *0* */
if (sliderLeft >= 0) {theSlider.style.left = "0px";}
The same for the last .item (slide):
/* If dragging greater than the last one, set to the last with animation */
if (sliderRight <= sliderWidth) {theSlider.style.left = on the last item}
Animation - Transition:
The property transition and it's value 0.5s ease is stored in a class named .shifting.
If any of both (the above conditions) is true, .shifting class will be added to the Slider, it'll transition: 0.5s (as mentioned above). And at the same time, a setTimeout() function, delay 0.5s will be executed, which will add and remove it. (The delay is to balance the time it takes to the transition to finish completely before removing the class). Important to mention that the class .shifting should be removed to keep the drag fast and smooth. In short: It'll have the class only in action (when the mouse is free).
.shifting{
transition: all 0.5s ease;
}
What I'm trying to achieve:
Make the slides draggable (full screen - responsive - without the infinite mode), and:
if the drag is only X(small number)px prevent it (as in jsfiddle - using .shifting with my code).
if more than X(greater than the x before)px, get the asked slide and center it.
EDIT: You have to sign in to see it, sorry didn't notice and couldn't find another example
Using for and forEach loops to get the items but couldn't connect between them and the theSlider.style.left.
Tried The jsfiddle example above with some changes (set to full screen) and it works but the problem is on window.resize it glitches and need to refresh the page the make it works as expected.
Refreshing a specific content in the page and not the page itself (not reloading), by using JavaScript or jQuery didn't work.
When refreshing a content in the page didn't work, I had an idea using the jsfiddle mentioned above changed the width and height to 100% and 100vh, and on window.resize` get the current slide index, remove the slider, and append it again with the stored index, but it may glitch sometimes so decided to stick with my code, and the questions is:
How can I connect between the slides to make the slider works as required?
// get the slider
var theSlider = document.querySelector(".slider-all-items");
// get the items in the slider
var sliderItem = document.querySelectorAll('.slider-item');
// variables saved for later
var sliderWidth;
var sliderRight;
// run the function
dragElement(theSlider);
function dragElement(theSlider) {
var pos1 = 0, pos3 = 0;
theSlider.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos3 = e.clientX;
// set the element's new position:
theSlider.style.left = (theSlider.offsetLeft - pos1) + "px";
}
function closeDragElement() {
// add the class .shifting to the slider for every css change (transition)
theSlider.classList.add("shifting");
// get each item width
sliderWidth = theSlider.getBoundingClientRect().width / sliderItem.length;
// get the right side position of the slider
sliderRight = theSlider.getBoundingClientRect().right;
// get the left side position of the slider
sliderLeft = theSlider.getBoundingClientRect().left;
if(sliderLeft >= 0){
theSlider.style.left = "0px";
}
if(sliderRight <= sliderWidth){
theSlider.style.left = -Math.abs((sliderWidth * sliderItem.length) - sliderWidth) + "px";
}
// delay 0.5s, then remove the class .shifting when finished checking and styling
// .shifting {transition: all 0.5s ease;}
setTimeout(() => {
theSlider.classList.remove("shifting");
}, 500);
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
*, *:before, *:after {
margin: 0;
padding: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.slider-container {
position: relative;
height: 80vh;
overflow-x: scroll;
overflow-y: hidden;
}
.slider-container::-webkit-scrollbar {
display: none !important;
}
.slider-all-items {
position: absolute;
display: inline-flex;
}
.slider-item {
width: calc(100vw - 0px);
height: 80vh;
cursor: grab;
display: block;
}
.slider-item1 {
background: red;
}
.slider-item2 {
background-color: blue;
}
.slider-item3 {
background-color: yellow;
}
.shifting{
transition: all 0.5s ease;
}
<div data-item="slider-full" class="slider-container">
<div class="slider-all-items">
<div class="slider-item slider-item1"></div>
<div class="slider-item slider-item2"></div>
<div class="slider-item slider-item3"></div>
</div>
</div>
I am not sure if i understand everything correctly, but maybe it helps you. Here is my code example for a full screen slider with your wished "shifting" class.
const slider = document.querySelector('.slider-container')
const items = document.querySelectorAll('.slider-item')
// active item index
let selectedIndex = 0
// move item positions depend on selected index
const applyItemPositions = () => {
items.forEach((item, index) => {
// add shifting class
item.classList.add('shifting')
item.style.left = `${ (index - selectedIndex) * 100 }%`
})
// remove shifting class after 500ms
setTimeout(() => {
items.forEach((item, index) => {
item.classList.remove('shifting')
})
}, 500)
}
// initial positions
applyItemPositions()
// helpers
const decreaseSelectedIndex = () => {
if (selectedIndex > 0) {
selectedIndex -= 1
applyItemPositions()
}
}
const increaseSelectedIndex = () => {
if (selectedIndex < items.length - 1) {
selectedIndex += 1
applyItemPositions()
}
}
// swipe events
startPos = [0, 0]
// swipestart
slider.addEventListener('pointerdown', (e) => {
startPos = [e.clientX, e.clientY]
})
// swipeend
slider.addEventListener('pointerup', (e) => {
const endPos = [e.clientX, e.clientY]
// threshold (min 20px swipe distance)
if (Math.abs(endPos[0] - startPos[0]) < 20) {
return
}
if (endPos[0] < startPos[0]) {
increaseSelectedIndex()
}
if (endPos[0] > startPos[0]) {
decreaseSelectedIndex()
}
})
html, body {
width: 100vw;
height: 100vh;
margin: 0;
padding: 0;
}
.slider-container {
position: relative;
width: 100%;
height: 100%;
background: #eee;
overflow: hidden;
}
.slider-item {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.slider-item1 {
background: red;
}
.slider-item2 {
background: blue;
}
.slider-item3 {
background: yellow;
}
.shifting{
transition: all 0.5s ease;
}
<div data-item="slider-full" class="slider-container">
<div class="slider-item slider-item1"></div>
<div class="slider-item slider-item2"></div>
<div class="slider-item slider-item3"></div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With