I'm trying to build a Webpage that senses the touch from the user and drags and object along the canvas.
So I'm doing something like this:
var touchStart = function(e) {
e.preventDefault();
// Do stuff
}
var touchMove = function(e) {
e.preventDefault();
console.log("Touch move");
// Move objs
}
var touchEnd = function(e) {
e.preventDefault();
console.log("Touch start!");
// clean up stuff
}
var touchCancel = function(e) {
e.preventDefault();
// Oh NO touch cancel!
console.log("Touch cancel!");
}
bindElemOrig.addEventListener('touchstart', touchStart, false);
bindElemOrig.addEventListener('touchmove', touchStart, false);
bindElemOrig.addEventListener('touchend', touchStart, false);
bindElemOrig.addEventListener('touchcancel', touchStart, false);
It works fine until some point.
The problem is that as soon as I load too many objs, it seems to me that the touchmove takes too long to respond, and touchcancel gets triggered. The problem is that as soon as touchcancel get triggered I don't receive any more touchmoves events, and I cannot sense the movement anymore.
Did anyone face this problem? I know about the bug in Android where you must call preventDefault (touchend event in ios webkit not firing?) but on this case it seems that it is not working because of the memory burden.
Thank you!
like this
var touchMove = function(e) {
e.preventDefault();
setTimeout(function(){
console.log("Touch move");
// Move objs
})
}
use setTimeout to wrap you logic in touchmove can solve this problem
This problem may be due to a bug (feature?) in Chrome/Android. See this bug report.
This test demonstrates the behavior (JSFiddle):
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
var delay = 200;
var haltEvent = function(event) {
event.preventDefault();
event.stopPropagation();
};
var pause = function() {
var startTime = new Date().getTime();
while (new Date().getTime() < startTime + delay);
};
window.addEventListener('load', function() {
var target = document.querySelector('#target');
var status = document.querySelector('#status');
target.addEventListener('touchstart', function(event) {
haltEvent(event);
status.innerHTML = '[touchstart]';
}, true);
target.addEventListener('touchmove', function(event) {
pause();
haltEvent(event);
status.innerHTML = '[touchmove]';
}, true);
target.addEventListener('touchend', function(event) {
status.innerHTML = '[touchend]';
}, true);
target.addEventListener('touchcancel', function(event) {
status.innerHTML = '[touchcancel]';
}, true);
});
</script>
<style>
#target {
background-color: green;
height: 300px;
}
#status {
text-align: center;
}
</style>
</head>
<body>
<div id="target"></div>
<p id="status">[]</p>
</body>
</html>
I don't find the touchcancel event to be fired randomly. Instead, it is fired whenever it takes ~200 ms to return from a touchmove event handler.
Touchcancel is specifically designed to take control of touch events and perform regular browser actions such as pan or zoom after a very small touch and move action (nearly 20px, depending on browser).
Your only options are to either:
- Switch to Pointer Events and use the
touch-action
CSS property as
explained here to
prevent pointercancel
from firing (recommended but requires Android 5+)
- Add
event.preventDefault()
inside your touchmove
event handler, but this will also disable any default actions like scroll, pan, zoom, etc.
You cannot attemp to cancel or preventDefault()
inside a touchcancel
function because it will be too late for that; the browser has already stopped listening to the touchmove
event. This is by design, not a bug.