2015-11-27 17 views
6

Ho un codice che trascina una linea da (x, y) coordinata a una nuova coordinata del mouse (x, y). Questo funziona bene nei browser desktop, ma per qualche motivo non funziona nei browser mobili. Ho aggiunto gli ascoltatori di eventi di tocco, ma immagino che le coordinate siano un po 'errate. Heres il mio codice:Canvas get touch position sul Web mobile

function getMouse(e) { 
    var element = canvas, offsetX = 0, offsetY = 0; 
    if (element.offsetParent) { 
     do { 
     offsetX += element.offsetLeft; 
     offsetY += element.offsetTop; 
     } while ((element = element.offsetParent)); 
    } 

    mx = (e.pageX - offsetX) - LINE_WIDTH; 
    my =(e.pageY - offsetY)- LINE_WIDTH; 
    } 
    function mouseDown(e){ 
    getMouse(e); 
    clear(fctx); 
    var l = lines.length; 
    for (var i = l-1; i >= 0; i--) { 
     draw(fctx,lines[i]); 
     var imageData = fctx.getImageData(mx, my, 1, 1); 
     if (imageData.data[3] > 0) { 
     selectedObject = lines[i]; 
     isDrag = true; 
     canvas.onmousemove = drag; 
     clear(fctx); 
     } 
    } 
    } 
    function mouseUp(){ 
    isDrag = false; 
    } 
    canvas.onmousedown = mouseDown; 
    canvas.onmouseup = mouseUp; 
    canvas.addEventListener('touchstart', mouseDown, false); 
    canvas.addEventListener('touchend', mouseUp, false); 

si può vedere la parte che lavora qui: http://codepen.io/nirajmchauhan/pen/yYdMJR

risposta

3

eventi Generazione del mouse da eventi touch

OK visto questa domanda qui per un po 'e nessuno è venuta avanti con una risposta darò uno.

Gli eventi di tocco diversi dagli eventi del mouse riguardano molti punti di contatto con l'interfaccia utente. Per adattarsi a questo, gli eventi touch forniscono una serie di punti di contatto. Poiché un mouse non può essere in due posti contemporaneamente, i due metodi di interazione dovrebbero essere gestiti separatamente per la migliore esperienza utente. OP come non chiedi di rilevare se il dispositivo è guidato da un tocco o da un mouse, l'ho lasciato a un'altra persona per chiedere.

gestire sia

Mouse e eventi touch possono coesistere. L'aggiunta di ascoltatori per gli eventi del mouse o tocco su un dispositivo che non ne ha uno o l'altro non costituisce un problema. L'interfaccia di input mancante semplicemente non genera alcun evento. Ciò semplifica l'implementazione di una soluzione trasparente per la tua pagina.

Si tratta dell'interfaccia che preferisci ed emula quell'interfaccia quando l'hardware per esso non è disponibile. In questo caso, emulare il mouse da qualsiasi evento di tocco che viene creato.

Creazione di eventi a livello di programmazione.

Il codice utilizza l'oggetto MouseEvent per creare e inviare eventi. È semplice da usare e gli eventi sono indistinguibili dai veri eventi del mouse. Per una descrizione dettagliata di MouseEvents goto MDN MouseEvent

Alla sua base.

creare un evento clic del mouse e la spedizione al documento

var event = new MouseEvent("click", {'view': window, 'bubbles': true,'cancelable': true}); 
    document.dispatchEvent(event); 

È inoltre possibile inviare l'evento ai singoli elementi.

document.getElementById("someButton").dispatchEvent(event); 

Per ascoltare l'evento è come ascoltare il mouse.

document.getElementById("someButton").addEventListener(function(event){ 
     // your code 
)); 

Il secondo argomento della funzione MouseEvent è dove è possibile aggiungere informazioni supplementari sull'evento. Supponiamo ad esempio clientX e clientY la posizione del mouse o which o buttons per il quale pulsante/i viene premuto.

Se avete mai guardato il mouseEvent saprete che ci sono un sacco di proprietà. Quindi, esattamente ciò che invii nell'evento del mouse dipenderà da ciò che il listener di eventi sta usando.

Toccare gli eventi.

Gli eventi di tocco sono simili al mouse. C'è touchstart, touchmove e touchend. Differiscono nel fatto che forniscono una serie di posizioni, un elemento per ogni punto di contatto. Non sei sicuro di quale sia il massimo ma per questa risposta ci interessa solo uno. Vedi MDN touchEvent per i dettagli completi.

Quello che dobbiamo fare è per gli eventi di tocco che coinvolgono solo un punto di contatto che vogliamo generare eventi di mouse corrispondenti nella stessa posizione. Se l'evento di tocco restituisce più di un punto di contatto, non possiamo sapere su quale sia l'obiettivo previsto, quindi li ignoreremo semplicemente.

function touchEventHandler(event){ 
    if (event.touches.length > 1){ // Ignor multi touch events 
     return; 
    } 
} 

Così ora sappiamo che il tocco di un singolo contatto che possiamo fare per creare gli eventi del mouse sulla base delle informazioni nel tocco eventi.

Nella sua forma più semplice

touch = event.changedTouches[0]; // get the position information 
if(type === "touchmove"){   
    mouseEventType = "mousemove"; // get the name of the mouse event 
            // this touch will emulate 
}else 
if(type === "touchstart"){ 
    mouseEventType = "mousedown";  // mouse event to create 
}else 
if(type === "touchend"){ 
    mouseEventType = "mouseup";  // ignore mouse up if click only 
} 

var mouseEvent = new MouseEvent(// create event 
    mouseEventType, // type of event 
    { 
     'view': event.target.ownerDocument.defaultView, 
     'bubbles': true, 
     'cancelable': true, 
     'screenX':touch.screenX, // get the touch coords 
     'screenY':touch.screenY, // and add them to the 
     'clientX':touch.clientX, // mouse event 
     'clientY':touch.clientY, 
}); 
// send it to the same target as the touch event contact point. 
touch.target.dispatchEvent(mouseEvent); 

Ora i vostri ascoltatori del mouse riceveranno mousedown, mousemove, mouseup eventi quando un utente tocca il dispositivo in un solo punto.

Manca il clic

Tutto bene finora, ma c'è un evento del mouse mancante, che è necessario pure. "onClick" Non sono sicuro che ci sia un evento tattile equivoco e, proprio come esercizio, ho visto che ci sono abbastanza informazioni su ciò che dobbiamo decidere se un insieme di eventi tattili può essere considerato un clic.

Dipenderà da quanto distanti gli eventi di tocco iniziale e finale, più di pochi pixel e il suo trascinamento. Dipenderà anche da quanto tempo. (Anche se non è lo stesso di un mouse) trovo che le persone tendono a toccare per fare clic, mentre un mouse può essere tenuto, invece della conformazione sul rilascio, o trascinare per annullare, questo non è il modo in cui le persone usano l'interfaccia touch.

Così registro l'ora in cui si verifica l'evento touchStart. event.timeStamp e da dove è iniziato. Quindi all'evento touchEnd trovo la distanza che ha spostato e il tempo trascorso da. Se sono entrambi sotto i limiti che ho impostato, genererò anche un evento click del mouse insieme all'evento mouse up.

Questo è il modo di base per convertire gli eventi tattili in eventi del mouse.

po 'di codice

Qui di seguito è una piccola API chiamata mouseTouch che fa ciò che ho appena spiegato. Copre le interazioni di mouse più elementari richieste in una semplice applicazione di disegno.

//        _______    _  
//        |__ __|    | |  
// _ __ ___ ___ _ _ ___ ___| | ___ _ _ ___| |__ 
// | '_ ` _ \/_ \| | |/__|/ _ \ |/ _ \| | | |/ __| '_ \ 
// | | | | | | (_) | |_| \__ \ __/ | (_) | |_| | (__| | | | 
// |_| |_| |_|\___/ \__,_|___/\___|_|\___/ \__,_|\___|_| |_| 
//                
//  
// Demonstration of a simple mouse emulation API using touch events. 

// Using touch to simulate a mouse. 
// Keeping it clean with touchMouse the only pubic reference. 
// See Usage instructions at bottom. 
var touchMouse = (function(){ 
    "use strict"; 
    var timeStart, touchStart, mouseTouch, listeningElement, hypot; 


    mouseTouch = {}; // the public object 
    // public properties. 
    mouseTouch.clickRadius = 3; // if touch start and end within 3 pixels then may be a click 
    mouseTouch.clickTime = 200; // if touch start and end in under this time in ms then may be a click 
    mouseTouch.generateClick = true; // if true simulates onClick event 
            // if false only generate mousedown, mousemove, and mouseup 
    mouseTouch.clickOnly = false; // if true on generate click events 
    mouseTouch.status = "Started."; // just for debugging 



    // ES6 new math function 
    // not sure the extent of support for Math.hypot so hav simple poly fill 
    if(typeof Math.hypot === 'function'){ 
     hypot = Math.hypot; 
    }else{ 
     hypot = function(x,y){ // Untested 
      return Math.sqrt(Math.pow(x,2)+Math.pow(y,2)); 
     }; 
    } 
    // Use the new API and MouseEvent object 
    function triggerMouseEvemt(type,fromTouch,fromEvent){ 
     var mouseEvent = new MouseEvent(
      type, 
      { 
       'view': fromEvent.target.ownerDocument.defaultView, 
       'bubbles': true, 
       'cancelable': true, 
       'screenX':fromTouch.screenX, 
       'screenY':fromTouch.screenY, 
       'clientX':fromTouch.clientX, 
       'clientY':fromTouch.clientY, 
       'offsetX':fromTouch.clientX, // this is for old Chrome 
       'offsetY':fromTouch.clientY, 
       'ctrlKey':fromEvent.ctrlKey, 
       'altKey':fromEvent.altKey, 
       'shiftKey':fromEvent.shiftKey, 
       'metaKey':fromEvent.metaKey, 
       'button':0, 
       'buttons':1, 
      }); 
     // to do. 
     // dispatch returns cancelled you will have to 
     // add code here if needed 
     fromTouch.target.dispatchEvent(mouseEvent); 
    } 

    // touch listener. Listens to Touch start, move and end. 
    // dispatches mouse events as needed. Also sends a click event 
    // if click falls within supplied thresholds and conditions 
    function emulateMouse(event) { 

     var type, time, touch, isClick, mouseEventType, x, y, dx, dy, dist; 
     event.preventDefault(); // stop any default happenings interfering 
     type = event.type ; // the type. 

     // ignore multi touch input 
     if (event.touches.length > 1){ 
      if(touchStart !== undefined){ // don't leave the mouse down 
       triggerMouseEvent("mouseup",event.changedTouches[0],event); 
      } 
      touchStart = undefined; 
      return; 
     } 
     mouseEventType = ""; 
     isClick = false; // default no click 
     // check for each event type I have the most numorus move event first, Good practice to always think about the efficancy for conditional coding. 
     if(type === "touchmove" && !mouseTouch.clickOnly){  // touchMove 
      touch = event.changedTouches[0]; 
      mouseEventType = "mousemove";  // not much to do just move the mouse 
     }else 
     if(type === "touchstart"){ 
      touch = touchStart = event.changedTouches[0]; // save the touch start for dist check 
      timeStart = event.timeStamp; // save the start time 
      mouseEventType = !mouseTouch.clickOnly?"mousedown":"";  // mouse event to create 
     }else 
     if(type === "touchend"){ // end check time and distance 
      touch = event.changedTouches[0]; 
      mouseEventType = !mouseTouch.clickOnly?"mouseup":"";  // ignore mouse up if click only 
      // if click generator active 
      if(touchStart !== undefined && mouseTouch.generateClick){ 
       time = event.timeStamp - timeStart; // how long since touch start 
       // if time is right 
       if(time < mouseTouch.clickTime){ 
        // get the distance from the start touch 
        dx = touchStart.clientX-touch.clientX; 
        dy = touchStart.clientY-touch.clientY; 
        dist = hypot(dx,dy); 
        if(dist < mouseTouch.clickRadius){ 
         isClick = true; 
        } 
       } 
      } 
     } 
     // send mouse basic events if any 
     if(mouseEventType !== ""){ 
      // send the event 
      triggerMouseEvent(mouseEventType,touch,event); 
     } 
     // if a click also generates a mouse click event 
     if(isClick){ 
      // generate mouse click 
      triggerMouseEvent("click",touch,event); 
     } 
    } 

    // remove events 
    function removeTouchEvents(){ 
     listeningElement.removeEventListener("touchstart", emulateMouse); 
     listeningElement.removeEventListener("touchend", emulateMouse); 
     listeningElement.removeEventListener("touchmove", emulateMouse); 
     listeningElement = undefined; 

    } 

    // start adds listeners and makes it all happen. 
    // element is optional and will default to document. 
    // or will Listen to element. 
    function startTouchEvents(element){ 
     if(listeningElement !== undefined){ // untested 
      // throws to stop cut and past useage of this example code. 
      // Overwriting the listeningElement can result in a memory leak. 
      // You can remove this condition block and it will work 
      // BUT IT IS NOT RECOGMENDED 

      throw new ReferanceError("touchMouse says!!!! API limits functionality to one element."); 
     } 
     if(element === undefined){ 
      element = document; 
     } 
     listeningElement = element; 
     listeningElement.addEventListener("touchstart", emulateMouse); 
     listeningElement.addEventListener("touchend", emulateMouse); 
     listeningElement.addEventListener("touchmove", emulateMouse); 
    } 

    // add the start event to public object. 
    mouseTouch.start = startTouchEvents; 
    // stops event listeners and remove them from the DOM 
    mouseTouch.stop = removeTouchEvents; 

    return mouseTouch; 

})(); 











// How to use 

touchMouse.start(); // done using defaults will emulate mouse on the entier page 

// For one element and only clicks 
// HTML 
<input value="touch click me" id="touchButton" type="button"></input> 
// Script 
var el = document.getElementById("touchButton"); 
if(el !== null){ 
    touchMouse.clickOnly = true; 
    touchMouse.start(el); 
} 

// For drawing on a canvas 
<canvas id="touchCanvas"></canvas> 
// script 
var el = document.getElementById("touchButton"); 
if(el !== null){ 
    touchMouse.generateClick = false; // no mouse clicks please 
    touchMouse.start(el); 
} 

// For switching elements call stop then call start on the new element 
// warning touchMouse retained a reference to the element you 
// pass it with start. Dereferencing touchMouse will not delete it. 
// Once you have called start you must call stop in order to delete it. 

// API 
//--------------------------------------------------------------- 
// To dereference call the stop method if you have called start . Then dereference touchMouse 
// Example 
touchMouse.stop(); 
touchMouse = undefined; 


// Methods. 
//--------------------------------------------------------------- 
// touchMouse.start(element); // element optional. Element is the element to attach listeners to. 
           // Calling start a second time without calling stop will 
           // throw a reference error. This is to stop memory leaks. 
           // YOU Have been warned... 

// touchMouse.stop();   // removes listeners and dereferences any DOM objects held 
//--------------------------------------------------------------- 
// Properties 
// mouseTouch.clickRadius = 3; // Number. Default 3. If touch start and end within 3 pixels then may be a click 
// mouseTouch.clickTime = 200; // Number. Default 200. If touch start and end in under this time in ms then may be a click 
// mouseTouch.generateClick; // Boolean. Default true. If true simulates onClick event 
//         // if false only generate mousedown, mousemove, and mouseup 
// mouseTouch.clickOnly;  // Boolean. Default false. If true only generate click events Default false 
// mouseTouch.status;   // String. Just for debugging kinda pointless really. 

Quindi spero che ti aiuti con il tuo codice.

Problemi correlati