make click handler work with touch events (closes #2996)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@11201 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
Éric Lemoine
2011-02-21 16:04:34 +00:00
parent 2908fa79e5
commit 7a8f3917c9
2 changed files with 152 additions and 17 deletions
+65 -13
View File
@@ -22,7 +22,6 @@
* - <OpenLayers.Handler> * - <OpenLayers.Handler>
*/ */
OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, { OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
/** /**
* APIProperty: delay * APIProperty: delay
* {Number} Number of milliseconds between clicks before the event is * {Number} Number of milliseconds between clicks before the event is
@@ -90,6 +89,13 @@ OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
*/ */
down: null, down: null,
/**
* Property: last
* {<OpenLayers.Pixel>} The pixel for the last touchmove. This is
* used to
*/
last: null,
/** /**
* Property: rightclickTimerId * Property: rightclickTimerId
* {Number} The id of the right mouse timeout waiting to clear the * {Number} The id of the right mouse timeout waiting to clear the
@@ -118,7 +124,7 @@ OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
// optionally register for mouseup and mousedown // optionally register for mouseup and mousedown
if(this.pixelTolerance != null) { if(this.pixelTolerance != null) {
this.mousedown = function(evt) { this.mousedown = function(evt) {
this.down = evt.xy; this.down = evt;
return true; return true;
}; };
} }
@@ -134,6 +140,19 @@ OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
*/ */
mousedown: null, mousedown: null,
/**
* Method: touchstart
* Handle touchstart.
*
* Returns:
* {Boolean} Continue propagating this event.
*/
touchstart: function(evt) {
this.down = evt;
this.last = null;
return true;
},
/** /**
* Method: mouseup * Method: mouseup
* Handle mouseup. Installed to support collection of right mouse events. * Handle mouseup. Installed to support collection of right mouse events.
@@ -141,16 +160,16 @@ OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
* Returns: * Returns:
* {Boolean} Continue propagating this event. * {Boolean} Continue propagating this event.
*/ */
mouseup: function (evt) { mouseup: function (evt) {
var propagate = true; var propagate = true;
// Collect right mouse clicks from the mouseup // Collect right mouse clicks from the mouseup
// IE - ignores the second right click in mousedown so using // IE - ignores the second right click in mousedown so using
// mouseup instead // mouseup instead
if (this.checkModifiers(evt) && if(this.checkModifiers(evt) &&
this.control.handleRightClicks && this.control.handleRightClicks &&
OpenLayers.Event.isRightClick(evt)) { OpenLayers.Event.isRightClick(evt)) {
propagate = this.rightclick(evt); propagate = this.rightclick(evt);
} }
return propagate; return propagate;
@@ -216,7 +235,10 @@ OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
* {Boolean} Continue propagating this event. * {Boolean} Continue propagating this event.
*/ */
dblclick: function(evt) { dblclick: function(evt) {
if(this.passesTolerance(evt)) { // for touch devices trigger dblclick only for
// "one finger" touch
if(this.passesTolerance(evt) &&
(!evt.lastTouches || evt.lastTouches.length == 1)) {
if(this["double"]) { if(this["double"]) {
this.callback('dblclick', [evt]); this.callback('dblclick', [evt]);
} }
@@ -225,6 +247,30 @@ OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
return !this.stopDouble; return !this.stopDouble;
}, },
/**
* Method: touchmove
* Store position of last move, because touchend event can have
* an empty "touches" property.
*/
touchmove: function(evt) {
this.last = evt;
},
/**
* Method: touchend
* Correctly set event xy property, and add lastTouches to have
* touches property from last touchstart or touchmove
*/
touchend: function(evt) {
if(!evt) {
return false;
}
var last = this.last || this.down;
evt.xy = last.xy;
evt.lastTouches = last.touches;
return evt.xy ? this.click(evt) : false;
},
/** /**
* Method: click * Method: click
* Handle click. * Handle click.
@@ -236,7 +282,12 @@ OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
if(this.passesTolerance(evt)) { if(this.passesTolerance(evt)) {
if(this.timerId != null) { if(this.timerId != null) {
// already received a click // already received a click
this.clearTimer(); if(evt.lastTouches) {
// touch device - we may trigger dblclick
this.dblclick(evt);
} else {
this.clearTimer();
}
} else { } else {
// set the timer, send evt only if single is true // set the timer, send evt only if single is true
//use a clone of the event object because it will no longer //use a clone of the event object because it will no longer
@@ -246,7 +297,7 @@ OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
this.timerId = window.setTimeout( this.timerId = window.setTimeout(
OpenLayers.Function.bind(this.delayedCall, this, clickEvent), OpenLayers.Function.bind(this.delayedCall, this, clickEvent),
this.delay this.delay
); );
} }
} }
return !this.stopSingle; return !this.stopSingle;
@@ -265,10 +316,10 @@ OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
*/ */
passesTolerance: function(evt) { passesTolerance: function(evt) {
var passes = true; var passes = true;
if(this.pixelTolerance != null && this.down) { if(this.pixelTolerance != null && this.down && this.down.xy) {
var dpx = Math.sqrt( var dpx = Math.sqrt(
Math.pow(this.down.x - evt.xy.x, 2) + Math.pow(this.down.xy.x - evt.xy.x, 2) +
Math.pow(this.down.y - evt.xy.y, 2) Math.pow(this.down.xy.y - evt.xy.y, 2)
); );
if(dpx > this.pixelTolerance) { if(dpx > this.pixelTolerance) {
passes = false; passes = false;
@@ -316,6 +367,7 @@ OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
this.clearTimer(); this.clearTimer();
this.down = null; this.down = null;
this.last = null;
deactivated = true; deactivated = true;
} }
return deactivated; return deactivated;
+86 -3
View File
@@ -43,7 +43,7 @@
} }
function test_Handler_Click_events(t) { function test_Handler_Click_events(t) {
t.plan(50); t.plan(80);
var map = new OpenLayers.Map('map'); var map = new OpenLayers.Map('map');
var control = { var control = {
@@ -72,7 +72,7 @@
// list below events that should be handled (events) and those // list below events that should be handled (events) and those
// that should not be handled (nonevents) by the handler // that should not be handled (nonevents) by the handler
var events = ["click", "dblclick", "mousedown", "mouseup", "rightclick"]; var events = ["click", "dblclick", "mousedown", "mouseup", "rightclick", "touchstart", "touchmove", "touchend"];
var nonevents = ["mousemove", "resize", "focus", "blur"]; var nonevents = ["mousemove", "resize", "focus", "blur"];
var handler = new OpenLayers.Handler.Click(control); var handler = new OpenLayers.Handler.Click(control);
// set browser event like properties on the handler // set browser event like properties on the handler
@@ -82,7 +82,7 @@
handler.activate(); handler.activate();
// different listeners registered for pixelTolerance option // different listeners registered for pixelTolerance option
var events = ["click", "dblclick", "mousedown", "mouseup", "rightclick"]; var events = ["click", "dblclick", "mousedown", "mouseup", "rightclick", "touchstart", "touchmove", "touchend"];
var nonevents = ["mousemove", "resize", "focus", "blur"]; var nonevents = ["mousemove", "resize", "focus", "blur"];
var handler = new OpenLayers.Handler.Click(control, {}, { var handler = new OpenLayers.Handler.Click(control, {}, {
pixelTolerance: 2 pixelTolerance: 2
@@ -290,6 +290,89 @@
OpenLayers.Event.isRightClick = temp; OpenLayers.Event.isRightClick = temp;
} }
function test_touch_click(t) {
t.plan(4);
// set up
var log;
var map = new OpenLayers.Map('map');
var control = {map: map};
var callbacks = {
'click': function(e) {
log = {x: e.xy.x, y: e.xy.y,
lastTouches: e.lastTouches};
}
};
var handler = new OpenLayers.Handler.Click(
control, callbacks,
{'single': true, pixelTolerance: null});
// test
log = null;
handler.touchstart({xy: {x: 1, y: 1}, touches: ["foo"]});
handler.touchend({});
t.delay_call(1, function() {
t.ok(log != null, "click callback called");
if(log != null) {
t.eq(log.x, 1, "evt.xy.x as expected");
t.eq(log.y, 1, "evt.xy.y as expected");
t.eq(log.lastTouches, ["foo"], "evt.lastTouches as expected");
}
// tear down
map.destroy();
});
}
function test_touch_dblclick(t) {
t.plan(5);
// set up
var log;
var map = new OpenLayers.Map('map');
var control = {map: map};
var callbacks = {
'click': function(e) {
log.click = {x: e.xy.x, y: e.xy.y,
lastTouches: e.lastTouches};
},
'dblclick': function(e) {
log.dblclick = {x: e.xy.x, y: e.xy.y,
lastTouches: e.lastTouches};
}
};
var handler = new OpenLayers.Handler.Click(
control, callbacks,
{'double': true, pixelTolerance: null});
// test
log = {};
handler.touchstart({xy: {x: 1, y: 1}, touches: ["foo"]});
handler.touchend({});
handler.touchstart({xy: {x: 1, y: 1}, touches: ["foo"]});
handler.touchend({});
t.eq(log.click, undefined, "click callback not called");
t.ok(log.dblclick != undefined, "dblclick callback called");
if(log.dblclick != undefined) {
t.eq(log.dblclick.x, 1, "evt.xy.x as expected");
t.eq(log.dblclick.y, 1, "evt.xy.y as expected");
t.eq(log.dblclick.lastTouches, ["foo"], "evt.lastTouches as expected");
}
// tear down
map.destroy();
}
</script> </script>
</head> </head>