Documentation menuDrag and throw
Drag and throw
Draggable elements with velocity, friction, bounds, rubber-banding and snap points.
import { draggable } from "@sweberdev/lagrangian";
const drag = draggable(element, {
axis: "x", // "x", "y" or "both"
bounds: { left: -300, right: 0 },// pixels relative to the start, or an element
rubberband: 0.55, // resistance past the bounds, false for a hard stop
inertia: true, // glide after release
deceleration: 0.998, // speed kept per millisecond (0.99 stops sooner)
snap: { x: [-300, -150, 0] }, // or a function (restingPoint) => snapped
spring: { stiffness: 400, damping: 40 }, // for edges and snapping
onEnd: ({ velocityX }) => console.log(velocityX),
});
drag.x.get(); // the physical values behind the element
drag.destroy();
How the throw works
- While dragging, every pointer position is sampled. The velocity is the slope of a least-squares line through the last 100 ms, which ignores the jitter of single events. If the pointer rested for more than 60 ms before release, the throw has no velocity.
- On release the element glides with friction:
v(t) = v₀·e^(−t/τ). It would come to rest atx₀ + v₀·τ;projectRest()gives you that point. - With snap points, Lagrangian picks the snap point nearest to that resting point and adjusts the friction so the glide ends exactly there. If the throw goes the wrong way, a spring carries it over.
- With bounds, the glide continues until the edge and a spring catches it there with the speed it had. Released past the edge, it springs back.
rubberband(distance, dimension) and rubberClamp() are exported for your own scroll containers.
Touch scrolling keeps working along the other axis: axis: "x" sets touch-action: pan-y.