Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieving touchstart coordinates in a touchend event

When a touchend event occurs, is it possible to know where the touch began (touchstart co-ordinates)? On first glance, this looks as easy as saving the coordinates during touchstart, but suppose the event is attached to all DOM elements with a particular class (ie. .special). Now consider that I touch two objects with the .special class then lift my finger off one. I can't just look at the last saved value, because it could be the first finger that I lifted up.

How can I retrieve the touchstart coordinates in these circumstances?

like image 233
Casebash Avatar asked Mar 06 '13 06:03

Casebash


2 Answers

On touchstart you can store all the values you may need (like x, y, target, an so on). On touchend you may retrieve all the stored values thanks to the Touch.identifier value which should be unique for each touch.

I have created a proof of concept here: http://jsbin.com/adifit/3/

The code below keeps track of x and y position only, but you can track any of the properties if you need.

The idea behind the code is:

  1. on touchstart create an object and store all the data inside (including the touch ID)
  2. store this object in the array
  3. on touchend check the id of the touch and try to find corresponding object in the array
  4. if found than we're done.

And the code:

var touches = [];
var cons;

$(init);

function init()
{
  cons = $("#console");
  document.getElementById("area").addEventListener("touchstart", onTouchStart);
  document.addEventListener("touchend", onTouchEnd);
  document.addEventListener("touchcancel", onTouchEnd);
}

function onTouchStart(e)
{
  e.preventDefault();
  var touchList = e.changedTouches;
  var touch;
  for(var i = 0; i < touchList.length; i++)
  {
    cons.html(cons.html() + "startX: " + touchList[i].screenX + ", id: " + touchList[i].identifier + "<br/>");
    touch = {x: touchList[i].screenX, y: touchList[i].screenY, id: touchList[i].identifier};
    touches.push(touch);
  }
}

function onTouchEnd(e)
{
  cons.html(cons.html() + "<strong>TouchEnd:</strong><br/>");
  var touchList = e.changedTouches;
  var touch;
  for(var i = 0; i < touchList.length; i++)
  {
    touch = {x: touchList[i].screenX, y: touchList[i].screenY, id: touchList[i].identifier};
    for (var j = touches.length - 1; j >= 0 ; j--)
    {
      if (touches[j].id == touch.id)
      {
        cons.html(cons.html() + "<strong>startX: "+ touches[j].x+ ", id: " + touchList[i].identifier + "</strong><br/>");
        touches.splice(j, 1);
      }
    }
  }
}

The code above uses jQuery, but it is used only for convenience of displaying the results on screen, jQuery is not used for anything else.

like image 83
strah Avatar answered Sep 18 '22 12:09

strah


Different touch events can be connected trough the event.target.

W3C specs on touchmove event:

The target of this event must be the same Element that received the touchstart event when this touch point was placed on the surface, even if the touch point has since moved outside the interactive area of the target element.

So you keep track of the event.target:

document.addEventListener("touchstart", onTouchStart);
document.addEventListener("touchend", onTouchEnd);
document.addEventListener("touchcancel", onTouchCancel);

var targets = []; // create array with all touch targets 
                  // still needs some sort of garbage collection though

function onTouchStart(event){
   targets.push(event.target); // add target to array
}

function onTouchEnd(event){
    // loop through array to find your target
    for (var i = 0; i < targets.length; i++) {
        if (targets[i] == event.target) { //test target
            // this is your match! Do something with this element
            targets[i].splice(i,1); // remove entry after event ends;
        }
    }
}

function onTouchCancel(event){
    // loop through array to find your target
    for (var i = 0; i < targets.length; i++) { 
        if (targets[i] == event.target) { //test target
            // Just delete this event
            targets[i].splice(i,1); // remove entry after event ends;
        }
    }
}  

NOTE: not tested. I see that @Strah has a good solution, mine is a bit simplified and only checks the event.target, not the touch-id. But it demonstrates a similar concept.

like image 28
Justus Romijn Avatar answered Sep 22 '22 12:09

Justus Romijn