1 year ago

#367340

test-img

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.

enter image description here

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

Accepted video resources