I want to make it so swiping over an image will take a user to the previous or next image, depending on the direction of the swipe. That part works great, BUT it removes the ability to zoom in on the image. According to this answer the solution is to enable touchAction: 'auto', but that breaks hammer.js entirely, preventing it from working for swipe at all.
Code:
<script src="../js/hammer.min.js"></script>
<script>
$('.imagecontainer').each(function(){
var options = {
touchAction: 'auto',
};
var mc = new Hammer(this, options);
mc.on("swipeleft", function() {
navTo('jsnavnext');
return false;
});
mc.on("swiperight", function() {
navTo('jsnavprev');
return false;
});
});
</script>
I can get pinch-zoom to work in the least user-friendly way possible with touchAction: 'pan-y' (basically requires the user to make a wacky circle motion), but that's not...great. Ideally I'd like hammer.js to ONLY add swipe navigation and not touch any other default behaviour.
I had a problem that was similar. I wanted to be able to detect swipes on a div and also be able to pinch zoom on the div. The swipe listener alone seemed to disable zoom. Adding touchAction:'auto' allowed me to pinch zoom, but it read would both fire my swipe action and scroll (I didn't want it to scroll, just wanted to fire the swipe action). The key part of the solution I have here is using recognizeWith, and then call preventDefault on panstart and panmove. This leaves me with just the desired pinch zoom and swipes
Here's my solution:
var target = document.getElementById("target-div")
var mc = new Hammer(target, {touchAction: 'auto' });
mc.add( new Hammer.Pan({
direction: Hammer.DIRECTION_ALL,
threshold: 0 }) );
mc.add(new Hammer.Swipe({
direction: Hammer.DIRECTION_ALL,
threshold: 1,
velocity:0.1
})).recognizeWith(mc.get('pan'));
mc.on('panstart panmove', function(ev) { ev.preventDefault(); });
mc.get('pinch').set({ enable: true });
mc.on("pinch", function(ev) {
//do anything you need to here, or not
});
mc.on("swipeleft", function(ev) {
//do something
}
mc.on("swiperight", function(ev) {
//do something
}
I am still new to hammer.js, but I have noticed a lot of issues on github where people are trying to combine multiple gestures on the same element. I hope this helps!
Related
Has anyone figure out how to solve this? I talked to Matteo from Cubiq and his solution was to use transitions instead of transforms. Right now, im essentially adding padding the size of the keyboard below the page when the keyboard comes up, but that has a bunch of new issues revolving around the cursor being messed up:
$('body').on('focus', 'input, textarea', function() {
console.log('SCROLLER INPUT FOCUS');
if(!self.getCurrentScroller()) return;
self.getCurrentScroller().css('padding-bottom', 260);
self.getCurrentIscroll().refresh();
self.getCurrentIscroll().scrollToElement(this, 0);
});
$('body').on('blur', 'input, textarea', function() {
console.log('SCROLLER INPUT BLUR');
if(!self.getCurrentScroller()) return;
self.getCurrentScroller().css('padding-bottom', 0);
self.getCurrentIscroll().refresh();
self.getCurrentIscroll().scrollToElement(this, 0);
});
the idea is that the keyboard only causes iScroll to get stuck above the viewport if you're at the bottom of iscroll and there is no more page to scroll when the keyboard pushes it up.
Sometimes virtual keyboard causes physical sroll to change. So that you might scroll it to top when keyboard hides.
$wrapper.find('input, textarea').on('blur', function (e) {
$wrapper.scrollTop(0);
});
I would like to know if it is possible to disable all scrolling on a webpage.
I am currently using
html, body { overflow:hidden; }
The issue is that this does not work on iOS devices and if you hold in the mouse wheel and drag it down you can also scroll, so it seems like a very poor solution to the problem
Is there a way to disable all methods of scrolling on all devices and then re-enable it?
I have had this exact same issue, i fixed it with the following;
var disableScroll = false;
var scrollPos = 0;
function stopScroll() {
disableScroll = true;
scrollPos = $(window).scrollTop();
}
function enableScroll() {
disableScroll = false;
}
$(function(){
$(window).bind('scroll', function(){
if(disableScroll) $(window).scrollTop(scrollPos);
});
$(window).bind('touchmove', function(){
$(window).trigger('scroll');
});
});
the touch move is bound to the window as the window scroll event is not fired until touch move is completed, so this allows a much smoother experience on iOS!
This isn't a perfect solution as you can 'throw' the page, but it will return to desired position when the throw has complete (as the window scroll event will then be fired). This is because iOS browsers strip out a lot of events for performance. also setTimeout and setInterval functions do not fire whilst the page is being thrown, having a loop isn't an option either!
see here http://jsfiddle.net/8T26k/
I try to make a mousewheel event script, but getting some issues since I'm using an Apple Magic Mouse and its continue-on-scroll function.
I want to do this http://jsfiddle.net/Sg8JQ/ (from jQuery Tools Scrollable with Mousewheel - scroll ONE position and stop, using http://brandonaaron.net/code/mousewheel/demos), but I want a short animation (like 250ms) when scrolling to boxes, AND ability to go throught multiple boxes when scrolling multiple times during one animation. (If I scroll, animation start scrolling to second box, but if I scroll again, I want to go to the third one, and if I scroll two times, to the forth, etc.)
I first thought stopPropagation / preventDefault / return false; could "stop" the mousewheel velocity (and the var delta) – so I can count the number of new scroll events (maybe with a timer) –, but none of them does.
Ideas?
EDIT : If you try to scroll in Google Calendars with these mouses, several calendars are switched, not only one. It seems they can't fix that neither.
EDIT 2 : I thought unbind mousewheel and bind it again after could stop the mousewheel listener (and don't listen to the end of inertia). It did not.
EDIT 3 : tried to work out with Dates (thanks to this post), not optimal but better than nothing http://jsfiddle.net/eZ6KE/
Best way is to use a timeout and check inside the listener if the timeout is still active:
var timeout = null;
var speed = 100; //ms
var canScroll = true;
$(element).on('DOMMouseScroll mousewheel wheel', function(event) {
// Timeout active? do nothing
if (timeout !== null) {
event.preventDefault();
return false;
}
// Get scroll delta, check for the different kind of event indexes regarding delta/scrolls
var delta = event.originalEvent.detail ? event.originalEvent.detail * (-120) : (
event.originalEvent.wheelDelta ? event.originalEvent.wheelDelta : (
event.originalEvent.deltaY ? (event.originalEvent.deltaY * 1) * (-120) : 0
));
// Get direction
var scrollDown = delta < 0;
// This is where you do something with scrolling and reset the timeout
// If the container can be scrolling, be sure to prevent the default mouse action
// otherwise the parent container can scroll too
if (canScroll) {
timeout = setTimeout(function(){timeout = null;}, speed);
event.preventDefault();
return false;
}
// Container couldn't scroll, so let the parent scroll
return true;
});
You can apply this to any scrollable element and in my case, I used the jQuery tools scrollable library but ended up heavily customizing it to improve browser support as well as adding in custom functionality specific to my use case.
One thing you want to be careful of is ensuring that the timeout is sufficiently long enough to prevent multiple events from triggering seamlessly. My solution is effective only if you want to control the scrolling speed of elements and how many should be scrolled at once. If you add console.log(event) to the top of the listener function and scroll using a continuous scrolling peripheral, you will see many mousewheel events being triggered.
Annoyingly the Firefox scroll DOMMouseScroll does not trigger on magic mouse or continuous scroll devices, but for normal scroll devices that have a scroll and stop through the clicking cycle of the mouse wheel.
I had a similar problem on my website and after many failed attempts, I wrote a function, which calculated total offset of selected box and started the animation over. It looked like this:
function getOffset() {
var offset = 0;
$("#bio-content").children(".active").prevAll().each(function (i) {
offset += $(this)[0].scrollHeight;
});
offset += $("#bio-content").children(".active")[0].scrollHeight;
return offset;
}
var offset = getOffset();
$('#bio-content').stop().animate( {
scrollTop: offset
}, animationTime);
I hope it gives you an idea of how to achieve what you want.
you can try detecting when wheel stops moving, but it would add a delay to your response time
$(document).mousewheel(function() {
clearTimeout($.data(this, 'timer'));
$.data(this, 'timer', setTimeout(function() {
alert("Haven't scrolled in 250ms!");
//do something
}, 250));
});
source:
jquery mousewheel: detecting when the wheel stops?
or implement flags avoiding the start of a new animation
var isAnimating=false;
$(document).bind("mousewheel DOMMouseScroll MozMousePixelScroll", function(event, delta) {
event.preventDefault();
if (isAnimating) return;
navigateTo(destination);
});
function navigateTo(destination){
isAnimating = true;
$('html,body').stop().animate({scrollTop: destination},{complete:function(){isAnimating=false;}});
}
This question has been asked after a detailed discussion on this SO question
Problem:
I need a horizontal scroll which can be scrolled using mouse drag on desktops and swipe events on touch enabled screens
Possible Solution:
I tried using the jQuery dragscrollable which works fine on desktops but not on touch enabled devices
So then I went on to explore Touch Swipe Jquery Plugin and came up with a possible solution at JSFiddle Code and the result for the JSFiddle can be found here
You can also find a working demo at here
My java script code is as follows
//to detect if device has touch enabled
var is_touch_device = 'ontouchstart' in document.documentElement;
$(function()
{
$('.myClass').dragscrollable();
//if touch is enabled then we have to map the swipe event
if(is_touch_device)
$('.panel_list').swipe( { swipeStatus:scroll_panel_list, allowPageScroll:'horizontal' } );
function scroll_panel_list(event, phase, direction, distance)
{
var pos = $('.myClass').scrollLeft();
if(direction == 'left')
{
$('.myClass').animate({scrollLeft: pos + 200} );
}
if(direction == 'right')
{
$('.myClass').animate({scrollLeft: pos - 200} );
}
}
});
I have tested it works fine on Android browser but not very reponsive on iPhone.
Can someone help me come up with a better solution ? I am using twitter bootstrap
EDIT:1
Well now I guess I might have hit upon a nice plugin in that seems to work fine on desktops and touch enabled devices, the plugin is called jquery.dragscroll, I have an updated demo here
EDIT:2
There seems to be another plugin that has support for touch-enabled devices, it is called Overscroll. I haven't evaluated it as yet
Additionally, there is the "Swipeview" script
http://cubiq.org/swipeview
I found an older solution and modified it for horizontal scrolling. I've tested it on Android Chrome and iOS Safari and the listener touch events have been around a long time, so it has good support: http://caniuse.com/#feat=touch.
Usage:
touchHorizScroll('divIDtoScroll');
Functions:
function touchHorizScroll(id){
if(isTouchDevice()){ //if touch events exist...
var el=document.getElementById(id);
var scrollStartPos=0;
document.getElementById(id).addEventListener("touchstart", function(event) {
scrollStartPos=this.scrollLeft+event.touches[0].pageX;
},false);
document.getElementById(id).addEventListener("touchmove", function(event) {
this.scrollLeft=scrollStartPos-event.touches[0].pageX;
},false);
}
}
function isTouchDevice(){
try{
document.createEvent("TouchEvent");
return true;
}catch(e){
return false;
}
}
Original Vertical one-finger touch scroll:
http://chris-barr.com/2010/05/scrolling_a_overflowauto_element_on_a_touch_screen_device/
Vertical now has a simplified CSS solution, doesn't work for horizontal DIV scroll on mobile though:
-webkit-overflow-scrolling: touch
The question also asks for mouse-grab on desktop, which can be accomplished with Nice Scroll, and does work in tandem with my solution above if you need it:
https://github.com/inuyaksa/jquery.nicescroll
var nice = $("#mydiv").getNiceScroll({horizrailenabled: true, hwacceleration: true});
This is possible with
http://labs.rampinteractive.co.uk/touchSwipe/demos/Page_scrolling.html
$('body').swipe({
swipe: function(event, direction, distance, duration, fingerCount) {
switch (direction) {
case 'left':
// Code here
break;
case 'right':
//Code here
break;
}
},
allowPageScroll: "vertical"
});
I use the following javascript (with jQuery) to handle drag and drop on a script I am writing:
jsc.ui.dragging = false;
jsc.ui.drag_element = {};
$(".drag-target").mousedown(function() {
jsc.ui.drag_element = $(this);
jsc.ui.dragging = true;
});
$("html").mousemove(function(e) {
if(jsc.ui.dragging) {
jsc.ui.drag_element.css({"position": "absolute", "top": e.clientY - 1, "left": e.clientX - 1, "z-index": "100"}); // - 1s are due to IE not leaving go otherwise
$("#overlay").show(); // Overlay stops text beneath being selected. TODO Stop current elements text being selected.
}
});
$(".drag-target").mouseup(function() {
if(jsc.ui.dragging) {
jsc.ui.dragging = false;
jsc.ui.drag_element.css("z-index", "98");
$("#overlay").hide();
}
});
However when the object is being dragged, the text inside it has a flickering selection i.e. it is being selected on and off as the element is moved. Is there any way to prevent this, or hide it's effect?
Is there a reason for not using jQuery UI Draggable ? Your code would look like that:
$(".drag-target").draggable();
You should at least check how it's build, it may help you to solve you flickering problem.
I think the extent of the effect depends on your hardware and video driver. To avoid it entirely, you could just draw a rectangle and then redraw the window when the mouse button is released.