web-dev-qa-db-fra.com

jquery mousewheel: détecter quand la roue s’arrête?

J'utilise Jquery mousewheel plugin et j'aimerais pouvoir détecter le moment où l'utilisateur a fini d'utiliser la molette. Fonctionnalité similaire à celle de l'événement stop: dans le contenu glissable. Quelqu'un peut-il me diriger dans la bonne direction?

20
Moustard

Il n'y a pas vraiment d'événement "stop" ici - vous obtenez un événement lorsque vous do scroll, de sorte que chaque fois qu'un événement de la souris se produit, l'événement est déclenché ... lorsqu'il n'y a rien, vous n'obtenez aucun événement et votre gestionnaire ne sera pas tirer.

Vous pouvez toutefois détecter quand l’utilisateur ne l’a pas utilisé depuis 250 ms, comme ceci:

$("#myElem").mousewheel(function() {
  clearTimeout($.data(this, 'timer'));
  $.data(this, 'timer', setTimeout(function() {
     alert("Haven't scrolled in 250ms!");
     //do something
  }, 250));
});

Vous pouvez essayer ici , tout ce que nous faisons, c'est enregistrer le délai d'attente à chaque utilisation en utilisant $.data() , si vous l'utilisez encore avant la fin du temps imparti, il est effacé ... si quel que soit le code que vous vouliez utiliser, l'utilisateur a "fini" d'utiliser sa molette pour la période de temps que vous testez.

36
Nick Craver

Pour compléter la réponse de Nick Craver:

var wheeldelta = {
  x: 0,
  y: 0
};
var wheeling;
$('#foo').on('mousewheel', function (e) {
  if (!wheeling) {
    console.log('start wheeling!');
  }

  clearTimeout(wheeling);
  wheeling = setTimeout(function() {
    console.log('stop wheeling!');
    wheeling = undefined;

    // reset wheeldelta
    wheeldelta.x = 0;
    wheeldelta.y = 0;
  }, 250);

  wheeldelta.x += e.deltaFactor * e.deltaX;
  wheeldelta.y += e.deltaFactor * e.deltaY;
  console.log(wheeldelta);
});

sorties de défilement:

start wheeling!
Object {x: -1, y: 0}
Object {x: -36, y: 12}
Object {x: -45, y: 12}
Object {x: -63, y: 12}
Object {x: -72, y: 12}
Object {x: -80, y: 12}
Object {x: -89, y: 12}
Object {x: -97, y: 12}
Object {x: -104, y: 12}
Object {x: -111, y: 12}
Object {x: -117, y: 12}
Object {x: -122, y: 12}
Object {x: -127, y: 12}
Object {x: -131, y: 12}
Object {x: -135, y: 12}
Object {x: -139, y: 12}
Object {x: -145, y: 12}
Object {x: -148, y: 12}
Object {x: -152, y: 12}
Object {x: -154, y: 12}
Object {x: -156, y: 12}
Object {x: -157, y: 12}
Object {x: -158, y: 12}
Object {x: -159, y: 12}
Object {x: -161, y: 12}
Object {x: -162, y: 12}
Object {x: -164, y: 12}
Object {x: -166, y: 12}
Object {x: -167, y: 12}
Object {x: -169, y: 12}
stop wheeling!
9
abernier

Voici comment mettre en œuvre votre propre événement d'arrêt de roue.

//initialise the new variables
var wheelMap = new Map;
var deltaXEnded = false;
var deltaYEnded = false;
var previousSwipe = Object;
    previousSwipe.timeStamp = 0;
    previousSwipe.deltaX = 0;
    previousSwipe.deltaY = 0;
var wheelstart = false;

créer un nouvel eventListener pour le wheelstop event

que nous allons appeler à partir de normalWheelEventCallbackFunction ()

var wheelstop = new Event("wheelstop");

ensuite, nous définirons le rappel dans le cas où cet événement serait distribué et ajouterons ensuite l'événement à l'objet window.

function wheelstopcallback(event){
    wheelstart = false;
    console.log("wheel event has ended");
}
window.addEventListener("wheelstop", wheelstopcallback.bind(this));

maintenant, nous définissons l'écouteur d'événement de roue normal ainsi que le rappel que cet écouteur utilisera ...

window.addEventListener("wheel", normalWheelEventCallbackFunction.bind(this));

La fonction de rappel d'événement de roue

function normalWheelEventCallbackFunction(event){
   if(previousSwipe.timeStamp !== 0){
      if(event.timeStamp - previousSwipe.timeStamp < 1000)
         wheelMap.set(event.timeStamp, event);
      else
         wheelMap.clear();
   }
 else{previousSwipe.timeStamp = event.timeStamp;}


  if(event.deltaX > 2 && event.deltaX > previousSwipe.deltaX){
     //forward
     wheelstart = true
  }
  else if(event.deltaX < -2&& event.deltaX < previousSwipe.deltaX){
     //backward
     wheelstart = true;
  }
  else if(event.deltaY > 2 && event.deltaY > previousSwipe.deltaY){
     wheelstart = true;
  }
  else if(event.deltaY < 2 && event.deltaY < previousSwipe.deltaY){
     wheelstart = true;
  }

  if(
     ((event.deltaX === 1 || event.deltaX === 0 || event.deltaX === -1) && ((event.deltaX > 0 && event.deltaX < previousSwipe.deltaX) || (event.deltaX < 0 && event.deltaX > previousSwipe.deltaX)) && wheelstart)
     || (wheelstart && (event.deltaX === 0 && previousSwipe.deltaX === 0))
  )
  {
     deltaXEnded = true;
     console.log("deltaXEnded");
  }
  if(
     (((event.deltaY === 1 || event.deltaY === 0 || event.deltaY === -1) && ((event.deltaY > 0 && event.deltaY < previousSwipe.deltaY) || (event.deltaY < 0 && event.deltaY > previousSwipe.deltaY))) && wheelstart)
     || (wheelstart && (event.deltaY === 0 && previousSwipe.deltaY === 0)))     {
        deltaYEnded = true;
        console.log("deltaYEnded");
     }

     if(deltaXEnded && deltaYEnded){
        deltaXEnded = false;
        deltaYEnded = false;
        window.dispatchEvent(wheelstop);
     }

  previousSwipe.deltaX = event.deltaX;
  previousSwipe.deltaY = event.deltaY;
}

cela peut comporter quelques erreurs, mais dans l'ensemble, la logique est plutôt bonne. Je recommanderais toutefois une solution de secours si vous devez intercepter chaque événement de roue expédié, car il peut y en avoir quelques unes après l'événement «wheelstop».

oh et pour finir, assurez-vous et implémentez un gestionnaire s'il est interrompu par l'événement click ce qui met fin à l'événement wheel ...

function wheelstopdispatch(){
  if(wheelstart)
    window.dispatchEvent(wheelstop);
  }
window.addEventListener("click", wheelstopdispatch);
1
Brandon Roberts

Nick Craver's answer fonctionne bien. Mais cela entraînera un petit retard (de 250 ms) pour exécuter le // do something. Une meilleure option serait d’exécuter vos codes immédiatement et d’attendre delayms avant d’attraper d’autres événements.

Pour ce faire, utilisez une variable globale say processing, initialisez-la avec false et basculez sa valeur avant et après l'exécution du code.

window.processing = false;
$("#myElem").mousewheel(function() {
   if (processing === false) {
     processing = true;
     // do something
     setTimeout(function() {
       processing = false;
     }, 250)); // waiting 250ms to change back to false.
   }
 });
0
musafar006

Voici comment le faire en JavaScript natif:

var _scrollTimeout = null;

function onMouseWheel() {
    var d = ((typeof e.wheelDelta != "undefined") ? (-e.wheelDelta) : e.detail);
    d = 100 * ((d>0)?1:-1);

    console.log("Scroll delta", d);

    clearTimeout(_scrollTimeout);
    _scrollTimeout = setTimeout(function() {
        console.log("Haven't scrolled in 250ms");
    }, 250);
}

window.addEventListener( 'mousewheel', onMouseWheel, false );
window.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
0
Ryan Weiss