touchmove/MSPointerMove event not firing in Windows 8 - javascript

I'm just a lowly uC programmer who's trying to put together a little web interface for his boss. I've got everything working so far except being able to select a square on a canvas using touch input.
This is on a Samsung Slate 7 tablet running Windows 8 and IE10
I've distilled the code down to pretty much the bare essentials here:
var cxt;
var c;
window.onload = function () {
c = document.getElementById('displayCanvas');
cxt = c.getContext('2d');
/*
c.addEventListener("MSPointerUp", mouseUp, false);
c.addEventListener("MSPointerMove", mouseMove, false);
c.addEventListener("MSPointerDown", mouseDown, false);
*/
c.addEventListener("touchend", mouseUp, false)
c.addEventListener("touchmove", mouseMove, false);
c.addEventListener("touchstart", mouseDown, false);
}
function mouseDown(downE) {
window.console && console.log("down");
};
function mouseMove(moveE){
window.console && console.log("move");
}
function mouseUp() {
window.console && console.log("end");
}
I get both the start and end events, using both the MSPointer and the "normal" javascript touch events, however the "move" event doesn't register.
I'm sure it's something really simple I'm missing here, thanks for helping me out!

I'm assuming you are interacting with the HTML page in desktop IE on Windows 8. In desktop IE, the MSPointerMove is not firing on that canvas because the default behavior when the user moves their finger around on the screen is to pan the content. If you style the canvas with the following snippet your MSPointerMove event should be detected.
style="-ms-touch-action: none"
Here's a great article on how to get touch working on many browsers. http://blogs.msdn.com/b/ie/archive/2011/10/19/handling-multi-touch-and-mouse-input-in-all-browsers.aspx

The Samsung Slate 7 tablets have a bug in older versions of the drivers that might be relevant. I saw another answer tagged [internet-explorer-10] that had the details. Have you updated your driver?

Related

Force update of ScaleLine Control in openlayers 2

I'm using Openlayers 2 and I'm creating a map app. I'm using apache cordova so it's just javascript/html/css.
It works fine for most cases but when I zoom in and out a bunch of times (with my fingers on a touchscreen) sometimes the scaleline stops updating. Moving the map around and zooming in/out some more usually get's it starting again.
My question is: Is there a way to force the ScaleLine control to redraw (other than moving around the screen and zoom in/out randomly). Like, is there a function I can run on, say, the click of a button to force redrawing?
I've tried
map.Control.Scaleline.update();
map.Control.Scaleline.draw();
But it doesn't work
Thanks!
PS:
I've tried opening the app from chrome on a desktop and since I don't have the touch screen capability there I can't reproduce the error
By looking at OpenLayers.debug.js I could see that scaleline is updated at "moveend" event which is only triggered when touch is completed (which it isn't if the user doesn't let the touch drag finish for example by zooming)
"move" always triggers, so I solved it by triggering "moveend" on "move" event.
map.events.on ({
"move": function () {
map.events.triggerEvent("moveend");
}
}
});
It removes the detail of adding certain events only on "moveend" but it solves the problem. Please comment if you have a better solution!
#atwinther was almost right. The solution is to watch for "touchend" and then send a moveend event. Only the latest browsers support this, however, so it might still be buggy for some people. At the least, according to Mozilla, this should work for the latest Firefox and Chrome: https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent
This is what I did that worked, with non-essential code ellided:
var SYP = {
init: function() {
this.map = new OpenLayers.Map("map");
// workaround for ol2 bug where touch events do not redraw the
// graticule or scaleline
this.map.events.on ({
"touchend": function () {
SYP.map.events.triggerEvent("moveend");
}
});
},

Why is setTimeout game loop experiencing lag when touchstart event fires?

This is a rather specific problem I'm having. The glitch only seems to appear in the latest update of Chrome for Android, so here are the specs:
Application Version:
Chrome 45.0.2454.84
Operating System:
Android 4.4.4; XT1031 Build/KXB21.14-L2.4
I'm using a Moto G, but the glitch also occurred on a Samsung running the same version of Chrome. Anyway, the problem is clearly that touchstart events interrupt my window.setTimeout game loop. Here's the code:
(
function rafTouchGlitch() {
/////////////////
/* FUNCTIONS. */
///////////////
function touchStartWindow(event_) {
event_.preventDefault();
}
///////////////////////
/* OBJECT LITERALS. */
/////////////////////
var engine = {
/* FUNCTIONS. */
start : function(interval_) {
var handle = this;
(function update() {
handle.timeout = window.setTimeout(update, interval_);
/* Draw the background and the red square. */
display.fillStyle = "#303030";
display.fillRect(0, 0, display.canvas.width, display.canvas.height);
display.fillStyle = "#f00000";
display.fillRect(red_square.x, red_square.y, 20, 20);
/* Update the square's position. */
red_square.x++;
if (red_square.x > display.canvas.width) {
red_square.x = -20;
}
})();
},
/* VARIABLES. */
timeout : undefined
};
red_square = {
/* VARIABLES. */
x : 0,
y : 0
};
/////////////////
/* VARIABLES. */
///////////////
var display = document.getElementById("canvas").getContext("2d");
//////////////////
/* INITIALIZE. */
////////////////
window.addEventListener("touchstart", touchStartWindow);
engine.start(1000 / 60);
})();
This code works fine in any other browser and even in previous versions of Chrome. It worked fine in the last release, but for some reason now there's a problem. I'm not sure if this is a bug on Chrome's end or if they're doing something new and I'm the one not covering my bases, but the fact remains that there's a glaring lag in my game loop when touchstart events fire.
Here's a fiddle: https://jsfiddle.net/dhjsqqxn/
Tap the screen and see how the red square lags! It's ridiculous. You can basically freeze the Timeout object by tapping the screen fast enough.
If you have an Android phone, I urge you to update Chrome and visit the link to see what I mean. If this is a bug it's a huge one, considering how valuable setTimeout is and how vital touchstart is on mobile. If it's not a bug, I'd really like to know what I'm doing wrong.
Thanks for your time!
See https://bugs.chromium.org/p/chromium/issues/detail?id=567800
Android Chrome does not run scheduled(setTimeout/setInterval) callbacks during touchmove.
As a workaround you can try window.requestAnimationFrame() or run the callback manually in touchmove event which would require to keep/check a last-run time.
Do "return false;" at the end of the touchstart func.
for a swipe the following jquery without jquerymobile..
$("#id").on({'touchstart' : functionforstart, 'touchmove' :onmove, 'touchend' : functionforend});
functionforstart(e){ e.originalEvent.touches[0].pageX usw.. return false;}
function onmove(e){lastMove=e}
function functionforend(){lastMove.originalEvent.touches[0].pageX} usw.. e.prefentDefault(); }
That works for me.. var lastMove have to be global and you need a touchmove step to get the position in touchend.. hope this is also what you needed..

Android 4 Chrome hit testing issue on touch events after CSS transform

I'm having issues with the combination of CSS transforms and touch event hit testing. This only reproduces for me in Chrome on Android 4 (stable and beta). iOS Safari, as well as Chrome desktop with touch emulation both appear to be working fine.
I'm almost positive this has to be a bug, so I think I'm mostly looking for workarounds here.
The issue is that hit testing for touch only seems to work for where the element was before the transform, not the final position. You can see an example on my jsfiddle (only on Android 4 Chrome):
jsfiddle: http://jsfiddle.net/LfaQq/
full screen: http://jsfiddle.net/LfaQq/embedded/result/
If you drag the blue box half way down the screen and release it will snap back to the top. Now, if you try dragging from the top half of the page again, no touch will register. The touch events aren't even fired on the element. However, if you attempt to touch the bottom of the element, it works fine. You can then try moving it up from the bottom, and observing that hit testing no longer works on the bottom, but works on the top.
This is how I'm handling the events:
function handleTouch(e) {
console.log("handle touch")
e.preventDefault();
switch(e.type){
case 'touchstart':
console.log("touchstart");
touchOriginY = e.targetTouches[0].screenY;
break;
case 'touchmove':
console.log("touchmove");
el.innerHTML = e.targetTouches[0].screenY;
var p = e.targetTouches[0].screenY - touchOriginY;
el.style[TRANSFORM] = 'translate3d(0,' + p + 'px' + ',0)';
break;
case 'touchcancel':
console.log("touchcancel");
// Fall through to touchend
case 'touchend':
//console.log("touchend");
//el.style[TRANSITION] = '.4s ease-out';
el.style[TRANSFORM] = 'translate3d(0,0,0)';
break;
}
}
el.addEventListener('touchstart', handleTouch);
el.addEventListener('touchend', handleTouch);
el.addEventListener('touchmove', handleTouch);
el.addEventListener(TRANSITION_END, function(e) {
console.log("transition end")
el.style[TRANSITION] = '';
});
I don't have any problems with the transforms in touchmove, as those aren't new touches to be detected anyways.
Any suggestions?
This is an unusual bug in Chrome.
Essentially the hit targets for an element is recorded during a layout pass by the browser. Each time you set innerHTML, the browser will relayout and the last time this is done, is before the touchend event is fired. There are a couple of ways around it:
OPTION 1: You can set a touch handler on the body element and check the target of touch event to see if it is touching the red block. Tip of the cap to Paul Lewis for this approach.
http://jsfiddle.net/FtfR8/5/
var el = document.body;
var redblock = $('.splash-section');
function handleTouch(e) {
console.log("handle touch")
if(e.target != redblock) {
return;
}
....
OPTION 2: Set an empty touch callback on the document seems to fix the problem as well - according to some of the linked bug reports, this causes the hit testing to be done on the main thread which is a hit on performance but it properly calculates the hit targets.
http://jsfiddle.net/LfaQq/2/
document.body.addEventListener('touchstart', function(){});
OPTION 3: Set innerHTML after the transition has ended to force a relayout:
el.addEventListener(TRANSITION_END, function(e) {
console.log("trans end - offsettop:" + el.offsetTop);
el.style[TRANSITION] = '';
el.innerHTML = 'Relayout like a boss!';
});
I've created a bug report here and Rick Byers has linked to a related bug with additional info: https://code.google.com/p/chromium/issues/detail?id=253456&thanks=253456&ts=1372075599

Javascript mousedown event location on windows phone

I am creating a mobile site that needs to be cross browser compatible. For one feature I need to detect the location of a touch event.
Windows Phone does not support touchstart etc. so I am using mousedown instead, but I am having trouble getting the page position from the event. It works without issue on desktop, and the mousedown is being detected on windows phone, but I can't figure out how to get the offsetX - offset Y.
Here's a sample which works on desktop and on iPhone and android
(I am using jQuery but no plugins or anything non-standard):
$("div").on("touchstart mousedown", function(e){
org_x = e.originalEvent.changedTouches[0].pageX ? e.originalEvent.changedTouches[0].pageX : e.originalEvent.offsetX;
alert(org_x);
org_y = e.originalEvent.changedTouches[0].pageY ? e.originalEvent.changedTouches[0].pageY : e.originalEvent.offsetY;
alert(org_y);
});
I have tested this on windows phone 8 and 9
try this code ,it will work fine
document.getElementById("clickdiv").addEventListener("MSPointerDown",handleDown,false);
function handleDown(evt) {
alert(evt.originalEvent.layerX);
}
$("#clickdivalt").on("MSPointerDown", handleAltDown);
function handleAltDown(evt){
alert(evt.originalEvent.layerX);
}
From what i see you want to read this article: Touch/Gestures On Mobile Devices or have a look at this stack overflow question: Windows phone 8 touch support
Im still looking arrow and will update my answer with better solutions as i find them!
The isues width MSPonterDown etc. seem to be a jquery bug/incompatablility. If I set the event handler with pure javascript I can get the pageX and pageY attributes. If I set the event handler with jquery there is no pageX pageY.
document.getElementById("clickdiv").addEventListener("MSPointerDown",handleDown,false);
function handleDown(evt) {
alert(evt.pageX);
}
$("#clickdivalt").on("MSPointerDown", handleAltDown);
function handleAltDown(evt){
alert(evt.pageX);
}

Detecting touch screen devices with Javascript

In Javascript/jQuery, how can I detect if the client device has a mouse?
I've got a site that slides up a little info panel when the user hovers their mouse over an item. I'm using jQuery.hoverIntent to detect the hover, but this obviously doesn't work on touchscreen devices like iPhone/iPad/Android. So on those devices I'd like to revert to tap to show the info panel.
var isTouchDevice = 'ontouchstart' in document.documentElement;
Note: Just because a device supports touch events doesn't necessarily mean that it is exclusively a touch screen device. Many devices (such as my Asus Zenbook) support both click and touch events, even when they doen't have any actual touch input mechanisms. When designing for touch support, always include click event support and never assume any device is exclusively one or the other.
Found testing for window.Touch didn't work on android but this does:
function is_touch_device() {
return !!('ontouchstart' in window);
}
See article: What's the best way to detect a 'touch screen' device using JavaScript?
+1 for doing hover and click both. One other way could be using CSS media queries and using some styles only for smaller screens / mobile devices, which are the ones most likely to have touch / tap functionality. So if you have some specific styles via CSS, and from jQuery you check those elements for the mobile device style properties you could hook into them to write you mobile specific code.
See here: http://www.forabeautifulweb.com/blog/about/hardboiled_css3_media_queries/
if ("ontouchstart" in window || navigator.msMaxTouchPoints) {
isTouch = true;
} else {
isTouch = false;
}
Works every where !!
return (('ontouchstart' in window)
|| (navigator.maxTouchPoints > 0)
|| (navigator.msMaxTouchPoints > 0));
Reason for using maxTouchPoints alongwith msMaxTouchPoints:
Microsoft has stated that starting with Internet Explorer 11,
Microsoft vendor prefixed version of this property (msMaxTouchPoints)
may be removed and recommends using maxTouchPoints instead.
Source : http://ctrlq.org/code/19616-detect-touch-screen-javascript
I use:
if(jQuery.support.touch){
alert('Touch enabled');
}
in jQuery mobile 1.0.1
Google Chrome seems to return false positives on this one:
var isTouch = 'ontouchstart' in document.documentElement;
I suppose it has something to do with its ability to "emulate touch events" (F12 -> settings at lower right corner -> "overrides" tab -> last checkbox). I know it's turned off by default but that's what I connect the change in results with (the "in" method used to work in Chrome).
However, this seems to be working, as far as I have tested:
var isTouch = !!("undefined" != typeof document.documentElement.ontouchstart);
All browsers I've run that code on state the typeof is "object" but I feel more certain knowing that it's whatever but undefined :-)
Tested on IE7, IE8, IE9, IE10, Chrome 23.0.1271.64, Chrome for iPad 21.0.1180.80 and iPad Safari. It would be cool if someone made some more tests and shared the results.
Wrote this for one of my sites and probably is the most foolproof solution. Especially since even Modernizr can get false positives on touch detection.
If you're using jQuery
$(window).one({
mouseover : function(){
Modernizr.touch = false; // Add this line if you have Modernizr
$('html').removeClass('touch').addClass('mouse');
}
});
or just pure JS...
window.onmouseover = function(){
window.onmouseover = null;
document.getElementsByTagName("html")[0].className += " mouse";
}
For my first post/comment:
We all know that 'touchstart' is triggered before click.
We also know that when user open your page he or she will:
1) move the mouse
2) click
3) touch the screen (for scrolling, or ... :) )
Let's try something :
//--> Start: jQuery
var hasTouchCapabilities = 'ontouchstart' in window && (navigator.maxTouchPoints || navigator.msMaxTouchPoints);
var isTouchDevice = hasTouchCapabilities ? 'maybe':'nope';
//attach a once called event handler to window
$(window).one('touchstart mousemove click',function(e){
if ( isTouchDevice === 'maybe' && e.type === 'touchstart' )
isTouchDevice = 'yes';
});
//<-- End: jQuery
Have a nice day!
I have tested following code mentioned above in the discussion
function is_touch_device() {
return !!('ontouchstart' in window);
}
works on android Mozilla, chrome, Opera, android default browser and safari on iphone...
all positive ...
seems solid for me :)
A helpful blog post on the subject, linked to from within the Modernizr source for detecting touch events. Conclusion: it's not possible to reliably detect touchscreen devices from Javascript.
http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
This works for me:
function isTouchDevice(){
return true == ("ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch);
}
If you use Modernizr, it is very easy to use Modernizr.touch as mentioned earlier.
However, I prefer using a combination of Modernizr.touch and user agent testing, just to be safe.
var deviceAgent = navigator.userAgent.toLowerCase();
var isTouchDevice = Modernizr.touch ||
(deviceAgent.match(/(iphone|ipod|ipad)/) ||
deviceAgent.match(/(android)/) ||
deviceAgent.match(/(iemobile)/) ||
deviceAgent.match(/iphone/i) ||
deviceAgent.match(/ipad/i) ||
deviceAgent.match(/ipod/i) ||
deviceAgent.match(/blackberry/i) ||
deviceAgent.match(/bada/i));
if (isTouchDevice) {
//Do something touchy
} else {
//Can't touch this
}
If you don't use Modernizr, you can simply replace the Modernizr.touch function above with ('ontouchstart' in document.documentElement)
Also note that testing the user agent iemobile will give you broader range of detected Microsoft mobile devices than Windows Phone.
Also see this SO question
In jQuery Mobile you can simply do:
$.support.touch
Don't know why this is so undocumented.. but it is crossbrowser safe (latest 2 versions of current browsers).
As already mentioned, a device may support both mouse and touch input. Very often, the question is not "what is supported" but "what is currently used".
For this case, you can simply register mouse events (including the hover listener) and touch events alike.
element.addEventListener('touchstart',onTouchStartCallback,false);
element.addEventListener('onmousedown',onMouseDownCallback,false);
...
JavaScript should automatically call the correct listener based on user input. So, in case of a touch event, onTouchStartCallback will be fired, emulating your hover code.
Note that a touch may fire both kinds of listeners, touch and mouse. However, the touch listener goes first and can prevent subsequent mouse listeners from firing by calling event.preventDefault().
function onTouchStartCallback(ev) {
// Call preventDefault() to prevent any further handling
ev.preventDefault();
your code...
}
Further reading here.
For iPad development I am using:
if (window.Touch)
{
alert("touchy touchy");
}
else
{
alert("no touchy touchy");
}
I can then selectively bind to the touch based events (eg ontouchstart) or mouse based events (eg onmousedown). I haven't yet tested on android.

Categories

Resources