I have tried using kinetic.js and the code below, however when I try this in IE11 it keeps jumping to the top every time I scroll:
$(\"html\").kinetic();
You can do this quite simply by recording the position of the mouse when clicked, and the current position when being dragged. Try this:
var clicked = false, clickY;
$(document).on({
'mousemove': function(e) {
clicked && updateScrollPos(e);
},
'mousedown': function(e) {
clicked = true;
clickY = e.pageY;
},
'mouseup': function() {
clicked = false;
$('html').css('cursor', 'auto');
}
});
var updateScrollPos = function(e) {
$('html').css('cursor', 'row-resize');
$(window).scrollTop($(window).scrollTop() + (clickY - e.pageY));
}
To prevent text selection while dragging, add the following CSS:
body {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
Example fiddle
Update
Here's an version of the above as a jQuery plugin, extended to allow both vertical and horizontal scrolling via the settings. It also allows you to change the cursor
that's used too.
(function($) {
$.dragScroll = function(options) {
var settings = $.extend({
scrollVertical: true,
scrollHorizontal: true,
cursor: null
}, options);
var clicked = false,
clickY, clickX;
var getCursor = function() {
if (settings.cursor) return settings.cursor;
if (settings.scrollVertical && settings.scrollHorizontal) return 'move';
if (settings.scrollVertical) return 'row-resize';
if (settings.scrollHorizontal) return 'col-resize';
}
var updateScrollPos = function(e, el) {
$('html').css('cursor', getCursor());
var $el = $(el);
settings.scrollVertical && $el.scrollTop($el.scrollTop() + (clickY - e.pageY));
settings.scrollHorizontal && $el.scrollLeft($el.scrollLeft() + (clickX - e.pageX));
}
$(document).on({
'mousemove': function(e) {
clicked && updateScrollPos(e, this);
},
'mousedown': function(e) {
clicked = true;
clickY = e.pageY;
clickX = e.pageX;
},
'mouseup': function() {
clicked = false;
$('html').css('cursor', 'auto');
}
});
}
}(jQuery))
$.dragScroll();
/* Note: CSS is not relevant to the solution.
This is only needed for this demonstration */
body,
html {
padding: 0;
margin: 0;
}
div {
height: 1000px;
width: 2000px;
border-bottom: 3px dashed #EEE;
/* gradient is only to make the scroll movement more obvious */
background: rgba(201, 2, 2, 1);
background: -moz-linear-gradient(-125deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
background: -webkit-gradient(left top, right bottom, color-stop(0%, rgba(201, 2, 2, 1)), color-stop(16%, rgba(204, 0, 204, 1)), color-stop(31%, rgba(94, 0, 201, 1)), color-stop(43%, rgba(0, 153, 199, 1)), color-stop(56%, rgba(0, 199, 119, 1)), color-stop(69%, rgba(136, 199, 0, 1)), color-stop(83%, rgba(199, 133, 0, 1)), color-stop(100%, rgba(107, 0, 0, 1)));
background: -webkit-linear-gradient(-125deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
background: -o-linear-gradient(-125deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
background: -ms-linear-gradient(-125deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
background: linear-gradient(-110deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#c90202', endColorstr='#6b0000', GradientType=1);
color: #EEE;
padding: 20px;
font-size: 2em;
}
body {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>First...</div>
<div>Second...</div>
I modified Rory's code quite a bit, and I got per-element side scrolling to work. I needed that for a project that had multiple scrollable tiles in a single view for a webapp. Add the .drag
class to any element, possibly do a bit of styling, and it should be good to go.
// jQuery sidescroll code. Can easily be modified for vertical scrolling as well.
// This code was hacked together so clean it up if you use it in prod.
// Written by Josh Moore
// Thanks to Rory McCrossan for a good starting point
// How far away the mouse should move on a drag before interrupting click
// events (your own code must also interrupt regular click events with a
// method that calls getAllowClick())
const THRESHOLD = 32;
var clicked = false;
var allowClick = true;
// mouseX: most recent mouse position. updates when mouse moves.
// el: jQuery element that will be scrolled.
// thX: "threshold X", where the mouse was at the beginning of the drag
var mouseX, startY, el, thX;
// Add the .drag class to any element that should be scrollable.
// You may need to also add these CSS rules:
// overflow: hidden; /* can be replaced with overflow-x or overflow-y */
// whitespace: none;
function drag() {
$('.drag').on({
'mousemove': e => {
if (el != null && clicked) {
el.scrollLeft(el.scrollLeft() + (mouseX - e.pageX));
mouseX = e.pageX;
allowClick = Math.abs(thX - mouseX) > THRESHOLD ? false : true;
}
},
'mousedown': e => {
clicked = true;
// This lets the user click child elements of the scrollable.
// Without it, you must click the .drag element directly to be able to scroll.
el = $(e.target).closest('.drag');
mouseX = e.pageX;
thX = e.pageX;
},
'mouseup': e => {
clicked = false;
el = null;
allowClick = true;
}
});
}
function getAllowClick() {
return allowClick;
}
Again, I had no use for vertical scrolling but it would be pretty simple to add (replace X's with Y's, scrollTop()
instead of scrollLeft()
, etc). Hope this helps someone in the future!
Based on the first answer, this is the code for horizontal scroll on mouse drag:
var clicked = false, clickX;
$(document).on({
'mousemove': function(e) {
clicked && updateScrollPos(e);
},
'mousedown': function(e) {
e.preventDefault();
clicked = true;
clickX = e.pageX;
},
'mouseup': function() {
clicked = false;
$('html').css('cursor', 'auto');
}
});
var updateScrollPos = function(e) {
$('html').css('cursor', 'grabbing');
$(window).scrollLeft($(window).scrollLeft() + (clickX - e.pageX));
}
I just like to add. Using Rory's code I made horizontal scrolling.
var clicked = false, base = 0;
$('#someDiv').on({
mousemove: function(e) {
clicked && function(xAxis) {
var _this = $(this);
if(base > xAxis) {
base = xAxis;
_this.css('margin-left', '-=1px');
}
if(base < xAxis) {
base = xAxis;
_this.css('margin-left', '+=1px');
}
}.call($(this), e.pageX);
},
mousedown: function(e) {
clicked = true;
base = e.pageX;
},
mouseup: function(e) {
clicked = false;
base = 0;
}
});
This code will work on horizontal and vertical mouse drag scroll. It's pretty simple.
var curYPos = 0,
curXPos = 0,
curDown = false;
window.addEventListener('mousemove', function(e){
if(curDown === true){
window.scrollTo(document.body.scrollLeft + (curXPos - e.pageX), document.body.scrollTop + (curYPos - e.pageY));
}
});
window.addEventListener('mousedown', function(e){ curDown = true; curYPos = e.pageY; curXPos = e.pageX; });
window.addEventListener('mouseup', function(e){ curDown = false; });
This framework is written in vanilla javascript, and worked best for me.
It also supports scroller inside divs.
Note: If you create dynamic content, call dragscroll.reset();
after render.
dragscroll
Usage
demo