A-Frame/JS mobile "click" fires twice - javascript

I have A-Frame scene with 8 cubes. I put this script after it:
document.addEventListener("touchstart", function(evt){
//console.log(evt);
if (!evt.isTrusted) return;
holded_m = true;
var touches_m = evt.changedTouches;
var touch_m = touches_m[touches_m.length-1]
mousePosX_m = touch_m.pageX;
mousePosY_m = touch_m.pageY;
rotX_m = ent_m.getAttribute("rotation")["x"];
newRotX_m = rotX_m;
newRotY_m = rotY_m;
})
document.addEventListener("touchend", function(evt){
holded_m = false;
rotX_m = newRotX_m;
rotY_m = newRotY_m;
})
document.addEventListener('touchmove', function(evt){
if (!holded_m) {return;}
//console.log(rotX - (mousePosY - evt.screenY)/10);
var touches_m = evt.changedTouches;
var touch_m = touches_m[touches_m.length-1];
newRotX_m = rotX_m - (mousePosY_m - touch_m.pageY)/slowing_m;
newRotY_m = rotY_m - (mousePosX_m - touch_m.pageX)/slowing_m;
ent_m.setAttribute("rotation", newRotX_m.toString() + " " + newRotY_m.toString() + " 0");
});
cube_8_m = document.querySelector("#cube_8_m")
cube_8_m.addEventListener("click", function(evt){
console.log(evt);
if (!clicked_m) {
clicked_m = true;
cube_8_m.emit("out");
desc_div_m.style.display = "block";
desc_header_m.innerHTML = "Some text"
desc_text_m.innerHTML = "Some text"
current_block_href = "https://some.com/"
console.log("out");
}
else {
clicked_m = false;
cube_8_m.emit("in");
desc_div_m.style.display = "none";
console.log("in");
}
})
When I click on selected cube with mouse on desctop - "click" event fires only once as should be. But on mobile devices in 90% cases tapping on cube fires two "clicks". I logged them to console and they are identical, but the second fires ~one second after the first.
I havn't any other click handling in code. I found that touching screen somewhere else, not on cube, holding touch and moving it on cube and releasing then fires one click event. Only one.
I don't know why does it happen, but I want to have one click = one event.

I don't know if this is still helpful for you or not.
Here's a work around solution to prevent triggering click event twice on mobile.
https://glitch.com/edit/#!/profuse-forest-sword
The point is adding
cursor="rayOrigin: mouse; fuseTimeout: 0"

Related

Smoothly movement

I want to make movement while button is clicked : left.
This is for mobile movement...
The problem its its move, but only once. I need to spam clicking button...
Code:
In create :
this.buttonleft.inputEnabled = true;
this.buttonleft.events.onInputDown.add(this.clickMoveLeft, this);
this.buttonleft.mouseDownCallback = false;
this.buttonleft.alpha = false; // Making no visable
Under everything - separate function :
clickMoveLeft: function()
{
if(!this.clickMoveLeft.mouseDownCallback)
{
this.player.body.velocity.x = -160;
this.buttonleft.mouseDownCallback = true;
}
else if (!this.clickMoveLeft.mouseUpCallback)
{
this.player.body.velocity.x = 0;
this.buttonleft.mouseDownCallback = false;
}
I don't know the phaser framework but, knowing how js events works and after a quick search in the docs I'm pretty sure that the .mouseDownCallback callback is fired just once when you click the mouse and isn't continuos.
So you can use the mousedown event to call a function that keep moving what you want to move and the mouseup to stop it.

Removing event listeners before leaving a page

I've developed a javascript drag and drop that mostly uses the standard 'allowdrop', 'drag' and 'drop' events.
I wanted to customise the 'ghosted' dragged object, so I've added a display:none div that get populated with the innerHTML of the draggable element and made visible (display:block;) when the user starts dragging.
The draggable div is absolutely positioned and matches the mouse movements. For this I needed to add 3 event listeners to document.body. They are as follows:
document.body.addEventListener('dragover', function (ev) {
console.log("dragover event triggered");
ev = ev || window.event;
ev.preventDefault();
dragX = ev.pageX;
dragY = ev.pageY;
document.getElementById("dragged-container").style.left = (dragX - dragOffsetX) + "px";
document.getElementById("dragged-container").style.top = (dragY - dragOffsetY - 10) + "px";
if (mostRecentHoveredDropTargetId!="") {
if (dragX<mostRecentHoveredDropTargetRect.left || dragX>mostRecentHoveredDropTargetRect.right || dragY<mostRecentHoveredDropTargetRect.top || dragY>mostRecentHoveredDropTargetRect.bottom) {
document.getElementById(mostRecentHoveredDropTargetId).classList.remove("drop-target-hover");
mostRecentHoveredDropTargetId = "";
}
}
});
document.body.addEventListener('drop', function (ev) {
console.log("drop event triggered");
ev.preventDefault();
var data = ev.dataTransfer.getData("text"); // data set to the id of the draggable element
if (document.getElementById(data)!=null) {
document.getElementById(data).classList.remove("dragged");
document.getElementById("dragged-container").innerHTML = "";
document.getElementById("dragged-container").style.display = "none";
var draggablesClasses = document.getElementById(data).className;
if ((draggablesClasses.indexOf('draggable')==-1 || draggablesClasses=="") && document.getElementById(data).getAttribute('draggable')=="true") {
if (draggablesClasses=="") {
document.getElementById(data).className += "draggable";
} else {
document.getElementById(data).className += " draggable";
}
}
}
});
// resets dragged-container and origin .draggable, when mouse released outside browser window
document.body.addEventListener('mouseleave', function (ev) {
if (jqueryReady==true) {
$(".dragged").addClass("draggable");
$(".dragged").removeClass("dragged");
}
document.getElementById("dragged-container").innerHTML = "";
document.getElementById("dragged-container").style.display = "none";
});
This is all working fine. The drag and drop performs exactly as I expect.
The problem is when I go to another page, obviously those body event listeners are still running.
I've seen a number of answers here and have tried everything I've seen. For starters this:
window.onunload = function() {
console.log("about to clear event listeners prior to leaving page");
document.body.removeEventListener('dragover', null);
document.body.removeEventListener('drop', null);
document.body.removeEventListener('mouseleave', null);
return;
}
...but the console.log output doesn't even appear (let alone the 'null's being wrong, I'm pretty sure). I've also tried this, in the jQuery ready function:
$(window).bind('beforeunload', function(){
console.log("about to clear event listeners prior to leaving page");
document.body.removeEventListener('dragover', null);
document.body.removeEventListener('drop', null);
document.body.removeEventListener('mouseleave', null);
});
..but, once again, the console isn't even receiving that output.
I have also tried both the above with 'onbeforeunload' AND 'onunload'.
What am I doing wrong? - specifically to do with removing these window.body event listeners, I mean (Anything else I can sort out later).
Thanks.
removeEventListener requires the handler
Don't use anonymous functions is the solution.
Like this:
var dragHandler = function (ev) {
console.log("dragover event triggered");
};
document.body.addEventListener('dragover', dragHandler);
and after:
window.onunload = function() {
console.log("about to clear event listeners prior to leaving page");
document.body.removeEventListener('dragover', dragHandler);
return;
}

HTML5 Canvas : How to handle mousedown mouseup mouseclick

I been playing around with html5 canvas and ran into a problem.
canvas.onmousedown = function(e){
dragOffset.x = e.x - mainLayer.trans.x;
dragOffset.y = e.y - mainLayer.trans.y;
canvas.onmousemove = mouseMove;
}
canvas.onmouseup = function(e){
canvas.onmousemove = null;
}
canvas.onmouseclick = mouseClick;
function mouseMove(e){
mainLayer.trans.x = e.x - dragOffset.x;
mainLayer.trans.y = e.y - dragOffset.y;
return false;
}
function mouseClick(e){
// click action
}
In this code, I make my mouse click+drag pan the canvas view by translating by the drag offset. But I also have a click event. Right now, whenever I drag my mouse and let go, it runs both onmouseup AND onclick.
Are there any techniques to make them unique?
A click event happens after a successful mousedown and mouseup on an element. Is there any particular reason you are using click on top of the mouse events? You should be fine with just mousedown/mouseup, click is a convenience event that saves you a little bit of coding.
I would generally do it this way:
var mouseIsDown = false;
canvas.onmousedown = function(e){
dragOffset.x = e.x - mainLayer.trans.x;
dragOffset.y = e.y - mainLayer.trans.y;
mouseIsDown = true;
}
canvas.onmouseup = function(e){
if(mouseIsDown) mouseClick(e);
mouseIsDown = false;
}
canvas.onmousemove = function(e){
if(!mouseIsDown) return;
mainLayer.trans.x = e.x - dragOffset.x;
mainLayer.trans.y = e.y - dragOffset.y;
return false;
}
function mouseClick(e){
// click action
}
in the function mouse move set a boolean to say that a move occured, encompase all the code in mouseup and click with an if statement to check that a drag did not occur. After these if statements and before the end of the functions set the dragging boolean to false.
Try declaring a variable such as clickStatus = 0; and at the start of each function check to ensure the correct value.
if (clickstatus == 0) {
clickstatus =1;
...//function code
};

Detect single tap in UIWebView, but still support text selection and links

I'm using JavaScript to detect taps in a page I'm showing in a UIWebView, like so:
<div id="wrapper">
Apple
</div>
<script>
document.getElementById("wrapper").addEventListener('click', function() {
document.location = 'internal://tap';
}, false);
</script>
I'm intercepting links with my web view delegate, and look for "internal://tap". When I get that, I prevent the web view from navigating, and respond to the tap. However doing this I lose the ability to select text. Tapping the link does still work correctly.
In fact, just adding an event listener for 'click' removes the ability to select text, even if the handler doesn't attempt to change the document location.
Any idea what I'm doing wrong?
Apparently if you put a click listener on an element, you can no longer select text within that element on iOS. My solution was to detect taps using a combination of touchstart, touchmove, and touchend events, along with a timer to ignore multi-taps, and checking the current document selection to make sure a selection event is not going on.
Here's the JS code I used:
SingleTapDetector = function(element, handler) {
this.element = element;
this.handler = handler;
element.addEventListener('touchstart', this, false);
};
SingleTapDetector.prototype.handleEvent = function(event) {
switch (event.type) {
case 'touchstart': this.onTouchStart(event); break;
case 'touchmove': this.onTouchMove(event); break;
case 'touchend': this.onTouchEnd(event); break;
}
};
SingleTapDetector.prototype.onTouchStart = function(event) {
this.element.addEventListener('touchend', this, false);
document.body.addEventListener('touchmove', this, false);
this.startX = this.currentX = event.touches[0].clientX;
this.startY = this.currentY = event.touches[0].clientY;
this.startTime = new Date().getTime();
};
SingleTapDetector.prototype.onTouchMove = function(event) {
this.currentX = event.touches[0].clientX;
this.currentY = event.touches[0].clientY;
};
SingleTapDetector.prototype.onTouchEnd = function(event) {
var that = this;
// Has there been one or more taps in this sequence already?
if (this.tapTimer) {
// Reset the timer to catch any additional taps in this sequence
clearTimeout(this.tapTimer);
this.tapTimer = setTimeout(function() {
that.tapTimer = null;
}, 300);
} else {
// Make sure the user didn't move too much
if (Math.abs(this.currentX - this.startX) < 4 &&
Math.abs(this.currentY - this.startY) < 4) {
// Make sure this isn't a long press
if (new Date().getTime() - this.startTime <= 300) {
// Make sure this tap wasn't part of a selection event
if (window.getSelection() + '' == '') {
// Make sure this tap is in fact a single tap
this.tapTimer = setTimeout(function() {
that.tapTimer = null;
// This is a single tap
that.handler(event);
}, 300);
}
}
}
}
};
new SingleTapDetector(document.body, function(event) {
document.location = "internal://tap";
});
There is no need to use Javascript for this, it's overkill when the UIGestureRecognizerDelegate has adequate methods. All you need to do is make sure that when text selection is taking place, the tap recogniser isn't triggered.
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
BOOL hasTap = ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] ||
[otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]);
BOOL hasLongTouch = ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] ||
[otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]);
if (hasTap && hasLongTouch) {
// user is selecting text
return NO;
}
return YES;
}
That takes care of text selection, and links should work fine anyway (at least they do for me).

How do I handle these events and why is my code not working?

I need to do the following. As soon as the user clicks on a div, i want to save the mouse coordinations while the user is moving the cursor over the div and is holding the left mouse button. When the user leaves the div or releases the left button, i want to stop recording the coordinates. I've got the following code:
$(document).ready(function() {
var coordhdl = new coordinateHandler();
$("#test").mousedown(function(e) {
$("#test").mousemove(function(ee) {
$("#test").mouseup(function(e) {
stopIt = true;
});
if(stopIt == false)
{
coordhdl.addCords(ee.pageX - this.offsetLeft, ee.pageY - this.offsetTop);
}
});
});
});
The problems with this code are:
It records coordinate even when the user only clicked the div without pressing the left button.
It doesn't stop recording the coordinates once it has been clicked.
I am new to Javascript/jQuery, so I don't know very much about it.
Something like this should work. It sets a flag to true/false when the mouse is pressed/released respectively. When the mouse moves, if the flag is set, the coordinates are added:
$(document).ready(function() {
var isDown = false,
coordhdl = new coordinateHandler();
$("#test").mousedown(function() {
isDown = true;
}).mouseup(function() {
isDown = false;
}).mousemove(function(e) {
if(isDown) {
coordhdl.addCords(ee.pageX - this.offsetLeft, ee.pageY - this.offsetTop);
}
});
});
Here's a demo of something similar in action (it simply writes the coordinates to a p element instead of using your coordinateHandler object).
Don't attach the event handlers inside the event handlers. On every mouse move you attach a new mouseup event handler. They don't get overridden, they get appended.
Use a "global" flag instead:
$(document).ready(function() {
var coordhdl = new coordinateHandler(),
recording = false;
$("#test").mousedown(function(e) {
recording = true;
}).mousemove(function(e) {
if(recording) {
coordhdl.addCords(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
}
}).mouseup(function(e) {
recording = false;
});
});
Every time there is a mousedown event, you add a mousemove handler, and every time the mouse moves, you add another mouseup handler. I can't see where the stopIt variable is declared so the scope of this variable may also be an issue. You don't need to nest the handlers, so try it this way.
$(document).ready(function() {
var coordhdl = new coordinateHandler();
var isRecording = false;
$("#test").mousedown(function(e) { isRecording = true })
.mouseup(function(e) { isRecording = false })
.mousemove(function(ee) {
if(isRecording)
{
coordhdl.addCords(ee.pageX - this.offsetLeft, ee.pageY - this.offsetTop);
}
});
});

Categories