'How to directly change TranslateX from one position to another smoothly?
I am facing this issue from a long time, Finally I managed to make a demo example of my problem. I am trying to make a infinite image scroll view. So when we point our mouse down and try to scroll to the right position, after change
is more than 40%, I want to transform directly from translateX to the last item transform value (-400px), but I am having a transition: 400ms ease
on the container so whenever I try to change TranslateX value from 0 to -400 when mouse is moving towards the right side (back from the 1st image), it gives a full transition effect of travelling from 0 to -400, and to solve this issue, I try to remove the transition after the change
hits 40% and then change the translateX value, it works, but its giving a sudden stop effect when I remove the transition and update the translateX value. I want it to be smooth and transition and smoothly change translateX value directly without travelling.
Please anyone help me, I am facing this issue from a long time, :- https://jsfiddle.net/4nj6cszk/2/
const modal_images_main_inner = document.querySelector('.modal-images-main-inner');
const modal_main_image_wrapper = document.querySelector('.modal-main-image-wrapper');
const modal_main_carousel = document.getElementById('modal-main-carousel');
const modal_slide_images = document.querySelectorAll('.modal-show-image');
//const verttest = document.getElementById('verttest');
const modalconfig = {
modalindividualItem: '.modal-show-image', // class of individual item
modalcarouselWidth: modal_images_main_inner.offsetWidth, // in px
modalcarouselId: '#modal-images-main-inner-container', // carousel selector
modalcarouselHolderId: '#modal-main-carousel', // carousel should be <div id="carouselId"><div id="carouselHolderId">{items}</div></div>
}
let modal_mousedown = false;
let modal_movement = false;
let modal_initialPosition = 0;
let modal_selectedItem;
let modal_currentDelta = 0;
let modalupchange;
let elementIndex;
let modalupDelta;
document.querySelectorAll(modalconfig.modalcarouselId).forEach(function(item) {
item.addEventListener('pointerdown', function(e) {
const modal_images_parent = e.target.closest('.modal-main-image-wrapper').parentElement;
const imagesIndex = modal_images_parent.parentElement.dataset.index;
elementIndex = imagesIndex;
modal_mousedown = true;
modal_selectedItem = item;
modal_initialPosition = e.pageX;
modal_currentDelta = parseFloat(item.querySelector(modalconfig.modalcarouselHolderId).style.transform.split('translateX(')[1]) || 0;
modalupDelta = modal_currentDelta;
});
});
const modalscrollCarousel = function(change, currentDelta, selectedItem) {
let newDelta = currentDelta + change;
const diff = newDelta - (currentDelta);
const diffpercent = (diff / modalconfig.modalcarouselWidth) * 100;
const newdiffpercent = currentDelta + diffpercent;
if(newdiffpercent <= 0) {
if(newdiffpercent > 0) {
const lastItemLeftValue = parseFloat(modal_slide_images[modal_slide_images.length - 1].style.left);
if(lastItemLeftValue <= -100) {
modal_slide_images[modal_slide_images.length - 1].style.left = `${parseInt(modal_slide_images[modal_slide_images.length - 1].dataset.index) * 100}%`;
}
}
if(selectedItem.querySelector(modalconfig.modalcarouselHolderId).classList.contains('modal-no-transition')) {
selectedItem.querySelector(modalconfig.modalcarouselHolderId).classList.remove('modal-no-transition');
}
selectedItem.querySelector(modalconfig.modalcarouselHolderId).style.transform = `translateX(${newdiffpercent}%)`;
} else {
if(newdiffpercent >= 0) {
if(elementIndex == 0) {
const fupTransform = parseFloat(modal_slide_images[2].style.left);
selectedItem.querySelector(modalconfig.modalcarouselHolderId).style.transform = `translateX(${newdiffpercent}%)`;
modal_slide_images[modal_slide_images.length - 1].style.left = `-100%`;
if(newdiffpercent >= 40) {
const lastItemValue = modal_slide_images[modal_slide_images.length - 1].dataset.index;
modal_slide_images[modal_slide_images.length - 1].style.left = `${parseInt(modal_slide_images[modal_slide_images.length - 1].dataset.index) * 100}%`;
modal_slide_images[0].style.left = `${(parseInt(modal_slide_images[modal_slide_images.length - 1].dataset.index) + 1) * 100}%`;
selectedItem.querySelector(modalconfig.modalcarouselHolderId).classList.add('modal-no-transition');
selectedItem.querySelector(modalconfig.modalcarouselHolderId).style.transform = `translateX(${-(lastItemValue * 100) - (100 - newdiffpercent)}%)`;
window.requestAnimationFrame(_ => { selectedItem.querySelector(modalconfig.modalcarouselHolderId).classList.remove("transition-no"); });
const loopLastTransform = parseFloat(modal_main_carousel.style.transform.split('translateX(')[1]);
}
else {
selectedItem.querySelector(modalconfig.modalcarouselHolderId).style.transform = `translateX(${newdiffpercent}%)`;
}
}
}
}
}
document.body.addEventListener('pointermove', function(e) {
if(modal_mousedown == true && typeof modal_selectedItem !== "undefined") {
let change = -(modal_initialPosition - e.pageX);
modalupchange = change;
modalscrollCarousel(change, modal_currentDelta, document.body);
document.querySelectorAll(`${modalconfig.modalcarouselId} img`).forEach(function(item) {
item.style.pointerEvents = 'none';
});
modal_movement = true;
}
});
['pointerup', 'mouseleave'].forEach(function(item) {
document.body.addEventListener(item, function(e) {
modal_selectedItem = undefined;
modal_movement = false;
document.querySelectorAll(`${modalconfig.modalcarouselId} img`).forEach(function(item) {
item.style.pointerEvents = 'all';
});
});
});
.modal-images-main {
position: relative;
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
}
.modal-images-main-inner {
position: relative;
overflow: hidden;
}
.modal-images-main-effect {
border-radius: 24px;
}
.modal-show-image {
width: 100%;
overflow: hidden;
position: absolute;
}
.modal-main-image-wrap {
max-width: 100%;
width: 100%;
margin: 0 auto;
}
.modal-main-image-wrapper {
height: 0;
padding-bottom: 100.0%;
overflow: hidden;
background: #f1f1f1;
}
.modal-no-transition {
transition: none !important;
}
.modal-images-main-carousel {
width: 100%;
height: 100%;
position: absolute;
transition: transform 400ms ease-out 0s;
}
<div class="modal-images-main">
<div id="modal-images-main-inner-container" class="modal-images-main-inner modal-images-main-effect" style="height: 440px; touch-action: pan-y;">
<div style="left: 0px; transform: translateX(0%);" id="modal-main-carousel" class="modal-images-main-carousel">
<div style="position: absolute; left: 0%;" data-index="0" class="modal-show-image">
<div style="position: relative;">
<div class="modal-main-image-wrapper">
<img class="modal-main-image-wrap" data-sizes="auto" src="https://www.w3schools.com/howto/img_lights.jpg" style="pointer-events: none;">
</div>
</div>
</div>
<div style="position: absolute; left: 100%;" data-index="1" class="modal-show-image">
<div style="position: relative;">
<div class="modal-main-image-wrapper">
<img class="modal-main-image-wrap" data-sizes="auto" src="https://www.w3schools.com/html/pic_trulli.jpg" style="pointer-events: none;">
</div>
</div>
</div>
<div style="position: absolute; left: 200%;" data-index="2" class="modal-show-image">
<div style="position: relative;">
<div class="modal-main-image-wrapper">
<img class="modal-main-image-wrap" data-sizes="auto" src="https://www.w3schools.com/html/img_chania.jpg" style="pointer-events: none;">
</div>
</div>
</div>
<div style="position: absolute; left: 300%;" data-index="3" class="modal-show-image">
<div style="position: relative;">
<div class="modal-main-image-wrapper">
<img class="modal-main-image-wrap" data-sizes="auto" src="https://www.w3schools.com/howto/img_snow.jpg
" style="pointer-events: none;">
</div>
</div>
</div>
<div style="position: absolute; left: 400%;" data-index="4" class="modal-show-image">
<div style="position: relative;">
<div class="modal-main-image-wrapper">
<img class="modal-main-image-wrap" data-sizes="auto" src="https://www.w3schools.com/howto/img_mountains.jpg" style="pointer-events: none;">
</div>
</div>
</div>
</div>
</div>
</div>
Solution 1:[1]
I see, you want to teleport left when they go too far right seamlessly scrolling forever.
console.log(newdiffpercent)
to see if you ever enter the if block,
Rather than adding a class with a transition:none
style,
do .style.transition = "none";
have that be the first thing you do in the if block.
I see .classList.remove("transition-no");
but if you search (ctrl-f
) you see this isn't used.
Did you mean .modal-no-transition
?
which would be .style.transition = "400 ms ease-in-out";
?
Solution 2:[2]
I think the way to change the smoothness of the transition is to use a cubic bezier curve for the animation timing function.
The animation in css:
.modal-images-main-carousel {
width: 100%;
height: 100%;
position: absolute;
transition: transform 400ms;
animation-timing-function: cubic-bezier(0,.89,.32,1)
}
Note that there will always be an initial point of acceleration in an ease out function and the way to keep on smoothing out the animation is by increasing the duration.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | bguiz |
Solution 2 | Steve |