is there a way to detect whether a 'mousedown' is a touch right click (hold the finger about 1 sec in place) or just a normal right click?
I think chrome can do this with "ev.originalEvent.sourceCapabilities.firesTouchEvents". But only chrome.
$('#container').mousedown(function(ev) {
if (ev.button === 2 && ev.comesFromTouch) return false
//...
}
edit:
current situation: after about one second after I pressed down my left mouse button, the browser automaticly triggers a 'mousedown' event with button = 2 (tested in the 'device toolbar' mode in chrome). I want to cancel this.
SOLUTION
If a right mousedown appears between a touchstart and touchend it is a right click on a touch screen.
it works something like this.
function onPcRight() { console.log(1);}
function onTouchRight() { console.log(2);}
$('#container').mousedown(function(ev) {
if (ev.button === BUTTON_RIGHT) {
if ($(this).prop('touchdown')) onTouchRight();
else onPcRight();
}
})
.on('touchstart', function() {
$(this).prop('touchdown', true);
})
.on('touchend', function() {
$(this).prop('touchdown', false);
});
I think you can use setTimeout/clearTimeout to count 1s. The pseudo code:
var global_timer = null;
$('#container').mousedown(function(ev) {
if (ev.button === 2) {
global_timer = setTimeout(fireTouchRightClick, 1000);
}
});
$('#container').mousemove(function(ev) {
cancelTouchRightClick();
});
$('#container').mouseleave(function(ev) {
cancelTouchRightClick();
});
$('#container').mouseup(function(ev) {
if (cancelTouchRightClick() && ev.button === 2) {
fireNormalRightClick();
}
});
function cancelTouchRightClick () {
if (global_timer) {
clearTimeout(global_timer);
global_timer = null;
return true;
}
return false;
}
function fireTouchRightClick () {
global_timer = null;
// TODO touch right click
}
I also found a repo to do mouse holding on Github: https://github.com/dna2github/dna2petal/tree/master/visualization
https://github.com/dna2github/dna2petal/blob/master/samples/visualization.html
Maybe you need to pass button type to the mousehold event callback
Related
This is what I tried:
function move(e)
{
if (e.keyCode==32)
{
up=0;
bottonup=650;
var temp="rect("+up+"px,auto,"+bottomup+"px,auto)";
rect2.style.clip=temp;
}
}
function move2(d){
if (d.keyCode==32)
{
up=0;
bottonup=0;
var temp="rect("+up+"px,auto,"+bottomup+"px,auto)";
rect2.style.clip=temp;
}
}
document.onkeydown=move;
document.onkeyup=move2;
My problem is when I press a button or release a button, the transition starts again and because of that, the animation slips.
When working with animation you usually need some kind of condition logic. For ex: waiting for the animation to finish before triggering it again.
let pressed = false
function down () {
// isAnimationDone -> holding key will not re-trigger animation if it's not finish
// pressed -> wait for the key to be release before being able to call the animation again
if (!pressed && isAnimationDone) {
// do animation
pressed = true
}
}
function up () {
pressed = false
}
Every Events has a type. Check against it.
const EventType = {
keyup: "keyup",
keydown: "keydown"
}
const move = (event) => {
if (event.keyCode === 13) {
if (event.type === EventType.keydown) {
console.log(`${event.code} is pressed.`)
} else if (event.type === EventType.keyup) {
console.log(`${event.code} is released.`)
}
}
}
document.body.onkeydown = move
document.body.onkeyup = move
Press Enter to test the code.
I have a mobile based web application. Currently I am encountering an issue when ajax calls are being made. The wait spinner which is enclosed in a div can be clicked through on the ipad device. The javascript event being triggered is touchstart. Is there anyway to prevent this event from going through normal processing?
Tried to call the following, however it did not work.
Disable
document.ontouchstart = function(e){ e.preventDefault(); }
Enable
document.ontouchstart = function(e){ return true; }
How touchstart is handled
$(document).on('touchstart', function (eventObj) {
//toggle for view-icon
if (eventObj.target.id == "view-icon") {
$("#view-dropdown").toggle();
} else if ($(eventObj.target).hasClass("view-dropdown")) {
$("#view-dropdown").show();
} else {
$("#view-dropdown").hide();
}
});
As user3032973 commented, you can use a touchLocked variable, which is working perfectly.
I have used it in combination with the Cordova Keyboard-Plugin. Scrolling will be disabled the time the keyboard is shown up and reenabled the time the keyboard is hiding:
var touchLocked = false;
Keyboard.onshowing = function () {
touchLocked = true;
};
Keyboard.onhiding = function () {
touchLocked = false;
};
document.ontouchstart = function(e){
if(touchLocked){
e.preventDefault();
}
};
I am trying to implement one event for a short press and a different for a long press. The short press is just doing the default action. The long press works, but also does the default action still. What am I missing?
HTML
<"Label for my Link"
Javascript
$(document).ready(function(){
$('.recordlongpress').each(function() {
var timeout, longtouch;
$(this).mousedown(function() {
timeout = setTimeout(function() {
longtouch = true;
}, 1000);
}).mouseup(function(e) {
if (longtouch) {
e.preventDefault();
$('#popupPanel').popup("open");
return false;
} else {
return;
}
longtouch = false;
clearTimeout(timeout);
});
});
});
I followed the jQuery documentation and was under the impress "preventDefault" should stop the short press default action. Any examples I have found online do not seem to be exactly my situation. I appreciate you taking the time to read this. Thank you for any input.
You're returning from your "mouseup" handler before clearing the timeout and setting "longtouch" to false.
Try:
}).mouseup(function(e) {
var returnval;
if (longtouch) {
e.preventDefault();
$('#popupPanel').popup("open");
returnval = false;
}
longtouch = false;
clearTimeout(timeout);
return returnVal;
});
I'd also clear "longtouch" in the "mousedown" handler. That said, I wouldn't do this with mouse events. I'd use "touchstart" and "touchend". On touch screen devices, "mouse" events are simulated from touch events, and there's a distinct delay involved. (You may also want to detect whether the finger moved during the touch period.)
jsFiddle Demo
In your code these lines are unreachable
longtouch = false;
clearTimeout(timeout);
JS:
$('.recordlongpress').each(function () {
var timeout, longtouch = false;
$(this).mousedown(function () {
timeout = setTimeout(function () {
longtouch = true;
}, 1000);
e.preventDefault();
}).mouseup(function (e) {
clearTimeout(timeout);
if (longtouch == true) {
longtouch = false;
$('body').append("long press" + longtouch);
return false;
} else {
return;
}
});
});
#Pointy lead me towards a working solution for clicking events.
$(document).ready(function(){
$('.recordlongpress').bind('tap', function(event) {
return;
});
$('.recordlongpress').bind('taphold', function(event) {
$('#popupPanel').popup("open");
});
});
Something still needs to be added because upon a long press on my mobile device, the default options screen with the four options; open, save link, copy link URL and select text still pops up as well. I will add on the fix for that once I find it.
We are emulating scrolling of an infinite list and we wish to detect the difference between a single finger scrolling, or the user starting a gesture.
In theory one can keep a count of fingers down in IE10 by +1 for every MSPointerDown and -1 for MSPointerUp events (and/or matching fingers using the event.msPointerId).
In practice, there is at least one bug where IE10 will generate an MSPointerDown event but never ever send the matching MSPointerUp event. (Sorry, I haven't been able to create a simple test case to show this, but I did spend a lot of time checking that the MSPointerUp event is definitely missing. Maybe due to removal of child elements during the touch).
Perhaps use the MSGesture events to see if multiple fingers are down? (I tried this with little success, but maybe someone else has solved it).
Any ideas?
PS: In webkit the equivalent is to check event.touches.length === 1 in the touchstart event (beware that you need an unobvious trick to get this working: document.ontouchstart must have an event registered, and then event.touches.length will be correct for touchstart events registered on other elements).
Make sure you are also keeping track of MSPointerOut. I've found that MSPointerUp will not be called if you let go of the screen whilst outside of the trackable area.
If it helps, I've got a WinJS class I've been using to track multitouch state.
var TouchState = WinJS.Class.define(
function () {
this.pointers = [];
this.primaryPointerId = 0;
this.touchzones = [];
}, {
touchHandler: function (eventType, e) {
if (eventType == "MSPointerDown") {
if (!this.pointers[this.primaryPointerId] || !this.pointers[this.primaryPointerId].touching) {
this.primaryPointerId = e.pointerId;
}
e.target.msSetPointerCapture(e.pointerId);
this.pointers[e.pointerId] = {
touching: true,
coords: {
x: e.currentPoint.rawPosition.x,
y: e.currentPoint.rawPosition.y
}
};
this.checkTouchZones(this.pointers[e.pointerId].coords.x, this.pointers[e.pointerId].coords.y, e);
}
else if (eventType == "MSPointerMove") {
if (this.pointers[e.pointerId]) {
this.pointers[e.pointerId].coords.x = e.currentPoint.rawPosition.x;
this.pointers[e.pointerId].coords.y = e.currentPoint.rawPosition.y;
}
}
else if (eventType == "MSPointerUp") {
if (this.pointers[e.pointerId]) {
this.pointers[e.pointerId].touching = false;
this.pointers[e.pointerId].coords.x = e.currentPoint.rawPosition.x;
this.pointers[e.pointerId].coords.y = e.currentPoint.rawPosition.y;
}
}
else if (eventType == "MSPointerOut") {
if (this.pointers[e.pointerId]) {
this.pointers[e.pointerId].touching = false;
this.pointers[e.pointerId].coords.x = e.currentPoint.rawPosition.x;
this.pointers[e.pointerId].coords.y = e.currentPoint.rawPosition.y;
}
}
},
checkTouchZones: function (x, y, e) {
for (var zoneIndex in this.touchzones) {
var zone = this.touchzones[zoneIndex];
if (x >= zone.hitzone.x1 && x < zone.hitzone.x2 && y > zone.hitzone.y1 && y < zone.hitzone.y2) {
zone.callback(e);
}
}
},
addTouchZone: function (id, hitzone, callback) {
this.touchzones[id] = {
hitzone: hitzone,
callback: callback
};
},
removeTouchZone: function (id) {
this.touchzones[id] = null;
}
});
Is there a way to receive right click mouse events on a Fabric.js canvas?
The following code works only with left click:
canvas.observe('mouse:down', function(){console.log('mouse down'));
NOTE: Most answers above are outdated; this answer applies to the latest Fabric version 2.7.0
Simply enable firing right/middle click events for your Fabric canvas
The config for firing right click and middle click events in the canvas can be found here for fireRightClick and here for fireMiddleClick and are set to false by default. This means right and middle click events are by default disabled.
The parameter stopContextMenu for stopping context menu to show up on the canvas when right clicking can be found here
You can enable these simply by setting the values when creating your canvas:
var canvas = new fabric.Canvas('canvas', {
height: height,
width: width,
fireRightClick: true, // <-- enable firing of right click events
fireMiddleClick: true, // <-- enable firing of middle click events
stopContextMenu: true, // <-- prevent context menu from showing
});
Now your mousedown event will fire for all clicks and you can distinguish them by using the button identifier on the event:
For canvas:
canvas.on('mouse:down', (event) => {
if(event.button === 1) {
console.log("left click");
}
if(event.button === 2) {
console.log("middle click");
}
if(event.button === 3) {
console.log("right click");
}
}
For objects:
object.on('mousedown', (event) => {
if(event.button === 1) {
console.log("left click");
}
if(event.button === 2) {
console.log("middle click");
}
if(event.button === 3) {
console.log("right click");
}
}
When clicking on objects you can reach the "real" mouse dom event through event.e:
if(event.button === 3){
console.log(event.e);
}
I've implemented right click by extending the fabric.Canvas class. Take a look here the _onMouseDown method.
Basically the right mouse down event for an object was disabled in fabricjs by default.
If you want to handle right clicks (on canvas or its objects), then set context menu listener on upper-canvas element. Using canvas method findTarget you can check if any target was clicked and if so, you can check type of the target.
let scope = this;
jQuery(".upper-canvas").on('contextmenu', function (options: any) {
let target: any = scope.canvas.findTarget(options, false);
if (target) {
let type: string = target.type;
if (type === "group") {
console.log('right click on group');
} else {
scope.canvas.setActiveObject(target);
console.log('right click on target, type: ' + type);
}
} else {
scope.canvas.discardActiveObject();
scope.canvas.discardActiveGroup();
scope.canvas.renderAll();
console.log('right click on canvas');
}
options.preventDefault();
});
The way I did this was to listen for a right click event across the entire canvas and match up the x,y coordinates of the click event to the object which is currently sitting at the given location. This solution feels a little like a hack but hey, it works!
$('#my_canvas').bind('contextmenu', function (env) {
var x = env.offsetX;
var y = env.offsetY;
$.each (canvas._objects, function(i, e) {
// e.left and e.top are the middle of the object use some "math" to find the outer edges
var d = e.width / 2;
var h = e.height / 2;
if (x >= (e.left - d) && x <= (e.left+d)) {
if(y >= (e.top - h) && y <= (e.top+h)) {
console.log("clicked canvas obj #"+i);
//TODO show custom menu at x, y
return false; //in case the icons are stacked only take action on one.
}
}
});
return false; //stops the event propigation
});
Here's what I did, which makes use of some built-in fabric object detection code:
$('.upper-canvas').bind('contextmenu', function (e) {
var objectFound = false;
var clickPoint = new fabric.Point(e.offsetX, e.offsetY);
e.preventDefault();
canvas.forEachObject(function (obj) {
if (!objectFound && obj.containsPoint(clickPoint)) {
objectFound = true;
//TODO: whatever you want with the object
}
});
});