I'm making a simple player motion in Javascript canvas. (Up down left right)
I created 4 buttons on screen for mobile players. I used the following code for the buttons as I wanted to move the player until the button is released.
upBtn.addEventListeter('mousedown',()=>{
let interval=setInterval(()=>{
player.y--;
}, 50);
upBtn.addEventListener('mouseup',()=>{
clearInterval(interval);
});
});
The above code works perfectly when the buttons are clicked in a computer. But in mobile it is not working.
I also tried to use touchdown and touchup but it didn't work.
What changes should I make in the code to make it work in mobile also?
Thanks in advance
You're looking for touchstart and touchend
function upFunc(event) {
//prevents some devices to emulate the click event
event.preventDefault();
let interval=setInterval(()=>{
player.y--;
}, 50);
upBtn.addEventListener('mouseup',downFunc);
upBtn.addEventListener('touchend',downFunc);
}
function downFunc(e) {
e.preventDefault();
clearInterval(interval);
}
upBtn.addEventListeter('mousedown', upFunc);
upBtn.addEventListeter('touchstart', upFunc);
Note that to support both mouse and touch in vanilla js you'll have to add both event listeners.
Also, some devices emulate the mouse events, so you can use preventDefault() to make sure your functions fires only once.
I had a similar issue and eventually solved it. I don't remember all the details of how I got to the end result but here is the code I eventually used to get it to work.
It is for controlling a camera robot. Pressing and holding the forward arrow makes the robot move forward while the button is held down and stops as soon as the button is released.
It works both on PC browser and on smartphone browsers. I've only tried it on a couple of browsers on Samsung though.
It uses the onmousup and onmousedown for the PC while for the smartphone it is a bit more complicated using the touch events.
Also important is the oncontextmenu="absorbEvent_()" which prevents the context menu from appearing when you hold down a button.
<button id="moveForward"
onmousedown="moveForward_onmousedown()"
onmouseup="anyMovementButton_onmouseup()"
onmouseout="anyMovementButton_onmouseout()"
ontouchstart="moveForward_onmousedown()"
ontouchend="anyMovementButton_onmouseup()"
ontouchmove="anyMovementButton_onmouseout()"
ontouchcancel="anyMovementButton_onmouseout()"
oncontextmenu="absorbEvent_()">
<svg width="34" height="34">
<polygon points="2,32 17,2 32,32" style="fill:lime;stroke:purple;stroke-width:3;fill-rule:evenodd;"></polygon>
</svg>
</button>
function moveLeft_onmousedown() {startMovement('left' ); }
function moveReverse_onmousedown() {startMovement('reverse'); }
function moveForward_onmousedown() {startMovement('forward'); }
function moveRight_onmousedown() {startMovement('right' ); }
function tiltUp_onmousedown() { singleMove('up' ); }
function tiltDown_onmousedown() { singleMove('down' ); }
function anyMovementButton_onmouseup() {stopMovement();}
function anyMovementButton_onmouseout() {stopMovement();}
// this function is for preventing context menu on mobile browser
function absorbEvent_(event)
{
var e = event || window.event;
e.preventDefault && e.preventDefault();
e.stopPropagation && e.stopPropagation();
e.cancelBubble = true;
e.returnValue = false;
return false;
}
Related
Sorry if this is a repeated question but i couldn't find any aswers.
Basically, I'm developing a web app that has a button in it.
I want that button to highlight in two different scenarios:
-If the user is on a non-touch (desktop) device, the button will highlight if the mouse is on top of it and get back to normal when it's not.
-If the user is on a touch device WITHOUT a mouse, the button will highlight if it's touched and get back to normal when the touching stops.
The desktop part is working fine, but the touch part have a problem: to get the button back to normal, I have to click somewhere else after clicking it, just stop touching the screen doesn't work.
What I'm doing wrong? Thanks!
JS Code:
if (!this.isTouch) {
document.getElementById("search_button").addEventListener("mouseover", function () {
highlightButton();
});
document.getElementById("search_button").addEventListener("mouseout", function() {
restoreButton();
});
}
else if (window.matchMedia("(any-pointer: none)").matches) {
document.getElementById("search_button").addEventListener("touchstart", function () {
highlightButton();
});
document.getElementById("search_button").addEventListener("touchend", function () {
restoreButton();
});
}
There are several touch events listed as well that may be of use for you, this extends touch devices such as tablets and phones:
el.addEventListener("touchstart", handleStart, false);
el.addEventListener("touchend", handleEnd, false);
el.addEventListener("touchcancel", handleCancel, false);
el.addEventListener("touchmove", handleMove, false);
read more at MDN docs
Try to combine also touchcancel event :
addEventListener( "touchcancel", function ( event ) {
console.log( "BREAK" );
restoreButton();
}, false );
I noticed that these function doesn't work good in Firefox, but does in Chrome.
I use these function in a game in Js to shoot bullet (left mouse click) and to create a fireball all around the player with the right click that burns everyone in a small radius.
document.onclick = function(event) {
if(!player){ //to avoid onclick to be used before calling Player();
return;
}
if(player.canAttack && player.distance >= 80) { //not for sword attack
performAttack(player);
player.canAttack = false;
}
if(player.distance < 80)
performAttack(player);
//event.preventDefault();
}
document.oncontextmenu = function(event) {
//hide default behaviour of right click -> no context menu popup
event.preventDefault();
if(player.obtainedGadjet > 0) {
player.pressingMouseRight = true;
performSpecialAttack(player);
}
}
In the performAttack function I set player.isStopped = true, so my updatePlayer() doesn't change player.x and player.y while he's attacking. The same for the fireball attack. I want my player stays there.
It works in chrome, my player stops, attacks,and then can moves again, but in Firefox if I right click it somethimes acts instead as I have left clicked, so shoot the magic ball, and maybe then the fireball too. Furthermore, my player ignore isStopped = true, it seems like in Firefox oncontextmenu has "lower priority" than other events.
Any idea?
Thanks
Please note that a click event contains information about which button was pressed. You can try yourself with something like:
document.addEventListener('click', function(ev){
console.log(ev.button);
});
And, yes, click events are fired when you right-click, even if you're doing something on related contextmenu events.
So your code should look a bit more like
document.addEventListener('click', function(ev){
if (ev.button === 0) {
// Perform primary action
} else if (ev.button === 2) {
// Perform secondary action
}
});
document.addEventListener('contextmenu', function(ev){
ev.preventDefault();
});
Using the same click event is advisable as said by Ivan. You may also want to read this other discussion here on SO about best practices and why it's not always good to disable default right click behaviour (i.e.: it's not always guaranteed to work).
Mobile browsers require user action to start play on Audio elements. The click event satisfies the requirement, but it appears that touchstart is not an acceptable initiating event in Chrome on Android or iOS. (See below)
Does anyone know where to find a precise definition of the event context required to start play.
(I was attempting to solve a UX problem using the ideas in How to prevent doubletap zoom in iOS and Android. Since posting my original question, I've found a solution that solves the UX problem without using touchstart, but I think the essential question about which events are considered to be user action is still valid.)
Addendum:
It has been suggested that I am mistaken about touchstart events, so for the record, I am providing a trivial test program. Since it requires a real music file and a mobile device, JSFiddle isn't a suitable platform (unless somebody knows how to simulate a touchstart event in a fiddle). To reproduce my observations, edit the javascript to load your own audio file.
<!DOCTYPE html>
<html>
<body>
<br>
<button type="button" id="but1">click</button>
<button type="button" id="but2">touch</button>
<br>
<br>
<span id="message"></span>
<script>
var e;
e = document.getElementById('but1');
e.onclick = click;
e = document.getElementById('but2');
e.ontouchstart = touchstart;
function click() {
alert('caught click');
play();
event.preventDefault();
}
function touchstart() {
alert('caught touchstart');
play();
event.preventDefault();
}
var p;
var t;
function play() {
p = new Audio();
p.src = '/k487.mp3'; // CHANGE THIS
p.preload = 'auto';
p.play();
t = setInterval(report,1000);
}
function report() {
var s = 'Player readyState='+p.readyState+', currentTime='+p.currentTime;
var e = document.getElementById('message');
e.innerHTML = s;
}
</script>
</body>
</html>
When I load this page in Chrome 58 on Android 6.0.1 the Click button works as expected, producing a popup, playing some music and updating the play time.
If I reload the page and touch the Touch button instead, I get the popup, but no music plays. The status display shows a readyState of 4 and a currentTime of 0. In other words, the touchstart event is permitted to load the audio but not to initiate play.
Since I can find no documentation on what events are meant to work, I don't know whether to consider this a Chrome bug, or intended behaviour.
When the play() method on a media element is invoked, the user agent must run the following steps https://html.spec.whatwg.org/multipage/media.html#dom-media-play
step1: if the media element is not allowed to play...
then I wonder the condition that allowed to play, it jump to here https://html.spec.whatwg.org/multipage/media.html#allowed-to-play
it says:
For example, a user agent could require that playback is triggered by user activation, but an exception could be made to allow playback while mute
then came to 'triggered-by-user-activation' here
I think that's the reason:
An algorithm is triggered by user activation if any of the following conditions is true:
The task in which the algorithm is running is currently processing an activation behavior whose click event's isTrusted attribute is true.
change
click
contextmenu
dblclick
mouseup
pointerup
reset
submit
touchend
'touchstart' is not mentioned there.
hope that helps you.
In this page you will found answer on this question .
Use some popup or any animation nice for eye to attract user for tap .
in my memory ... android and iOS have no same behavior it is about max number of audios that we can start buffer with this trick .
var EXE_JUST_ONE_TIME = false;
document.addEventListener("touchstart" , function(e) {
if (EXE_JUST_ONE_TIME == false){
EXE_JUST_ONE_TIME = true;
document.getElementById("LaserShot").play(); // need for play pause just for buffering start
document.getElementById("LaserShot").pause();
// now you can play programmability from js
document.getElementById("LaserShot_CLONE").play();
document.getElementById("LaserShot_CLONE").pause();
}
else if(EXE_JUST_ONE_TIME = true){
document.getElementById("MakeReadyotherAudio1").play();
document.getElementById("MakeReadyotherAudio1").pause();
EXE_JUST_ONE_TIME = 'NOMORE'
}
}
If you have problems i can make you code snippet with working example !
I put in 90% in mobile web dev in event function on begin :
document.getElementById("myAnchor").addEventListener("click", function(event){
event.preventDefault()
});
//Sometimes even if you dont use some event its good to override :
window.addEventListener('touchstart', function(e){
e.preventDefault()
}, false)
window.addEventListener('touchmove', function(e){
e.preventDefault()
}, false)
window.addEventListener('touchend', function(e){
e.preventDefault()
}, false)
window.addEventListener('touchleave', function(e){
e.preventDefault()
}, false)
window.addEventListener('touchcancel', function(e){
e.preventDefault()
}, false)
window.addEventListener('touchenter', function(e){
e.preventDefault()
}, false)
If you wanna you can use this library :
desktop/mobile event optimise for canvas
I'm trying to disable the mouse right click option. So i used contextmenu bind function to prevent it. This works fine but when shift is pressed along with the mosue right click the contextmenu bind function is not triggering but it shows the contextmenu. Means am not getting the alert but it shows the menu.
Here is the code i tried.
$(document).ready(function(){
$(document).bind("contextmenu",function(e){
alert('Context Menu event has fired!');
return false;
});
});
In order to capture the shift button press and mouse right click am doing the below code but this doesn't help. May be i am doing something wrong.
$(document).ready(function(){
$(document).bind("contextmenu",function(e){
alert('Context Menu event has fired!');
return false;
});
var shift = false;
jQuery(document).on("keydown", function(event) {
//check for shift key is pressed
if (event.which === 16) {
shift = true;
}
});
jQuery(document).mousedown(function(e) {
// e.which === 3 is for mouse right click
if (e.which === 3 && shift === true) {
console.log("both action are triggered");
return false; // how to stop the contextmenu action here
}
});
});
I tried giving the e.preventDefault instead of return false. I think the context menu event itself is not triggering in firefox when shift is clicked.
How to disable the mouse right click in this situation for firefox? Any help or clue will be much helpful
JSFIDDLE
NOTE
This is not happening in chrome. This is happening in firefox only. Is this a bug?
It's not a bug, it's a feature!
http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#context-menus
User agents may provide means for bypassing the context menu
processing model, ensuring that the user can always access the UA's
default context menus. For example, the user agent could handle
right-clicks that have the Shift key depressed in such a way that it
does not fire the contextmenu event and instead always shows the
default context menu.
You will not be able to do this in Firefox, by design. It's annoying, especially for complex web apps and games, but it's hard-coded into the browser and there's not way to disable it in javascript (that I know of).
Blame the standards, not Mozilla.
Javascript code to disable mouse right click
<script language="javascript">
document.onmousedown=disableRightclick;
status="Disabled";
function disableRightclick(event)
{
if(event.button==2)
{
alert(status);
return false;
}
}
</script>
On the HTML Body tag set the oncontextmenu property to false.
<body oncontextmenu="return false">
...
</body>
Disclaimer: The link provided is the blog which i have written. Hope
this solves the problem.
I wonder if its possible to prevent double-tap-to-zoom and double-tap-to-center on a specific HTML element in Safari iOS (iPad 1) ?
Because my small HTML5 game forces users to make fast clicks (or taps), which are interpreted as double clicks, and when it happens - the page changes zoom and centers itself.
Detecting double clicks (like in this answer - Safari iPad : prevent zoom on double-tap) smells bad..
Wrong answer #1:
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> - does not suit my purposes, because it will block any zoom.
Wrong answer #2: maybe would .preventDefault() on click event alone be enough for that ? - Does not have any effect.
There's no other way than catching the events you want to prevent, and call preventDefault() on them, as you had already more or less figured out.
Indeed, some particular CSS properties / values may change the global site behavior (fixed width or fixed, for example), but you're not safe from changes to the OS (see fixedhandling change in iOS5), nor do these changes necessarily prevent all behavior (pinch might be off, but not double-tapping).
So, the best way to disable default behavior only for double-tapping is to take advantage of the count of touches iOS provides: if we have only one contact, then we're tapping. Two, this means we're pinching.
The following setup code provides that functionality:
var elm = document.body; // or some selection of the element you want to disable
var catcher = function(evt) {
if (evt.touches.length < 2)
evt.preventDefault();
};
elm.addEventListener('touchstart', catcher, true);
Demo on jsFiddle.
Note: the third parameter (true) to addEventListener means that we want to capture events, that is catch them all, even for our descendant children.
I am preventing doubletaps like this:
var doubleTouchStartTimestamp = 0;
$(document).bind("touchstart", function (event) {
var now = +(new Date());
if (doubleTouchStartTimestamp + 500 > now) {
event.preventDefault();
}
doubleTouchStartTimestamp = now;
});
The elegance lies within the fact, that no timeouts are needed. I only update a timestamp. It only gets compared on the next touchstart. Works for me on iOS 6.
Doubletaps further down the dom are not affected.
The same works without jQuery, as well:
var doubleTouchStartTimestamp = 0;
document.addEventListener("touchstart", function (event) {
var now = +(new Date());
if (doubleTouchStartTimestamp + 500 > now) {
event.preventDefault();
}
doubleTouchStartTimestamp = now;
});
I wrote a jQuery plugin for the same purpose - selectively disabling double-tap zoom on given page elements (in my case, navigation buttons to flip pages) I want to respond to every tap (including double-tap) as a normal click event, with no iOS "touch magic", no matter how fast the user clicks it.
To use it, just run something like $('.prev,.next').nodoubletapzoom(); on the elements you care for. The principle it uses is to listen for consecutive touchstart events on a node within 500ms, and running event.preventDefault() on the second, unless other touches are active at the same time. As that preventDefault consumes both touches, we also synthesize the two "missed" click events for the node, so your intended touch action happens as many times as the user intended.
Apple has a lot of tips with specialized tags for webkit (Safari). View Official Docs
What iOS version/Safari browser are you using? That site most definitely does not let you double-tap. I found some CSS but haven't had time to try it as I'm about to step out:
body {
-webkit-text-size-adjust:none;
margin:0px;
}
div{
clear:both!important;
display:block!important;
width:100%!important;
float:none!important;
margin:0!important;
padding:0!important;
}
You will need to implement a double tap function and preventDefault on the second tap. Here is some tested code that uses global variables that should get you started:
<button id="test1">Double Tap Me!</button>
<div id="test2">EMPTY</div>
var elm1 = document.getElementById('test1');
var elm2 = document.getElementById('test2');
var timeout;
var lastTap = 0;
elm1.addEventListener('touchend', function(event) {
var currentTime = new Date().getTime();
var tapLength = currentTime - lastTap;
clearTimeout(timeout);
if (tapLength < 500 && tapLength > 0) {
elm2.innerHTML = 'Double Tap';
event.preventDefault();
} else {
elm2.innerHTML = 'Single Tap';
timeout = setTimeout(function() {
elm2.innerHTML = 'Single Tap (timeout)';
clearTimeout(timeout);
}, 500);
}
lastTap = currentTime;
});
And a fiddle: http://jsfiddle.net/brettwp/J4djY/
JQuery approach to disable Double Tap Zoom in MVC4
To Disable the double tap (double mouse down) functionality on iOS 1+ you need to catch the touchStart Event and create an override to prevent the zoom.
// Using Single script.js and JQuery.Mobile-1.2.0 UI each page in MVC gets assigned JQuery through delegates so you don't have to do a full refresh of the page allowing you to take advantage of the data-prefetch which loads the page in the DOM when the app loads for the first time
$(document).delegate("#CashRegister", "pageinit", function () {
// To Disable 'Pinch to Zoom' Note: don't implement gester event handlers if you want to
//keep pinch to zoom functionality NOTE: i use this as my pageinit is a delegate of a page
this.addEventListener("gesturestart", gestureStart, false);
this.addEventListener("gesturechange", gestureChange, false);
this.addEventListener("gestureend", gestureEnd, false);
//handle each event by disabling the defaults
function gestureStart(event) {
event.preventDefault();
}
function gestureChange(event) {
event.preventDefault();
}
function gestureEnd(event) {
event.preventDefault();
}
//Recreate Double Tap and preventDefault on it
$(this).bind('touchstart', function preventZoom(e) {
// recreate the double tab functionality
var t2 = e.timeStamp
, t1 = $(this).data('lastTouch') || t2
, dt = t2 - t1
, fingers = e.originalEvent.touches.length;
$(this).data('lastTouch', t2);
if (!dt || dt > 500 || fingers > 1) return; // not double-tap
e.preventDefault(); // double tap - prevent the zoom
// also synthesize click events we just swallowed up
$(this).trigger('click').trigger('click');
});
Actually, .preventDefault() definitely does work... using jQuery:
var InputHandler = {
startEventType : isTouch ? "touchstart" : "mousedown"
}
$(selector).bind(InputHandler.startEventType, function(evnt) {
evnt.preventDefault();
});
Your problem with trying to prevent on .click() is that the browser isn't throwing a "click" element. Safari only fires a click to help simulate a click... But when there's a double tab, Safair doesn't through a "click" element. Your event handler for .click() doesn't ever fire, and therefore the .preventDefault() doesn't fire either.