Skip to content

Instantly share code, notes, and snippets.

@Shtille
Created July 1, 2024 10:20
Show Gist options
  • Save Shtille/e027c5ff4f3874e013c32a22b37fe82c to your computer and use it in GitHub Desktop.
Save Shtille/e027c5ff4f3874e013c32a22b37fe82c to your computer and use it in GitHub Desktop.
Auto scrolling while dragging (JavaScript)
/**
* Drag scroller 0.2.0
* @author Shtille <[email protected]>
* @license MIT
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global.DragAutoScroller = factory());
}(this, (function() { 'use strict';
/**
* A drag scroller.
*
* @class DragAutoScroller (name)
* @param {Object} options The options. Possible options:
* - {Object} context The callback context. Could be null.
* - {Function} matchFn The function to test draggable target.
* The signature is function(HTMLElement). Optional.
* - {Function} scrollFn The function to scroll viewport content.
* The signature is function(dy).
* - {Function} scrollDeltaFn The function to define own scroll delta depending on the draggable position.
* The signature is function(pageY). Optional.
* - {HTMLElement} viewport The viewport element.
* You can either define viewport or scroll delta function.
*/
function DragAutoScroller(options)
{
// Inner variables
var _threshold = 30,
_timer = null,
_enabled = false,
_scrollDelta = 0,
_scrollDefault = true,
_context,
_viewport,
_matchFn,
_scrollFn,
_scrollDeltaFn;
const _onInterval = function() {
if (_scrollFn) {
_scrollFn.call(_context, _scrollDelta);
_scrollDelta = 0;
}
};
const _startTimer = function() {
if (_timer === null) {
_timer = setInterval(_onInterval, 24);
}
};
const _stopTimer = function() {
if (_timer !== null) {
clearInterval(_timer);
_timer = null;
}
};
const _onDragOver = function(e) {
e = e || window.event;
let context = _scrollDefault ? null : _context;
_scrollDelta = _scrollDeltaFn.call(context, e.pageY);
};
const _defaultScrollDeltaFn = function(pageY) {
let rect = _viewport.getBoundingClientRect();
let top = rect.top + _threshold;
if (pageY < top) {
// At top
return pageY - top;
}
let bottom = rect.bottom - _threshold;
if (pageY > bottom) {
// At bottom
return pageY - bottom;
}
return 0;
};
/**
* Initializes with the given options.
*
* @param {Object} options The options
* @private
*/
const init = function(options) {
_context = options.context;
if (options.matchFn !== undefined && typeof options.matchFn == 'function')
_matchFn = options.matchFn;
if (options.scrollFn !== undefined && typeof options.scrollFn == 'function')
_scrollFn = options.scrollFn;
if (options.scrollDeltaFn !== undefined && typeof options.scrollDeltaFn == 'function') {
_scrollDeltaFn = options.scrollDeltaFn;
_scrollDefault = false;
} else {
_scrollDeltaFn = _defaultScrollDeltaFn;
_scrollDefault = true;
}
if (options.viewport !== undefined && options.viewport instanceof HTMLElement)
_viewport = options.viewport;
};
/**
* Destroys the object.
*/
this.destroy = function() {
_stopTimer();
};
/**
* Called on start.
*
* @param {Event} event The event
*/
this.onStart = function(event) {
if (_matchFn === undefined || _matchFn.call(_context, event.target)) {
_enabled = true;
document.addEventListener('dragover', _onDragOver, false);
_startTimer();
}
};
/**
* Called on end.
*
* @param {Event} event The event
*/
this.onEnd = function(event) {
if (_enabled) {
_enabled = false;
document.removeEventListener('dragover', _onDragOver, false);
_stopTimer();
}
};
init(options);
}
return DragAutoScroller;
})));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment