auto-scroll on drag

This commit is contained in:
2026-07-01 10:45:07 -03:00
parent 924e287aee
commit bb3ac1c946

119
Asset/js/drag-autoscroll.js Normal file
View File

@@ -0,0 +1,119 @@
/*
* TweakDrag -- auto-scroll the board while dragging a card near a screen edge.
*
* Kanboard drags cards with jQuery UI sortable. The board does not scroll during a drag
* (jQuery UI's autoscroll is unreliable horizontally, and on touch the bundled Touch Punch
* shim suppresses native scrolling while a card is held), so you can only drop onto columns
* already on screen. This scrolls #board-container while a card drag is active and the
* pointer nears the left/right edge, with a smooth continuous speed that grows toward the
* edge -- so you can drag a card to the edge and roll the board to a far column.
*
* It only acts during an active card drag near an edge, so it is harmless when idle. Works
* on desktop (mouse) and mobile (touch, via Touch Punch). No core changes.
*/
(function () {
"use strict";
var EDGE_ZONE = 50; // px from the board edge where auto-scroll begins
var MAX_SPEED = 22; // px per animation frame at the very edge
var EASE = 1; // 1 = linear ramp, 2 = gentle-then-fast
var jq = window.jQuery;
if (!jq) {
return;
}
var container = null;
var dragging = false;
var rafId = 0;
var lastX = 0;
var lastY = 0;
function onMove(e) {
if (e.touches && e.touches.length) {
lastX = e.touches[0].clientX;
lastY = e.touches[0].clientY;
} else {
lastX = e.clientX;
lastY = e.clientY;
}
}
// Distance is px from the edge; returns 0 at the zone border up to MAX_SPEED at the edge.
function speedFor(distance) {
var p = (EDGE_ZONE - distance) / EDGE_ZONE;
if (p <= 0) {
return 0;
}
if (p > 1) {
p = 1;
}
if (EASE !== 1) {
p = Math.pow(p, EASE);
}
return MAX_SPEED * p;
}
function step() {
if (!dragging || !container) {
return;
}
var rect = container.getBoundingClientRect();
var dLeft = lastX - rect.left;
var dRight = rect.right - lastX;
var speed = 0;
if (dLeft < EDGE_ZONE) {
speed = -speedFor(dLeft);
} else if (dRight < EDGE_ZONE) {
speed = speedFor(dRight);
}
if (speed !== 0) {
var before = container.scrollLeft;
container.scrollLeft = before + speed;
// Only when the board actually moved: nudge jQuery UI to recompute drop
// positions so the placeholder follows onto the newly revealed column.
if (container.scrollLeft !== before) {
document.dispatchEvent(new MouseEvent("mousemove", {
clientX: lastX,
clientY: lastY,
bubbles: true
}));
}
}
rafId = window.requestAnimationFrame(step);
}
function startLoop() {
container = document.getElementById("board-container");
if (!container) {
return;
}
dragging = true;
if (!rafId) {
rafId = window.requestAnimationFrame(step);
}
}
function stopLoop() {
dragging = false;
if (rafId) {
window.cancelAnimationFrame(rafId);
rafId = 0;
}
}
// Track the pointer at all times (cheap; only used while dragging).
document.addEventListener("mousemove", onMove, true);
document.addEventListener("touchmove", onMove, true);
document.addEventListener("pointermove", onMove, true);
// A card drag started / stopped. jQuery UI sortable fires these (on touch too, via
// Touch Punch); delegated on the document so board redraws need no rebinding.
jq(document).on("sortstart", startLoop);
jq(document).on("sortstop", stopLoop);
})();