I'm doing an HTML5 app, and I want to configure a swipe/drag function to open/close the offcanvas menu.
The function works great but I want to have more precise horizontal swipe or drag to prevent triggering vertical scroll and activating the menu.
By default swipe doesn't seem to works well because must be really fast (even changing the speed), drag works ok, but just pressing and move a bit activates the event.
I tried changing the variable drag_lock_min_distance, but unfortunately doesn't work at all, I cannot feel the difference even for the huge value that follows.
I tried checking real time the internal variables X speed and distance but they show the values taking as a reference the very first event, and not the dragstart and dragend.
I'm using raw hammer.js with twitter bootstrap, hammerjs version 1.0.6 from a CDN (last stable version). I'm testing on Android stock browser 4.1.2, and 4.4 (two different phones) as well as Google Chrome for Android.
Here you have the code:
var element = document.getElementById('contenido');
Hammer(element,{drag: true,
prevent_default: false,
drag_block_horizontal: true,
drag_lock_min_distance: 250,
hold: true,
release: true}).on("dragleft", function(event) {
// function
});
Hammer(element,{drag: true,
prevent_default: false,
drag_block_horizontal: true,
drag_lock_min_distance: 250,
hold: true,
release: true}).on("dragright", function(event) {
//function
});
Do you know any way to control the distance, to make firing of the event less sensible?
For someone coming across this in future, from Hammer > 2.0,
You can specify a threshold option to set the minimal distance required before recognizing, as shown below:
var hammertime = new Hammer(myElement, myOptions);
hammertime.get('swipe').set({ threshold: 100 });
hammertime.on('swipe', function(ev) {
console.log(ev);
});
Related
I have a horizontal scrolling element like this:
<ul class="playlist">
<li>element1</li>
<li>element2</li>
.
.
<li>elementN</li>
</ul>
https://jsfiddle.net/3um9n6zk/
On a touch device, the user can then swipe-scroll and select an element.
I'd also like to be able to pinch the container to adjust the elements' scale. Using Hammer 2.0:
function pinchMe($container) {
var options={
touchAction:"pan-x"
// touchAction:"none"
};
var hammer = new Hammer.Manager($container[0], options),
cInitScale;
hammer
.add( [
new Hammer.Pinch({ threshold: 0 }),
new Hammer.Tap(),
new Hammer.Press()
])
.on("pinchstart", function(e) {
cInitScale = VSIZE;
window.console.log("pinch start is ",VSIZE);
})
.on("pinch pinchmove", function(ev) {
// if pan-x is activated, I dont' get these events until a pinchend
window.console.log("pinch");
resizeHot (cInitScale * ev.scale);
})
.on("tap", tapHandler);
.on("press", pressHandler);
}
My problem is, once I use Hammer to control the pinch, the (native html) scrolling no longer works.
When I set pan-x as the Touch Action, no pinch events are sent after pinchstart, only when the pinch ends I get an event. I suspect the intermediate events are ignored as part of a scroll (even though 2 touches are pressed)
When I don't set pan-x, the scrolling doesn't work(as expected) and the pinch does work
Is it possible to have both things at once?
It seems you have a typo there. The option is called touchAction, singular. The value of "pan-x" that you gave it is correct in your case and will allow you to scroll horizontally.
I've updated your fiddle to try it out: https://jsfiddle.net/3um9n6zk/1/
I have a problem with a mediaelement player created within a Fancybox Modal. This is specific to an Android Device running 4.0.4.
On all iOS devices, new Android OS, Chrome, Firefox, and IE down to 7, when I create a new MediaElement player within a flexbox modal, I am able to view and interact with the controls.
But when I create it on the 4.0.4, the controls are hidden, though I can tap on them if I correctly guess where they are. But I cannot click on the video itself, which makes playing difficult. And the hidden controls are obviously a problem.
mediaelementjs_settings = {
loop : mej_loop,
pluginPath : options.plugin_path,
iPadUseNativeControls: options.mobile_native_controls,
iPhoneUseNativeControls: options.mobile_native_controls,
AndroidUseNativeControls: false,
alwaysShowControls: false,
error : function (mediaElement, domObject) {
$('<p class="' + options.component_type + '_error_message">' + options.error_msg + '</p>').insertAfter($(mediaElement).parent().parent().parent());
options.component_el.trigger(component_error, options);
},
success : function( mediaElement, domObject ) {
var meEl = mediaElement;
options.component_el.trigger(component_initialized, options);
if(mej_auto_start) {
// autostart requires a short timeout to work on several video formats. 100ms
// is hardly noticeable so we do it for everything for consistency
window.setTimeout(function() {
mediaElement.play();
}, 100);
}
},
pauseOtherPlayers: false
};
new MediaElementPlayer($(this).find('video:first'), mediaelementjs_settings);
I've played with z-index and other css fixes, but am currently stumped. Any ideas.
I determined it to be an issue where the overlay for Fancybox was somehow obscuring the controls. The solution was to set the positioning of the overlay to absolute instead of fixed. This could have impact on the way Fancybox worked so the script that inserts the video adds and removes a class which applies the appropriate style.
I've implemented drag and drop using the jQuery UI draggable widget.
I'm now implementing auto scroll during drag operations. I set it up so that when you start to drag, gray overlays appear at the top and bottom of the browser window. When you drag into one of these overlays, the browser window starts to auto scroll.
You can see my test page at http://www.softcircuits.com/Client/scrolltest.html. Drag an item by dragging one of the crosshair icons on the left side.
But there's a problem: if you scroll to the bottom of the page, and then drag an item to the top overlay, it will scroll up as expected. However, for me, I get about half way up the page and the draggable helper won't go any higher. There's no way for me to drag all the way to the top of the page.
This most likely seems related to the Draggable widget. Is anyone able to see why this is happening? I'm using Google Chrome on Windows 7.
To be cross-browser compatible and to avoid wird behavior, I would recommend to use all JQueryUI draggable callbacks.
I read some days ago that the last version of Chrome has some really tricky problems with natives HTML5 draggable events.
For example, I have just checked your web page source code and you are using $('.drag-handle').on('drag', function(){...}); => You should use the drag callback.
I would also recommend to not use window as the scrollable container in your case. You should create a div to wrap all the tables contents and use it as a scroll container. I have already done this implementation in the past and it is working.
Don't forget to set the wrapper ID in the containment option durring the draggable widget creation.
If it always not working, you could also try to overwrite the helper position in the drag callback :
//Save the mouse position in global variables
$(document).mousemove(function(e){
window.mouseXPos = e.pageX;
window.mouseYPos = e.pageY;
});
$('[id^="drag-"]').each(function() {
$(this).draggable({
opacity: 0.7,
cursorAt: { top: 15, left: 50 },
scroll: true,
stop: function(){},
drag : function(e,ui){
//Force the helper position
ui.position.left = window.mouseXPos - $(this).draggable('option','cursorAt').left;
ui.position.top = window.mouseYPos- $(this).draggable('option','cursorAt').top;
});
});
Changing the draggable containment option from window to document worked for me.
$('.drag-handle').draggable({
...
containment: "document",
...
});
See: http://docs.jquery.com/UI/Draggable#option-containment
I am using the most wonderful javascript tool iScroll4 http://cubiq.org/iscroll-4 on a mobile website for iOS and Android. Here is what my layout looks like:
The horizontally scroll-able area is making use of iScroll4 with the following settings:
var myScroll = new iScroll('frame', { hScrollbar: false, vScrollbar: false, vScroll: false })
The horizontal scrolling part works great. This issue is what happens when a user attempts to scroll up or down the page placing their finger on the horizontal scrolling area. So I need native vertical scrolling, and iScroll horizontal scrolling on the same area.
What I have tried so far:
Removing e.preventDefault() in the iScroll code (allows for native scrolling, but in BOTH axes).
Removing e.preventDefault() and then disabling horizontal scrolling page wide with this:
var touchMove;
document.ontouchstart = function(e){
touchMove = e.touches[0];
}
document.ontouchmove = function(e){
var theTouch = e.touches[0] || e.changedTouches[0];
var Xer = rs(touchMove.pageX - theTouch.pageX).toPos();
var Yer = rs(touchMove.pageY - theTouch.pageY).toPos();
touchMove = theTouch;
if(Yer > Xer){ e.preventDefault(); }
}
which seems to do nothing. How can I allow for native vertical scrolling in the horizontal scrolling area, without loosing the horizontal scrolling of iScroll? I am really stumped here. Thanks in advance.
(just for the record rs(foo).toPos() is a function that makes foo a positive number regardless of its value).
If you would like to achieve the effect described by Fresheyeball without hacking the core, and without changing from iScroll to swipeview, then iScroll 4 does offer you its event listeners to work with.
myScroll = new iScroll('scrollpanel', {
// other options go here...
vScroll: false,
onBeforeScrollMove: function ( e ) {
if ( this.absDistX > (this.absDistY + 5 ) ) {
// user is scrolling the x axis, so prevent the browsers' native scrolling
e.preventDefault();
} else {
// delegate the scrolling to window object
window.scrollBy( 0, -this.distY );
}
},
});
By doing so, the onBeforeScrollMove-Handler checks whether the scroll direction seems to be horizontal, and then prevents the default handler, thus effectively locking the scroll action to the X-Axis (try commenting it out, you'll see the difference). Otherwise, if the scroll direction needs to be vertical, we make the browser scroll via the window.scrollBy() method. This is not exactly native, but does the job just fine.
Hope that helps
Lukx
[EDIT]
My original solution, which didn't use window.scrollBy() ,did not work on slower Samsung phones, which is why I needed to adapt the answer.
Suggested edit to #Lukx's excellent solution. New versions of iScroll4 place the e.preventDefault() in onBeforeScrollMove which can be overridden. By placing the if block into this option, default is not prevented for vertical scrolling, and vertical can scroll natively.
myScroll = new iScroll('scrollpanel', {
// other options go here...
vScroll: false,
onBeforeScrollStart: function ( e ) {
if ( this.absDistX > (this.absDistY + 5 ) ) {
// user is scrolling the x axis, so prevent the browsers' native scrolling
e.preventDefault();
}
},
});
With iscroll 5, you can set eventPassthrough: true to achieve this. See http://iscrolljs.com/#configuring
OLD ANSWER
UPDATE a special pluggin has been written just to address this problem:
http://cubiq.org/swipeview
I found a way!
add a variable to the top of the document: if android is 15 and is iOS is 3
var scrollTolerance = ( rs().isDevice('android') )?15:3;
disable the original e.preventDefault(); for scrolling. This is under onBeforeScrollStart:
the in _move just under
timestamp = e.timeStamp || Date.now();
add this line
if( Math.sqrt(deltaX*deltaX) > scrollTolerance){e.preventDefault();}
What this does is the following:
the scrollTolerance sets, you guessed it, a tolerance for finger direction. We don't want to demand a perfect vertical angle to get the up down native scroll. Also iOS does not detect properly and will never be higher than 4 for some reason so I used 3. Then we disable iScroll's standard e.preventDefault(); which prevents native vertical scrolling on our bi-scrollable area. Then we insert e.preventDefault(); only upon move and based on finger direction from tolerance.
This does not work perfect. But is acceptable and works on iOS and Android. If anyone sees better ways please post here. This is something I (and assume others) need to use regularly, and we should have a perfect rock solid solution.
Thanks.
Please test this solution from Adam.
https://gist.github.com/hotmeteor/2231984
I think the trick is to add the check in onBeforeScrollMove. First get the initial touch position in onBeforeScrollTouchStart and then in onBeforeScrollMove check the new position and then disable the required scroll based on the difference.
iScroll 5 supports native scrolling of any axis!
http://iscrolljs.com/
on iScroll5 just set eventPassthrougt to true. That fixes it.
Is it possible to have YUI menus e.g. slide in as opposed to simply popping up?
Of cause. You should set up SLIDE effect for the widget.
var oMenu = new YAHOO.widget.Menu(
"productsandservices",
{
position: "static",
hidedelay: 750,
lazyload: true,
effect: {
effect: YAHOO.widget.ContainerEffect.SLIDE,
duration: 0.25
}
}
);
One of the older (be careful as at the time I used it, it required patches) series of examples for YUI MenuBar hacks in this functionality using various events:
http://developer.yahoo.com/yui/examples/menu/topnavfrommarkupwithanim.html
I don't think this is available out of the box, which is a bummer. Another peeve of mine is that there's no (built-in) way to hide submenus automatically once the user has moused over some options. This makes sense for accessibility (and is the reason it is like that, according to the YUI team), but there's nothing I can do about clients who will only see it as broken.