1 year ago
#367340
Stepan J.
Draggable element with resistance effect
I would like to achieve a smooth resistance effect once a draggable element overflows its parent or any other area that it is confined to.
I came up with many different solutions (without using a high-level library). So far, I have one simple solution that has been working pretty well, however it comes with a strange lag.
I have been killing my brains cells over this.
I am using a bunch of low-level libraries. I am pretty confident that they are not causing the issue.
Please see the Codepen for a full working demo: https://codepen.io/stepj/pen/JjMOyLx
HTML:
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/mezr/mezr.js"></script>
<script src="https://biodiv.github.io/contactjs/assets/js/contact.min.js"></script>
<script src="https://unpkg.com/everpolate/everpolate.browserified.min.js"></script>
<div class="fixed inset-0 flex flex-col items-center justify-end">
<span class="pb-2 text-sm font-bold text-blue-600 select-none">Swipe up</span>
<div id="wrapper" class="py-8 bg-blue-400 rounded-lg">
<div id="sheet" class="flex flex-col justify-center items-center gap-y-4 text-center w-64 bg-blue-800 rounded-xl p-4">
<div id="handle" class="w-full h-4 bg-orange-400 cursor-move rounded-full"></div>
<div class="text-white text-sm">
<p class="font-medium">Overflow maximum (px): <span class="font-bold" id="overflowMax">0</span></p>
<p class="font-medium">Overflow (px): <span class="font-bold" id="overflow">0</span></p>
<div class="text-white text-sm">
<p class="font-medium">Overflow resistance (%): <span class="font-bold" id="resistance">0</span></p>
</div>
</div>
<div>
<div>
JS:
let wrapper = document.querySelector("#wrapper");
let sheet = document.querySelector("#sheet");
let handle = document.querySelector("#handle");
let overflowInfo = document.querySelector("#overflow");
let overflowMaxInfo = document.querySelector("#overflowMax");
let resistanceInfo = document.querySelector("#resistance");
let options = {
supportedGestures: [Pan]
};
let pointerListener = new PointerListener(handle, options);
let originY = 0;
let previousDeltaY = 0;
let y;
let currentEvent;
handle.addEventListener("panstart", function (event) {
console.log(event.type, event);
});
handle.addEventListener("pan", function (event) {
currentEvent = event;
animate();
});
handle.addEventListener("panend", function (event) {
console.log(event.type, event);
originY = y || 0;
});
const animate = () => {
let sheetHeight = sheet.getBoundingClientRect().height;
overflowMaxInfo.innerText = sheetHeight;
let sheetWrapperOverflowTop = mezr.overflow(wrapper, sheet).top;
let sheetWrapperOverflowTopInterpolation = everpolate.linear(
sheetWrapperOverflowTop,
[0, sheetHeight],
[1, 0]
)[0];
let currentDeltaY = currentEvent.detail.global.deltaY;
y = originY + currentDeltaY;
if (
sheetWrapperOverflowTopInterpolation <= 1 &&
sheetWrapperOverflowTopInterpolation >= 0
) {
console.log(
"sheetWrapperOverflowTopInterpolation:",
sheetWrapperOverflowTopInterpolation
);
resistanceInfo.innerText = ((1 - sheetWrapperOverflowTopInterpolation) * 100).toFixed(2);
let sheetOutside = 1 - sheetWrapperOverflowTopInterpolation;
y = y * sheetOutside * sheetWrapperOverflowTopInterpolation + y * sheetWrapperOverflowTopInterpolation;
sheet.style.transform = `translate3d(0px, ${Math.round(y)}px, 0px)`;
} else {
sheet.style.transform = `translate3d(0px, ${Math.round(y)}px, 0px)`;
}
overflowInfo.innerText = sheetWrapperOverflowTop;
};
If someone had an idea how to fix this up, it would be hugely appreciated.
javascript
animation
interpolation
draggable
pan
0 Answers
Your Answer