I'm trying to create a horizontal slider which can be dragged left / right and it will update its transform translate position accordingly. I want to try and approach this in pure javascript, so no external libraries please.
What I have so far works on initial load and will drag to its position, but then it won't update again to continue.
var object = document.querySelector('.js-slider-container'),
initX, firstX;
object.addEventListener('mousedown', function(e) {
e.preventDefault();
initX = this.style.transform;
firstX = e.pageX;
this.addEventListener('mousemove', dragIt, false);
console.log(initX);
window.addEventListener('mouseup', function() {
object.removeEventListener('mousemove', dragIt, false);
}, false);
}, false);
object.addEventListener('touchstart', function(e) {
e.preventDefault();
initX = this.style.transform;
var touch = e.touches;
firstX = touch[0].pageX;
this.addEventListener('touchmove', swipeIt, false);
window.addEventListener('touchend', function(e) {
e.preventDefault();
object.removeEventListener('touchmove', swipeIt, false);
}, false);
}, false);
function dragIt(e) {
this.style.transform = `translate3d(${initX+e.pageX-firstX}px,0,0)`;
}
function swipeIt(e) {
var contact = e.touches;
this.style.transform = `translate3d(${initX+contact[0].pageX-firstX}px,0,0)`;
}
Here is a jsfiddle to show what I mean, it works on initial run - but then wont continue to update its position from that point. I also can't figure out how to cap it's left and right position to avoid over scroll.
Any advice is appreciated, cheers
Initially the value of this.style.transform
will be an empty string ""
and later when you drag it'll get updated to translate3d(-578px, 0px, 0px)
.
You are using this string value directly in your calculations without picking only x
value, thus it's failing.
We can use a RegEx to pick x
value only like below then use it in calculations.
const txMatch = this.style.transform.match(/translate3d\((-?\d+)px,.+\)/);
initX = txMatch ? +(txMatch[1] || 0) : 0;
var object = document.querySelector('.js-slider-container'),
initX, firstX;
object.addEventListener('mousedown', function(e) {
e.preventDefault();
const txMatch = this.style.transform.match(/translate3d\((-?\d+)px,.+\)/);
initX = txMatch ? +(txMatch[1] || 0) : 0;
firstX = e.pageX;
this.addEventListener('mousemove', dragIt, false);
window.addEventListener('mouseup', function() {
object.removeEventListener('mousemove', dragIt, false);
}, false);
}, false);
object.addEventListener('touchstart', function(e) {
e.preventDefault();
const txMatch = this.style.transform.match(/translate3d\((-?\d+)px,.+\)/);
initX = txMatch ? +(txMatch[1] || 0) : 0;
var touch = e.touches;
firstX = touch[0].pageX;
this.addEventListener('touchmove', swipeIt, false);
window.addEventListener('touchend', function(e) {
object.removeEventListener('touchmove', swipeIt, false);
}, false);
}, false);
function dragIt(e) {
const maxMove = this.offsetWidth - this.parentElement.offsetWidth;
const x = initX + e.pageX - firstX;
if (x >= 0 || x <= -maxMove) {
return;
}
this.style.transform = `translate3d(${x}px,0,0)`;
}
function swipeIt(e) {
var contact = e.touches;
this.style.transform = `translate3d(${initX+contact[0].pageX-firstX}px,0,0)`;
}
*,
*:before,
*:after {
-webkit-box-sizing: inherit;
box-sizing: inherit;
}
.container_full-vh {
position: relative;
height: 100vh;
}
section {
padding: 400px 0;
}
/* Slider */
.slider {
position: absolute;
top: 0;
left: 0;
bottom: 0;
z-index: 9;
will-change: transform;
display: flex;
align-items: center;
width: 100%;
height: 100vh;
overflow-x: hidden;
}
.slider-container {
position: relative;
left: 10px;
display: grid;
align-items: center;
grid-template-columns: repeat(7, 33.3333vw);
grid-column-gap: 4.167vw;
padding: 0 8.33333vw;
height: unset;
cursor: grab;
}
.slider-item {
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
will-change: transform;
position: relative;
overflow: hidden;
opacity: 1;
visibility: inherit;
}
.slider-item_img-wrap {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
overflow: hidden;
opacity: 1;
visibility: inherit;
}
.slider-item:before,
.slider-item_img-wrap:before {
content: "";
display: block;
padding-bottom: calc(100%/0.8);
}
.slider-item_img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
max-width: unset;
pointer-events: none;
user-select: none;
transform-origin: left center;
transform: scale(1.75);
will-change: transform;
}
.slider-item_content {
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
z-index: 1;
user-select: none;
}
.slider-item_content-heading {
display: flex;
overflow: hidden;
}
.slider-item_content-heading h3 {
pointer-events: none;
font-size: 7.569vw;
line-height: 6.944vw;
color: white;
text-transform: uppercase;
transform-origin: left bottom;
will-change: transform;
}
<div class="container_full-vh">
<section>
<div class="js-slider slider">
<div class="js-slider-container slider-container">
<div class="slider-item">
<div class="slider-item_img-wrap">
<img src="https://images.unsplash.com/photo-1479839672679-a46483c0e7c8?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80&ar=0.8" class="slider-item_img">
</div>
<div class="slider-item_content">
<div class="slider-item_content-heading">
<h3>Indigo</h3>
</div>
</div>
</div>
<div class="slider-item">
<div class="slider-item_img-wrap">
<img src="https://images.unsplash.com/photo-1566688342604-dbe3e7357104?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80&ar=0.8" class="slider-item_img">
</div>
<div class="slider-item_content">
<div class="slider-item_content-heading">
<h3>Rouge</h3>
</div>
</div>
</div>
<div class="slider-item">
<div class="slider-item_img-wrap">
<img src="https://images.unsplash.com/photo-1472835560847-37d024ebacdc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80&ar=0.8" class="slider-item_img">
</div>
<div class="slider-item_content">
<div class="slider-item_content-heading">
<h3>Juane</h3>
</div>
</div>
</div>
<div class="slider-item">
<div class="slider-item_img-wrap">
<img src="https://images.unsplash.com/photo-1541320823636-40247af897bf?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80&ar=0.8" class="slider-item_img">
</div>
<div class="slider-item_content">
<div class="slider-item_content-heading">
<h3>Orange</h3>
</div>
</div>
</div>
<div class="slider-item">
<div class="slider-item_img-wrap">
<img src="https://images.unsplash.com/photo-1566787020216-3e4f973ec5ec?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80&ar=0.8" class="slider-item_img">
</div>
<div class="slider-item_content">
<div class="slider-item_content-heading">
<h3>Vert</h3>
</div>
</div>
</div>
</div>
</div>
</section>
</div>