Disabling scrolling while dragging on mobile - javascript

I am trying to create a list of items that can be re-sorted. I have set it up on mobile where the item is to begin being moved after a long-hold, followed by a drag to re-position it.
It works fine when only a few items are present, but once enough appear to allow the div to scroll (only the div containing the ul scrolls, not the whole page), I can no longer re-position items as dragging causes a scroll.
I have tried using .preventDefault() on touchmove, but it does not appear to have an effect.
Basically, I have this:
$(document).on('touchmove mousemove', e => {
// check to make sure we're holding something
// if not, just return
e.preventDefault()
// this stops the text from being highlighted,
// but does not stop scrolling
// report the mouse/touch position to the actual move function.
})
Most solutions say that using preventDefault() stops it, but that does not appear to be the case.
What can I do here?
Edit: I have tried manipulating the overflow property, but that prevents the div from being programmatically scrolled as well, which it needs to do.

try to prevent scroll:
$('div').on('scroll', function(e) {e.preventDefault()});

Related

How to ensure the mousewheel/wheel event fires only once per scroll inside scrollable div

I'm using pagePiling.js to create a one page scroll effect. Within one of the pagepiling sections, I have a child div that is scrollable. When the user gets to the section with the scrollable div inside it, I'd like them to be able to scroll to the top of each paragraph within the scrollable div every time they scroll downwards via the mousewheel.
The issue here is that the mousewheel/wheel event fires 2 times, 4 times, 12 times, or even 21 times when I move my mousewheel one "tick" (for lack of a better term), but I'd only like it to fire once. Otherwise my functions are firing too often and exhibiting a poor scrolling experience. The number of wheel events starts to jump when I either scroll inside the scrollable container specifically or when I jump back and forth between sections and try to scroll the scrollable container again.
So far I've tried implementing lodash.js and the debounce/throttle methods using addEventListener() in the past but I still receive multiple mouse events after a single wheel tick, similar to what I've described above.
I've created a codepen here to show what I've got so far. My issue begins within the mouseover function, here's what I've been working with so far:
$('.overflow-section').on('wheel', function(e) {
var oEvent = e.originalEvent,
delta = oEvent.deltaY || oEvent.wheelDelta;
if (delta > 0) {
$('#scrollable-container').animate({
scrollTop: $("#section-two").offset().top
});
} else {
$('#scrollable-container').animate({
scrollTop: $("#section-one")
});
}
});
Once I scroll to the bottom section, the console outputs 6 wheel events when I tick the wheel once but it should only fire once.
You can take a look at Letarghy library.
It is an attempt to solve problems with "kinetic scrolling" which is your case.
Note it won't be perfect tho, as there's literally no way to detect a single swipe/scroll in some devices. In that case a delay would be applied.

Prevent scrolling of the background div on scrolling the modal box content

I have a modalbox for for mobile site(ios device), which contains scrollable content inside it. The initial issue was that on scrolling the content inside the modal, even the background page was scrollable. To fix this, I added a 'position: fixed' property to the body tag when the modalbox is opened, and removing it when the modalbox is closed.
Though this fixes the initial scroll issue, it causes the page to scroll to top on adding the "fixed property:" to the body tag and and the page scrolls to the initial position once the modalbox is closed.
Wanted a solution to avoid the page being scrolled to top if fixed property is added to the body.
One way to do this would be monitor touch and wheel events and call preventDefault on them when you know they are going to scroll wrong element. Here's main idea:
element.addEventListener('touchstart', onTouchStart);
element.addEventListener('touchmove', onTouchMove, { passive: false });
element.addEventListener('wheel', onWheel, { passive: false });
onWheel(event) {
// Walk up the DOM tree from target element until the
// topmost element you want to isolate scroll with
// i.e. your modal and check if any of the elements
// can be scrolled in the wheel direction (event.deltaY).
// If there are no such elements, call event.preventDefault().
}
onTouchStart(event) {
// Store initial touch coordinates to determine direction later
}
onTouchMove(event) {
// Using initial touch coordinates determine direction of the move
// and do the similar thing as with the wheel event — call
// event.preventDefault() if you know that resulting scroll will happen
// outside of your modal
}

jQuery.kinetic animated move to position

I'm using jQuery.kinetic to allow a div to be scrolled within its parent div by dragging the mouse, just like the demo on the author's site
I want to add a button, which upon clicking it, moves the jQuery.kinetic activated div to a certain position, however I could not find how to do this. I know the scrollLeft and scrollRight methods can be called to change the position, exactly as I want:
$("container-selector").kinetic("scrollLeft", 50);
$("container-selector").kinetic("scrollTop", 480);
However I wish the change in positions to be animated, not immediate like how the code above does it.
Would anybody know how to smoothly move the draggable div to a specified position upon the clicking of a button, and have this animated? Thanks!
From the demo page HERE
$('#yourButtonIdOrClass').click(function() {
$('.container-selector').kinetic('start', { velocity: -10 }); // code to move your container
});
From the Doc's
Start movement in the scroll container at a particular velocity.
This velocity will not slow until the end method is called.
So you need to call the end() method to stop the div from scrolling either to the end of the right hand side or end of the left hand side, you might want to use the moved event and check how much the container has moved something like the below:
moved : function() {
if() // check moved position {
$('.container-selector').kinetic('end');
}
}
The above code will go inside the initialization of the plugin.
NOTE:: you can use the dev tools to check the event listeners attached to the left or right buttons.

How do I force the mouse cursor to change without a mouse movement in Javascript?

In my webpage, testing on Chrome, I have a button div. The button is styled so that it has a hover state in a different colour, and a hand-shaped mouse pointer. All this is fine.
When the button is pressed, it triggers an animation, and I don't want to let the user press the button again until it's done, so I put a semi-opaque div over the top to block the button.
The problem comes when the animation completes and the div is removed. The mouse pointer is over the button but the hover state isn't active until the user actually moves the mouse, then the mouse pointer changes and all is well.
Note that the click still works - this is a purely cosmetic (but annoying) aberration.
Can I force the browser to re-evaluate the point under the cursor?
The correct way to prevent input to a button is to disable it. You can toggle the cursor style with the CSS cursor property.
Javascript:
var theButton = document.getElementById('theButton');
theButton.disabled = true;
theButton.setAttribute('style','cursor:default;');
// animation is complete
theButton.disabled = false;
theButton.removeAttribute('style');
jQuery:
var $theButton = $('#theButton').prop('disabled',true).css('cursor','default');
// animation is complete
$theButton.prop('disabled',false).css('cursor','pointer');
Check the position of the mouse when the animation ends and you remove the div, or just always store them and check that value when it ends to see if the cursor is still over your button. You could do this with event.clientX, event.clientY or event.pageX, event.pageY something similar to those(not completely sure just did some quick research but those seemed to work in chrome,IE, and firefox). Then if the mouse is still over the button, trigger the on.hover for the button element again.
Try to set the curser of all elements using the * wildcard in jquery. See if this will update the cursor.
It seems like the root of your question was to how to prevent double animating. Instead of placing a <div> over it, you can just do it with JavaScript.
Set a global variable called isAnimating to true when you start your animation. At the top of your click handler add this line if (isAnimating) return false; Obviously, you need to set isAnimating to false as soon as the animation is completed, either through a timer or in some kind of callback function.
This will prevent double animating, without doing anything silly with the DOM that would affect the hover states, or so I'd hope!
Let me know if that's not what you meant and I'll take another look at it!

Event that gets fired before (not after!) DOM elements are scrolled in javascript

Basically, I would like to do some pre-processing before the DOM elements are scrolled. The problem is that the scroll event is fired AFTER the DOM elements are scrolled. I know that when you use the mousewheel to scroll, the mousewheel scroll event gets fired before DOM elements are scrolled although it does not provide you with the anticipated scroll position and it is only one type of scroll. I am wondering if there is any event that gets fired for every scroll method(eg. mousewheel, dragging the scroll bar, pushing the down arrow etc.) BEFORE the DOM elements are scrolled. It does not have to be an event. I am not trying to scroll to a certain position so scrollTo would not be applicable.
The chain of event with on scroll:
User scrolls -> DOM elements physically scroll -> fires onScroll event -> handle stuff
The desired chain of event:
User scrolls -> some event is captured and do what I want to do -> DOM elements physically scroll -> fires onScroll event -> handle stuff
Heres something you might want to try.
Give your page overflow:hidden so that no scroll bars appear, then place an absolutely positioned div with the correct width & height over the content. When this div is scrolled, you can then update any underlying content before re-triggering the event.
You would need to pass through clicks etc as well, so this is really a hack. Something like jQuery would help with the triggering of the events and measuring the height of the content.
EDIT: css pointer-events:none may help here depending on the browser. See https://developer.mozilla.org/en/css/pointer-events
The best you can do is when onScroll fires, if scrollTop > thingToStick's distance from the top, then set position: fixed on thingToStick otherwise, set position to whatever it was originally. It'll flicker when changing from not-sticking to sticking, but besides that, you won't get any flickering.
in sudo-ish code:
onScroll = function()
{
if(scrollTop > thingToStick.y)
thingToStick.position = "fixed";
else
thingToStick.position = "relative";
}
In browsers that don't support fixed positioning, you're stuck with the flicker...
Never tryed this before, but to break the chain of event it would be possible to :
Capture the scroll event
Do your stuff
Use preventDefault() and stopPropagation to inhibit the event
Fake a new scroll event using the original one (this should be feasible I think)
Hope this will help.

Categories

Resources