J'utilise jQuery.click
pour gérer l'événement de clic de souris sur le graphe de Raphael, alors que j'ai besoin de gérer un événement de souris drag
, le glissement de souris consiste en mousedown
, mouseup
et mousemove
à Raphaël.
Il est difficile de distinguer click
et drag
parce que click
contient également mousedown
& mouseup
, comment distinguer un clic de souris et un glissement de souris en Javascript?
Je pense que la différence est qu’il existe une mousemove
entre mousedown
et mouseup
en un glissement, mais pas en un clic.
Vous pouvez faire quelque chose comme ça:
const element = document.createElement('div')
element.innerHTML = 'test'
document.body.appendChild(element)
let moved
let downListener = () => {
moved = false
}
element.addEventListener('mousedown', downListener)
let moveListener = () => {
moved = true
}
element.addEventListener('mousemove', moveListener)
let upListener = () => {
if (moved) {
console.log('moved')
} else {
console.log('not moved')
}
}
element.addEventListener('mouseup', upListener)
// release memory
element.removeEventListener('mousedown', downListener)
element.removeEventListener('mousemove', moveListener)
element.removeEventListener('mouseup', upListener)
Si vous utilisez déjà jQuery:
var $body = $('body');
$body.on('mousedown', function (evt) {
$body.on('mouseup mousemove', function handler(evt) {
if (evt.type === 'mouseup') {
// click
} else {
// drag
}
$body.off('mouseup mousemove', handler);
});
});
Cela devrait bien fonctionner. Identique à la réponse acceptée (avec jQuery), mais le drapeau isDragging
n'est réinitialisé que si la nouvelle position de la souris diffère de celle de l'événement mousedown
. Contrairement à la réponse acceptée, cela fonctionne sur les versions récentes de Chrome, où mousemove
est déclenché, que la souris ait été déplacée ou non.
var isDragging = false;
var startingPos = [];
$(".selector")
.mousedown(function (evt) {
isDragging = false;
startingPos = [evt.pageX, evt.pageY];
})
.mousemove(function (evt) {
if (!(evt.pageX === startingPos[0] && evt.pageY === startingPos[1])) {
isDragging = true;
}
})
.mouseup(function () {
if (isDragging) {
console.log("Drag");
} else {
console.log("Click");
}
isDragging = false;
startingPos = [];
});
Vous pouvez également ajuster le contrôle des coordonnées dans mousemove
si vous souhaitez ajouter un peu de tolérance (c’est-à-dire traiter les petits mouvements comme des clics, pas comme des traînées).
Comme le souligne mrjrdnthms dans son commentaire sur la réponse acceptée, cela ne fonctionne plus sur Chrome (il déclenche toujours le déplacement de la souris), j'ai adapté la réponse de Gustavo (depuis que jQuery est utilisé) pour Chrome comportement.
var currentPos = [];
$(document).on('mousedown', function (evt) {
currentPos = [evt.pageX, evt.pageY]
$(document).on('mousemove', function handler(evt) {
currentPos=[evt.pageX, evt.pageY];
$(document).off('mousemove', handler);
});
$(document).on('mouseup', function handler(evt) {
if([evt.pageX, evt.pageY].equals(currentPos))
console.log("Click")
else
console.log("Drag")
$(document).off('mouseup', handler);
});
});
La fonction Array.prototype.equals
provient de ceci réponse
var element = document;
Rx.Observable
.merge(
Rx.Observable.fromEvent(element, 'mousedown').mapTo(0),
Rx.Observable.fromEvent(element, 'mousemove').mapTo(1)
)
.sample(Rx.Observable.fromEvent(element, 'mouseup'))
.subscribe(flag => {
console.clear();
console.log(flag ? "drag" : "click");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://unpkg.com/@reactivex/[email protected]/dist/global/Rx.js"></script>
Ceci est un clone direct de ce que @ wong2 a fait dans sa réponse, mais converti en RxJs.
Également utilisation intéressante de sample
. L'opérateur sample
prendra la dernière valeur de la source (le merge
de mousedown
et mousemove
) et l'émettra lorsque l'émetteur observable intérieur (mouseup
) sera émis.
let drag = false;
document.addEventListener('mousedown', () => drag = false);
document.addEventListener('mousemove', () => drag = true);
document.addEventListener('mouseup', () => console.log(drag ? 'drag' : 'click'));
N'a rencontré aucun bogue, comme d'autres l'ont commenté.
Utilisation de jQuery avec un minimum de 5 pixels x/y pour détecter le glissement:
var dragging = false;
$("body").on("mousedown", function(e) {
var x = e.screenX;
var y = e.screenY;
dragging = false;
$("body").on("mousemove", function(e) {
if (Math.abs(x - e.screenX) > 5 || Math.abs(y - e.screenY) > 5) {
dragging = true;
}
});
});
$("body").on("mouseup", function(e) {
$("body").off("mousemove");
console.log(dragging ? "drag" : "click");
});
Si vous voulez filtrer la casse, procédez comme suit:
var moved = false;
$(selector)
.mousedown(function() {moved = false;})
.mousemove(function() {moved = true;})
.mouseup(function(event) {
if (!moved) {
// clicked without moving mouse
}
});
Cette DeltaX et DeltaY comme suggéré par un commentaire dans la réponse acceptée pour éviter l'expérience frustrante lorsque vous essayez de cliquer et d'obtenir une opération de glisser à la place en raison d'un déplacement de souris à un tick.
deltaX = deltaY = 2;//px
var element = document.getElementById('divID');
element.addEventListener("mousedown", function(e){
if (typeof InitPageX == 'undefined' && typeof InitPageY == 'undefined') {
InitPageX = e.pageX;
InitPageY = e.pageY;
}
}, false);
element.addEventListener("mousemove", function(e){
if (typeof InitPageX !== 'undefined' && typeof InitPageY !== 'undefined') {
diffX = e.pageX - InitPageX;
diffY = e.pageY - InitPageY;
if ( (diffX > deltaX) || (diffX < -deltaX)
||
(diffY > deltaY) || (diffY < -deltaY)
) {
console.log("dragging");//dragging event or function goes here.
}
else {
console.log("click");//click event or moving back in delta goes here.
}
}
}, false);
element.addEventListener("mouseup", function(){
delete InitPageX;
delete InitPageY;
}, false);
element.addEventListener("click", function(){
console.log("click");
}, false);
Pour une action publique sur une carte OSM (positionner un marqueur sur un clic), la question était la suivante: 1) comment déterminer la durée de l'activation/désactivation de la souris (vous ne pouvez pas imaginer créer un nouveau marqueur pour chaque clic) et 2) la souris se déplace pendant la descente vers le haut (l'utilisateur glisse la carte).
const map = document.getElementById('map');
map.addEventListener("mousedown", position);
map.addEventListener("mouseup", calculate);
let posX, posY, endX, endY, t1, t2, action;
function position(e) {
posX = e.clientX;
posY = e.clientY;
t1 = Date.now();
}
function calculate(e) {
endX = e.clientX;
endY = e.clientY;
t2 = (Date.now()-t1)/1000;
action = 'inactive';
if( t2 > 0.5 && t2 < 1.5) { // Fixing duration of mouse down->up
if( Math.abs( posX-endX ) < 5 && Math.abs( posY-endY ) < 5 ) { // 5px error on mouse pos while clicking
action = 'active';
// --------> Do something
}
}
console.log('Down = '+posX + ', ' + posY+'\nUp = '+endX + ', ' + endY+ '\nAction = '+ action);
}