2011-08-17 10 views
17

Sto giocando con gli eventi touchstart e touchend sul mio iPhone. Ho creato una pagina di esempio che ha div che se la tocchi e scorri la pagina, dovrebbe restituire le coordinate y delle posizioni di inizio e fine.jQuery (Scorri contro tocco) paginaX e paginaY continua a tornare 0

link: http://jsbin.com/ibemom/2

jQuery:

var touchStartPos; 

$('.theDiv') 
    .bind('touchstart', function(e){ 
    touchStartPos = e.pageY; 
    }) 
    .bind('touchend', function(e){ 
    alert(touchStartPos + ' | ' + e.pageY) 
    }) 

Quando carico la pagina sul mio iPhone, tuttavia, l'avviso mantiene segnalazione entrambi i valori pari a zero. Qualcuno vede qualcosa di sbagliato in quello che ho?

UPDATE:

mi sono imbattuto in questo pezzo di codice nel progetto jQuery Mobile: https://github.com/jquery/jquery-mobile/issues/734

Un commento da esso sporgeva:

// (in iOS event.pageX and event.pageY are always 0) 

non dice perché questo è il caso, ma almeno ho trovato qualcun altro che vede la stessa cosa. Scava attraverso il codice di esempio su quella pagina per vedere se la soluzione è lì.

UPDATE II:

Ebbene, dopo aver guardato attraverso il codice di esempio nel link qui sopra, sembra che questo restituirà un valore effettivo:

e.originalEvent.touches[0].pageY 

Il problema è, ora mi rendo conto che non è ho proprio bisogno. Restituisce l'offset Y dell'area che ho toccato all'interno dell'oggetto che ho allegato all'evento in IN RELAZIONE AL DOCUMENTO HTML ... piuttosto che alla finestra del browser.

Il mio obiettivo è capire da dove sullo schermo è iniziato il tocco e dove è finito ... e quindi confrontare i valori. Se sono abbastanza diversi, allora asseriamo che è stato eseguito uno swipe ... piuttosto che un tocco.

UPDATE III:

sto trovando anche riferimenti a questi esempi:

e.originalEvent.touches[0].pageX 

event.targetTouches[0].pageY 

Anche se non riesco a ottenere quelli a funzionare. Entrambi restituiscono errori non definiti.

UPDATE IV:

Sembra che una soluzione è quello di replicare offset() nel documento stesso. Posso applicare un evento touchend al documento e quindi controllarlo.

Il problema è che il mio evento touchend si innescherà per la prima volta sull'elemento sulla mia pagina e POI lo accenderà sul documento (bubbling). Quindi non posso determinare se è stato un tocco o uno swift PRIMA che ho bisogno di capire cosa fare sull'evento touchend degli oggetti.

ancora riflettendo questo ...

+0

strano, non knwo su cellulari, ma funziona bene con gli scatti http://jsfiddle.net/nH2PU/ – Sinetheta

+1

Speravo che questo non sarebbe stato così tanto di una Stumper. ;) –

+0

La stessa cosa sembra accadere in Android (2.2.2) – NoBugs

risposta

19

Ok la risposta rapida non è possibile rilevare un tocco quando il dito lascia lo schermo (touchend).

Il mio primo esempio dimostra che: http://jsfiddle.net/Y4fHD/

Ora per la soluzione. O chiamalo come vuoi. Forse ha senso non rilevare l'evento touchend perché il tocco ha terminato.

Bind il gestore sull'evento touchmove: http://jsfiddle.net/Y4fHD/1/

var endCoords = {}; 
$(document.body).bind("touchmove", function(event) { 
    endCoords = event.originalEvent.targetTouches[0]; 
}); 

e quindi utilizzare la variabile endCoords di determinare l'ultimo tocco

$(document.body).bind("touchend", function(event) { 
    $('p').text("Your end coords is: x: " + endCoords.pageX + ", y: " + endCoords.pageY); 
}); 

prova Ok per toccare il tuo dispositivo! Quindi l'errore continuerà ad apparire: Perché? Perché non hai spostato il tuo tocco.

Se noi tutti pronti nel touchstart definisce la variabile endCoords siamo lì: http://jsfiddle.net/Y4fHD/2/

var endCoords = {}; 
$(document.body).bind("touchstart touchmove", function(event) { 
    endCoords = event.originalEvent.targetTouches[0]; 
}); 

e quindi utilizzare la variabile endCoords di determinare l'ultimo tocco

$(document.body).bind("touchend", function(event) { 
    $('p').text("Your end coords is: x: " + endCoords.pageX + ", y: " + endCoords.pageY); 
}); 

Ora provate a toccare il vostro dispositivo!

Alcune note finali saranno: make Per variabili: startCoords e endCoords poi utilizzare questi in caso touchend: http://jsfiddle.net/Y4fHD/3/

var startCoords = {}, endCoords = {}; 
$(document.body).bind("touchstart", function(event) { 
    startCoords = endCoords = event.originalEvent.targetTouches[0]; 
}); 
$(document.body).bind("touchmove", function(event) { 
    endCoords = event.originalEvent.targetTouches[0]; 
}); 
$(document.body).bind("touchend", function(event) { 
    $('p').text("Your touch on the axis: " + Math.abs(startCoords.pageX-endCoords.pageX) + "x, " + Math.abs(startCoords.pageY-endCoords.pageY) + "y"); 
}); 

Nota:
Nessuno degli esempi di cui sopra sono testati, speranze funziona!
Math.abs mi dà il valore assoluto di un numero ad esempio: -5 diventa 5

+0

Ho trovato che nell'ultimo esempio, hai scritto il valore assoluto per l'asse Y due volte sulla riga "$ ('p'). Text (" Il tuo tocco su l'asse ... ". – Arabam

+0

@Arabam Questo è stato corretto. Pensare che dopo due anni verrà trovato il tipo di errore :) – andlrc

+0

Grazie per aver menzionato' event.originalEvent' - su Android l'evento originale stava sopprimendo la proprietà targetTouches Interessante, non era un problema per iOS, rendendo più difficile il debug. – jocull

1

Ecco ciò che funziona per me .... pezzo

$('.someClass').bind('touchmove',function(e){ 
    e.preventDefault(); 
    var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0]; 
    var elm = $(this).offset(); 
    var x = touch.pageX - elm.left; 
    var y = touch.pageY - elm.top; 
    if(x < $(this).width() && x > 0){ 
     if(y < $(this).height() && y > 0){ 
       //your code here 
     } 
    } 
}); 
2

C'è semplificata del codice che sono abituato a rilevare strisciata gesti per .myelement, in originale era galleria cursore

$(function() { 
    var diff, tchs, del = 150, 
    clk = function(el){ 
     if (typeof(tchs) !== 'object') return; //we have nothing to do 
     if ((diff - tchs[tchs.length - 1].pageX) < 0) { //swipe right 

     } 
     else if ((diff - tchs[tchs.length - 1].pageX) > 0) { //swipe left 

     } 
    }; 
    $('.myelement').bind('touchstart touchmove', function(ev){ 
      var oev = ev.originalEvent, el = $(this); 
      switch(ev.type.charAt(5)){ 
       case 's': //touch start 
        diff = oev.pageX; 
        window.setTimeout(clk, del, el); 
       break; 
       case 'm': //touch move 
        tchs = oev.touches; 
       break; 
      } 
    }); 
}); 

UPD: a proposito, quando ho usato la versione MobiOne 2.0.0M2 software Testing Center che aveva messo il valore pageX touchend come ci si aspettava, in modo che suoni ba d implementazione che può facilmente essere confusa se non si ha accesso rapido al dispositivo reale.

UPD2: ok, ispirato al feedback positivo :) versione bit complicata realizzata, che consente di rilevare i colpi di destra, sinistra, su e giù, ma ha ancora bisogno di essere ripulito, ma hai avuto l'idea. risposta

$(function() { 
    var ftch, // first touch cache 
    lck = Math.sin(Math.PI/4); //lock value, sine of 45 deg configurable 

    var defSwipeDir = function (el, tchs) { // need define swaping direction, for better UX 
     if (typeof (tchs) !== 'object') return 0; // check if there was any movements since first touch, if no return 0 
     var ltch = tchs[tchs.length - 1], // last touch object 
      dx = ltch.pageX - ftch.pageX, 
      dy = ltch.pageY - ftch.pageY, 
      hyp = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)), 
      sin = dy/hyp, 
      cos = dx/hyp, 
      dir; 

     if (Math.abs(cos) >= lck) { // left or right swape 
      dir = cos > 0 ? 'r' : 'l'; 
     } else { // up or down 
      dir = sin < 0 ? 'u' : 'd'; 
     } 
     el.trigger('swipe', dir); // trigger custom swipe event 
     return dir; // and return direction too 
    } 

    $('.myelementTouchDetection').on('touchstart touchmove swipe', function (ev, d) { 
     var oev = ev.originalEvent, 
      myelementTouchDetection = $(this), 
      dir; // you may know swipes on move event too 

     switch (ev.type) { 
      case 'touchstart': 
       ftch = oev; 
       break; 
      case 'touchmove': 
       dir = defSwipeDir(myelementTouchDetection, oev.touches); 
       return false // cancel default behaiviour 
       break; 
      case 'swipe': 
       switch (d) { 
        case 'r': // swipe right 
         console.log('swipe right'); 
         break; 
        case 'l': // swipe left 
         console.log('swipe left'); 
         break; 
        case 'u': // swipe up 
         console.log('swipe up'); 
         break; 
        case 'd': // swipe down 
         console.log('swipe down'); 
         break; 
       } 
       break; 
     } 
    }) 
}); 
2

NULL, in precedenza, ha lavorato molto per me, tranne che non è possibile assegnare alla startCoords endCoords nella funzione TouchStart-bound. Quindi puntano allo stesso oggetto in modo tale che quando endCoords viene aggiornato, così fa startCoords. Quando l'evento touchend viene attivato, startCoords sarà sempre uguale a endCoords.

Codice aggiornato di seguito. Questo ha funzionato per me su un iPad 3 utilizzando Safari su iOS 6.0. Modificato anche per correggere un errore matematico e di visualizzazione e rimuovere Math.abs() all'interno della funzione associata al tocco. Inoltre, ha aggiunto una chiamata event.preventDefault() all'interno della funzione associata a touchmove, in modo che funzionino anche su Google Chrome su iOS.

var startCoords = {}, endCoords = {}; 

$(document.body).bind("touchstart", function(event) { 
    endCoords = event.originalEvent.targetTouches[0]; 
    startCoords.pageX = event.originalEvent.targetTouches[0].pageX; 
    startCoords.pageY = event.originalEvent.targetTouches[0].pageY; 
}); 

$(document.body).bind("touchmove", function(event) { 
    event.preventDefault(); 
    endCoords = event.originalEvent.targetTouches[0]; 
}); 

$(document.body).bind("touchend", function(event) { 
    $('p').text("Your touch on the axis: " + (endCoords.pageX-startCoords.pageX) + "x, " + (endCoords.pageY-startCoords.pageY) + "y"); 
});