drag autoscroll: add vertical (page) scroll + percentage edge zones (15%, 30-160px); v1.2
This commit is contained in:
@@ -2,11 +2,20 @@
|
|||||||
* TweakDrag -- auto-scroll the board while dragging a card near a screen edge.
|
* 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
|
* 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
|
* (jQuery UI's autoscroll is unreliable, and on touch the bundled Touch Punch shim
|
||||||
* shim suppresses native scrolling while a card is held), so you can only drop onto columns
|
* suppresses native scrolling while a card is held), so you can only drop where already on
|
||||||
* already on screen. This scrolls #board-container while a card drag is active and the
|
* screen. While a card drag is active and the pointer nears an edge, this scrolls toward it
|
||||||
* pointer nears the left/right edge, with a smooth continuous speed that grows toward the
|
* with a smooth continuous speed that grows toward the edge:
|
||||||
* edge -- so you can drag a card to the edge and roll the board to a far column.
|
*
|
||||||
|
* - Horizontal: scrolls #board-container (near its left/right edge).
|
||||||
|
* - Vertical: scrolls the window/page (near the viewport top/bottom). This matters when
|
||||||
|
* the vertical-collapse view is OFF and the whole page scrolls; when collapse is ON the
|
||||||
|
* page is not scrollable so window scrolling no-ops and the per-column scroll stays
|
||||||
|
* native.
|
||||||
|
*
|
||||||
|
* The edge zone is a percentage of each axis (clamped), so it adapts to screen size and
|
||||||
|
* orientation: a narrow phone width gets a small horizontal zone, a tall phone height a
|
||||||
|
* larger vertical one, a wide desktop the reverse -- with no device detection.
|
||||||
*
|
*
|
||||||
* It only acts during an active card drag near an edge, so it is harmless when idle. Works
|
* 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.
|
* on desktop (mouse) and mobile (touch, via Touch Punch). No core changes.
|
||||||
@@ -14,7 +23,9 @@
|
|||||||
(function () {
|
(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var EDGE_ZONE = 50; // px from the board edge where auto-scroll begins
|
var EDGE_ZONE_PCT = 0.15; // edge zone = 15% of the axis length...
|
||||||
|
var EDGE_ZONE_MIN = 30; // ...clamped to at least 30px...
|
||||||
|
var EDGE_ZONE_MAX = 160; // ...and at most 160px.
|
||||||
var MAX_SPEED = 22; // px per animation frame at the very edge
|
var MAX_SPEED = 22; // px per animation frame at the very edge
|
||||||
var EASE = 1; // 1 = linear ramp, 2 = gentle-then-fast
|
var EASE = 1; // 1 = linear ramp, 2 = gentle-then-fast
|
||||||
|
|
||||||
@@ -23,7 +34,6 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var container = null;
|
|
||||||
var dragging = false;
|
var dragging = false;
|
||||||
var rafId = 0;
|
var rafId = 0;
|
||||||
var lastX = 0;
|
var lastX = 0;
|
||||||
@@ -39,9 +49,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Distance is px from the edge; returns 0 at the zone border up to MAX_SPEED at the edge.
|
// Edge zone for an axis of the given length (px), 15% clamped to [30, 160].
|
||||||
function speedFor(distance) {
|
function zoneFor(length) {
|
||||||
var p = (EDGE_ZONE - distance) / EDGE_ZONE;
|
var z = length * EDGE_ZONE_PCT;
|
||||||
|
if (z < EDGE_ZONE_MIN) { z = EDGE_ZONE_MIN; }
|
||||||
|
if (z > EDGE_ZONE_MAX) { z = EDGE_ZONE_MAX; }
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distance is px from the edge; 0 at the zone border up to MAX_SPEED at the edge.
|
||||||
|
function speedFor(distance, zone) {
|
||||||
|
var p = (zone - distance) / zone;
|
||||||
if (p <= 0) {
|
if (p <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -55,42 +73,72 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function step() {
|
function step() {
|
||||||
if (!dragging || !container) {
|
if (!dragging) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var rect = container.getBoundingClientRect();
|
var moved = false;
|
||||||
|
|
||||||
|
// Horizontal: scroll the board container near its left/right edge.
|
||||||
|
var c = document.getElementById("board-container");
|
||||||
|
if (c) {
|
||||||
|
var rect = c.getBoundingClientRect();
|
||||||
|
var zoneH = zoneFor(rect.width);
|
||||||
|
var hspeed = 0;
|
||||||
var dLeft = lastX - rect.left;
|
var dLeft = lastX - rect.left;
|
||||||
var dRight = rect.right - lastX;
|
var dRight = rect.right - lastX;
|
||||||
var speed = 0;
|
|
||||||
|
|
||||||
if (dLeft < EDGE_ZONE) {
|
if (dLeft < zoneH) {
|
||||||
speed = -speedFor(dLeft);
|
hspeed = -speedFor(dLeft, zoneH);
|
||||||
} else if (dRight < EDGE_ZONE) {
|
} else if (dRight < zoneH) {
|
||||||
speed = speedFor(dRight);
|
hspeed = speedFor(dRight, zoneH);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (speed !== 0) {
|
if (hspeed !== 0) {
|
||||||
var before = container.scrollLeft;
|
var beforeX = c.scrollLeft;
|
||||||
container.scrollLeft = before + speed;
|
c.scrollLeft = beforeX + hspeed;
|
||||||
|
if (c.scrollLeft !== beforeX) {
|
||||||
|
moved = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only when the board actually moved: nudge jQuery UI to recompute drop
|
// Vertical: scroll the window near the viewport top/bottom (collapse-off case;
|
||||||
// positions so the placeholder follows onto the newly revealed column.
|
// a natural no-op when the page is not scrollable).
|
||||||
if (container.scrollLeft !== before) {
|
var zoneV = zoneFor(window.innerHeight);
|
||||||
|
var vspeed = 0;
|
||||||
|
var dTop = lastY;
|
||||||
|
var dBottom = window.innerHeight - lastY;
|
||||||
|
|
||||||
|
if (dTop < zoneV) {
|
||||||
|
vspeed = -speedFor(dTop, zoneV);
|
||||||
|
} else if (dBottom < zoneV) {
|
||||||
|
vspeed = speedFor(dBottom, zoneV);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vspeed !== 0) {
|
||||||
|
var beforeY = window.pageYOffset;
|
||||||
|
window.scrollBy(0, vspeed);
|
||||||
|
if (window.pageYOffset !== beforeY) {
|
||||||
|
moved = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the board/page actually moved, nudge jQuery UI to recompute drop positions
|
||||||
|
// so the placeholder follows onto the newly revealed area (either axis).
|
||||||
|
if (moved) {
|
||||||
document.dispatchEvent(new MouseEvent("mousemove", {
|
document.dispatchEvent(new MouseEvent("mousemove", {
|
||||||
clientX: lastX,
|
clientX: lastX,
|
||||||
clientY: lastY,
|
clientY: lastY,
|
||||||
bubbles: true
|
bubbles: true
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
rafId = window.requestAnimationFrame(step);
|
rafId = window.requestAnimationFrame(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
function startLoop() {
|
function startLoop() {
|
||||||
container = document.getElementById("board-container");
|
if (!document.getElementById("board-container")) {
|
||||||
if (!container) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dragging = true;
|
dragging = true;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class Plugin extends Base
|
|||||||
|
|
||||||
public function getPluginVersion()
|
public function getPluginVersion()
|
||||||
{
|
{
|
||||||
return '1.1.0';
|
return '1.2.0';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPluginHomepage()
|
public function getPluginHomepage()
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -10,7 +10,9 @@ A Kanboard plugin that groups board dragging and spacing tweaks, configurable un
|
|||||||
- **Mobile drag handle size** -- enlarge the card drag handle Kanboard shows on mobile so
|
- **Mobile drag handle size** -- enlarge the card drag handle Kanboard shows on mobile so
|
||||||
it is easy to grab with a finger.
|
it is easy to grab with a finger.
|
||||||
- **Drag auto-scroll** -- while dragging a card, the board scrolls when the pointer nears a
|
- **Drag auto-scroll** -- while dragging a card, the board scrolls when the pointer nears a
|
||||||
screen edge, so you can reach a column that is off screen (desktop and mobile).
|
screen edge, so you can reach a column or row that is off screen. Horizontal scrolls the
|
||||||
|
board; vertical scrolls the page (when the vertical-collapse view is off). Works on
|
||||||
|
desktop and mobile.
|
||||||
|
|
||||||
These options were originally part of the ShrinkVertically plugin and moved here so that
|
These options were originally part of the ShrinkVertically plugin and moved here so that
|
||||||
drag/touch behaviour can grow on its own (planned: mobile drag-to-move cards, and a drag
|
drag/touch behaviour can grow on its own (planned: mobile drag-to-move cards, and a drag
|
||||||
@@ -34,10 +36,13 @@ movement threshold so ending a drag does not open the task) without bloating tha
|
|||||||
keeps the handle hidden.
|
keeps the handle hidden.
|
||||||
- **Drag auto-scroll**: a script (`Asset/js/drag-autoscroll.js`) listens for jQuery UI
|
- **Drag auto-scroll**: a script (`Asset/js/drag-autoscroll.js`) listens for jQuery UI
|
||||||
sortable's `sortstart`/`sortstop` (which also fire on touch via Kanboard's bundled Touch
|
sortable's `sortstart`/`sortstop` (which also fire on touch via Kanboard's bundled Touch
|
||||||
Punch) and, while a card drag is active, scrolls `#board-container` when the pointer nears
|
Punch) and, while a card drag is active, scrolls toward whichever edge the pointer nears:
|
||||||
its left/right edge. Speed ramps up smoothly toward the edge. After each scroll step it
|
the board (`#board-container`) horizontally, and the window/page vertically (for the
|
||||||
dispatches a synthetic `mousemove` so jQuery UI moves the drop placeholder onto the newly
|
collapse-off view; a no-op when the page does not scroll). Speed ramps up smoothly toward
|
||||||
revealed column. It only acts during an active drag, so it is idle otherwise.
|
the edge. The edge zone is 15% of each axis, clamped to 30-160px, so it adapts to screen
|
||||||
|
size and orientation. After each scroll step it dispatches a synthetic `mousemove` so
|
||||||
|
jQuery UI moves the drop placeholder onto the newly revealed area. It only acts during an
|
||||||
|
active drag, so it is idle otherwise.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user