diff --git a/lib/OpenLayers/Events.js b/lib/OpenLayers/Events.js index 801225d0d9..1256481bed 100644 --- a/lib/OpenLayers/Events.js +++ b/lib/OpenLayers/Events.js @@ -90,6 +90,20 @@ OpenLayers.Event = { return event.target || event.srcElement; }, + /** + * Method: isSingleTouch + * Determine whether event was caused by a single touch + * + * Parameters: + * event - {Event} + * + * Returns: + * {Boolean} + */ + isSingleTouch: function(event) { + return event.touches && event.touches.length == 1; + }, + /** * Method: isLeftClick * Determine whether event was caused by a left click. @@ -369,7 +383,8 @@ OpenLayers.Events = OpenLayers.Class({ "mouseover", "mouseout", "mousedown", "mouseup", "mousemove", "click", "dblclick", "rightclick", "dblrightclick", - "resize", "focus", "blur" + "resize", "focus", "blur", + "touchstart", "touchmove", "touchend" ], /** @@ -846,10 +861,16 @@ OpenLayers.Events = OpenLayers.Class({ if (!this.element.offsets) { this.element.offsets = OpenLayers.Util.pagePosition(this.element); } + var clientX = evt.clientX; + var clientY = evt.clientY; + if (evt.touches && evt.touches.length > 0) { + clientX = evt.touches[0].clientX; + clientY = evt.touches[0].clientY; + } return new OpenLayers.Pixel( - (evt.clientX + this.element.scrolls[0]) - this.element.offsets[0] + (clientX + this.element.scrolls[0]) - this.element.offsets[0] - this.element.lefttop[0], - (evt.clientY + this.element.scrolls[1]) - this.element.offsets[1] + (clientY + this.element.scrolls[1]) - this.element.offsets[1] - this.element.lefttop[1] ); }, diff --git a/lib/OpenLayers/Handler/Drag.js b/lib/OpenLayers/Handler/Drag.js index 12eca49950..ec32d39d7c 100644 --- a/lib/OpenLayers/Handler/Drag.js +++ b/lib/OpenLayers/Handler/Drag.js @@ -32,11 +32,11 @@ OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { /** * Property: started - * {Boolean} When a mousedown event is received, we want to record it, but - * not set 'dragging' until the mouse moves after starting. + * {Boolean} When a mousedown or touchstart event is received, we want to + * record it, but not set 'dragging' until the mouse moves after starting. */ started: false, - + /** * Property: stopDown * {Boolean} Stop propagation of mousedown events from getting to listeners @@ -131,11 +131,124 @@ OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { } }, + /** + * Method: dragstart + * This private method is factorized from mousedown and touchstart methods + * + * Parameters: + * evt - {Event} The event + * + * Returns: + * {Boolean} Let the event propagate. + */ + dragstart: function (evt) { + var propagate = true; + this.dragging = false; + if (this.checkModifiers(evt) && + (OpenLayers.Event.isLeftClick(evt) || + OpenLayers.Event.isSingleTouch(evt))) { + this.started = true; + this.start = evt.xy; + this.last = evt.xy; + OpenLayers.Element.addClass( + this.map.viewPortDiv, "olDragDown" + ); + this.down(evt); + this.callback("down", [evt.xy]); + OpenLayers.Event.stop(evt); + + if(!this.oldOnselectstart) { + this.oldOnselectstart = document.onselectstart ? + document.onselectstart : OpenLayers.Function.True; + } + document.onselectstart = OpenLayers.Function.False; + + propagate = !this.stopDown; + } else { + this.started = false; + this.start = null; + this.last = null; + } + return propagate; + }, + + /** + * Method: dragmove + * This private method is factorized from mousemove and touchmove methods + * + * Parameters: + * evt - {Event} The event + * + * Returns: + * {Boolean} Let the event propagate. + */ + dragmove: function (evt) { + if (this.started && !this.timeoutId && (evt.xy.x != this.last.x || + evt.xy.y != this.last.y)) { + if(this.documentDrag === true && this.documentEvents) { + if(evt.element === document) { + this.adjustXY(evt); + // do setEvent manually because the documentEvents are not + // registered with the map + this.setEvent(evt); + } else { + this.removeDocumentEvents(); + } + } + if (this.interval > 0) { + this.timeoutId = setTimeout( + OpenLayers.Function.bind(this.removeTimeout, this), + this.interval); + } + this.dragging = true; + this.move(evt); + this.callback("move", [evt.xy]); + if(!this.oldOnselectstart) { + this.oldOnselectstart = document.onselectstart; + document.onselectstart = OpenLayers.Function.False; + } + this.last = this.evt.xy; + } + return true; + }, + + /** + * Method: dragend + * This private method is factorized from mouseup and touchend methods + * + * Parameters: + * evt - {Event} The event + * + * Returns: + * {Boolean} Let the event propagate. + */ + dragend: function (evt) { + if (this.started) { + if(this.documentDrag === true && this.documentEvents) { + this.adjustXY(evt); + this.removeDocumentEvents(); + } + var dragged = (this.start != this.last); + this.started = false; + this.dragging = false; + OpenLayers.Element.removeClass( + this.map.viewPortDiv, "olDragDown" + ); + this.up(evt); + this.callback("up", [evt.xy]); + if(dragged) { + this.callback("done", [evt.xy]); + } + document.onselectstart = this.oldOnselectstart; + } + return true; + }, + /** * The four methods below (down, move, up, and out) are used by subclasses * to do their own processing related to these mouse events. */ - + /** * Method: down * This method is called during the handling of the mouse down event. @@ -146,7 +259,7 @@ OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { */ down: function(evt) { }, - + /** * Method: move * This method is called during the handling of the mouse move event. @@ -192,37 +305,27 @@ OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { * Handle mousedown events * * Parameters: - * evt - {Event} + * evt - {Event} * * Returns: * {Boolean} Let the event propagate. */ - mousedown: function (evt) { - var propagate = true; - this.dragging = false; - if (this.checkModifiers(evt) && OpenLayers.Event.isLeftClick(evt)) { - this.started = true; - this.start = evt.xy; - this.last = evt.xy; - OpenLayers.Element.addClass( - this.map.viewPortDiv, "olDragDown" - ); - this.down(evt); - this.callback("down", [evt.xy]); - OpenLayers.Event.stop(evt); - - if(!this.oldOnselectstart) { - this.oldOnselectstart = (document.onselectstart) ? document.onselectstart : OpenLayers.Function.True; - } - document.onselectstart = OpenLayers.Function.False; - - propagate = !this.stopDown; - } else { - this.started = false; - this.start = null; - this.last = null; - } - return propagate; + mousedown: function(evt) { + return this.dragstart(evt); + }, + + /** + * Method: touchstart + * Handle touchstart events + * + * Parameters: + * evt - {Event} + * + * Returns: + * {Boolean} Let the event propagate. + */ + touchstart: function(evt) { + return this.dragstart(evt); }, /** @@ -230,38 +333,29 @@ OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { * Handle mousemove events * * Parameters: - * evt - {Event} + * evt - {Event} * * Returns: * {Boolean} Let the event propagate. */ - mousemove: function (evt) { - if (this.started && !this.timeoutId && (evt.xy.x != this.last.x || evt.xy.y != this.last.y)) { - if(this.documentDrag === true && this.documentEvents) { - if(evt.element === document) { - this.adjustXY(evt); - // do setEvent manually because the documentEvents are not - // registered with the map - this.setEvent(evt); - } else { - this.removeDocumentEvents(); - } - } - if (this.interval > 0) { - this.timeoutId = setTimeout(OpenLayers.Function.bind(this.removeTimeout, this), this.interval); - } - this.dragging = true; - this.move(evt); - this.callback("move", [evt.xy]); - if(!this.oldOnselectstart) { - this.oldOnselectstart = document.onselectstart; - document.onselectstart = OpenLayers.Function.False; - } - this.last = this.evt.xy; - } - return true; + mousemove: function(evt) { + return this.dragmove(evt); }, - + + /** + * Method: touchmove + * Handle touchmove events + * + * Parameters: + * evt - {Event} + * + * Returns: + * {Boolean} Let the event propagate. + */ + touchmove: function(evt) { + return this.dragmove(evt); + }, + /** * Method: removeTimeout * Private. Called by mousemove() to remove the drag timeout. @@ -275,31 +369,30 @@ OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { * Handle mouseup events * * Parameters: - * evt - {Event} + * evt - {Event} * * Returns: * {Boolean} Let the event propagate. */ - mouseup: function (evt) { - if (this.started) { - if(this.documentDrag === true && this.documentEvents) { - this.adjustXY(evt); - this.removeDocumentEvents(); - } - var dragged = (this.start != this.last); - this.started = false; - this.dragging = false; - OpenLayers.Element.removeClass( - this.map.viewPortDiv, "olDragDown" - ); - this.up(evt); - this.callback("up", [evt.xy]); - if(dragged) { - this.callback("done", [evt.xy]); - } - document.onselectstart = this.oldOnselectstart; - } - return true; + mouseup: function(evt) { + return this.dragend(evt); + }, + + /** + * Method: touchend + * Handle touchend events + * + * Parameters: + * evt - {Event} + * + * Returns: + * {Boolean} Let the event propagate. + */ + touchend: function(evt) { + // override evt.xy with last position since touchend does not have + // any touch position + evt.xy = this.last; + return this.dragend(evt); }, /** @@ -307,7 +400,7 @@ OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { * Handle mouseout events * * Parameters: - * evt - {Event} + * evt - {Event} * * Returns: * {Boolean} Let the event propagate. diff --git a/tests/Handler/Drag.html b/tests/Handler/Drag.html index d9344a9beb..25f644f864 100644 --- a/tests/Handler/Drag.html +++ b/tests/Handler/Drag.html @@ -45,7 +45,7 @@ } function test_Handler_Drag_events(t) { - t.plan(25); + t.plan(40); var map = new OpenLayers.Map('map'); var control = new OpenLayers.Control(); @@ -54,7 +54,8 @@ // list below events that should be handled (events) and those // that should not be handled (nonevents) by the handler - var events = ["mousedown", "mouseup", "mousemove", "mouseout", "click"]; + var events = ["mousedown", "mouseup", "mousemove", "mouseout", "click", + "touchstart", "touchmove", "touchend"]; var nonevents = ["dblclick", "resize", "focus", "blur"]; map.events.registerPriority = function(type, obj, func) { var r = func();