diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index 1741aa6fd7..a21452d9e7 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -170,6 +170,7 @@ "OpenLayers/Handler/Polygon.js", "OpenLayers/Handler/Feature.js", "OpenLayers/Handler/Drag.js", + "OpenLayers/Handler/Pinch.js", "OpenLayers/Handler/RegularPolygon.js", "OpenLayers/Handler/Box.js", "OpenLayers/Handler/MouseWheel.js", diff --git a/lib/OpenLayers/Events.js b/lib/OpenLayers/Events.js index f19e7f0f74..4e7f51f4d3 100644 --- a/lib/OpenLayers/Events.js +++ b/lib/OpenLayers/Events.js @@ -104,6 +104,20 @@ OpenLayers.Event = { return event.touches && event.touches.length == 1; }, + /** + * Method: isMultiTouch + * Determine whether event was caused by a multi touch + * + * Parameters: + * event - {Event} + * + * Returns: + * {Boolean} + */ + isMultiTouch: function(event) { + return event.touches && event.touches.length > 1; + }, + /** * Method: isLeftClick * Determine whether event was caused by a left click. diff --git a/lib/OpenLayers/Handler/Pinch.js b/lib/OpenLayers/Handler/Pinch.js new file mode 100644 index 0000000000..d50d96ebf2 --- /dev/null +++ b/lib/OpenLayers/Handler/Pinch.js @@ -0,0 +1,227 @@ +/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the Clear BSD license. + * See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Handler.js + */ + +/** + * Class: OpenLayers.Handler.Pinch + * The pinch handler is used to deal with sequences of browser events related + * to pinch gestures. The handler is used by controls that want to know + * when a pinch sequence begins, when a pinch is happening, and when it has + * finished. + * + * Controls that use the pinch handler typically construct it with callbacks + * for 'start', 'move', and 'done'. Callbacks for these keys are + * called when the pinch begins, with each change, and when the pinch is + * done. + * + * Create a new pinch handler with the constructor. + * + * Inherits from: + * - + */ +OpenLayers.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, { + + /** + * Property: started + * {Boolean} When a touchstart event is received, we want to record it, + * but not set 'pinching' until the touchmove get started after + * starting. + */ + started: false, + + /** + * Property: stopDown + * {Boolean} Stop propagation of touchstart events from getting to + * listeners on the same element. Default is true. + */ + stopDown: true, + + /** + * Property: pinching + * {Boolean} + */ + pinching: false, + + /** + * Property: last + * {Object} Object that store informations related to pinch last touch. + */ + last: null, + + /** + * Property: start + * {Object} Object that store informations related to pinch touchstart. + */ + start: null, + + /** + * Constructor: OpenLayers.Handler.Pinch + * Returns OpenLayers.Handler.Pinch + * + * Parameters: + * control - {} The control that is making use of + * this handler. If a handler is being used without a control, the + * handlers setMap method must be overridden to deal properly with + * the map. + * callbacks - {Object} An object containing functions to be called when + * the pinch operation start, change, or is finished. The callbacks + * should expect to receive an object argument, which contains + * information about scale, distance, and position of touch points. + * options - {Object} + */ + initialize: function(control, callbacks, options) { + OpenLayers.Handler.prototype.initialize.apply(this, arguments); + }, + + /** + * Method: touchstart + * Handle touchstart events + * + * Parameters: + * evt - {Event} + * + * Returns: + * {Boolean} Let the event propagate. + */ + touchstart: function(evt) { + var propagate = true; + this.pinching = false; + if (OpenLayers.Event.isMultiTouch(evt)) { + this.started = true; + this.last = this.start = { + distance: this.getDistance(evt.touches), + delta: 0, + scale: 1 + }; + this.callback("start", [evt, this.start]); + propagate = !this.stopDown; + } else { + this.started = false; + this.start = null; + this.last = null; + } + OpenLayers.Event.stop(evt); + return propagate; + }, + + /** + * Method: touchmove + * Handle touchmove events + * + * Parameters: + * evt - {Event} + * + * Returns: + * {Boolean} Let the event propagate. + */ + touchmove: function(evt) { + if (this.started && OpenLayers.Event.isMultiTouch(evt)) { + this.pinching = true; + var current = this.getPinchData(evt); + this.callback("move", [evt, current]); + this.last = current; + } + return true; + }, + + /** + * Method: touchend + * Handle touchend events + * + * Parameters: + * evt - {Event} + * + * Returns: + * {Boolean} Let the event propagate. + */ + touchend: function(evt) { + if (this.started) { + this.started = false; + this.pinching = false; + this.callback("done", [evt, this.start, this.last]); + this.start = null; + this.last = null; + } + return true; + }, + + /** + * Method: activate + * Activate the handler. + * + * Returns: + * {Boolean} The handler was successfully activated. + */ + activate: function() { + var activated = false; + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { + this.pinching = false; + activated = true; + } + return activated; + }, + + /** + * Method: deactivate + * Deactivate the handler. + * + * Returns: + * {Boolean} The handler was successfully deactivated. + */ + deactivate: function() { + var deactivated = false; + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { + this.started = false; + this.pinching = false; + this.start = null; + this.last = null; + deactivated = true; + } + return deactivated; + }, + + /** + * Method: getDistance + * Get the distance in pixels between two touches. + * + * Parameters: + * touches - {Array(Object)} + */ + getDistance: function(touches) { + var t0 = touches[0]; + var t1 = touches[1]; + return Math.sqrt( + Math.pow(t0.clientX - t1.clientX, 2) + + Math.pow(t0.clientY - t1.clientY, 2) + ); + }, + + + /** + * Method: getPinchData + * Get informations about the pinch event. + * + * Parameters: + * evt - {Event} + * + * Returns: + * {Object} Object that contains data about the current pinch. + */ + getPinchData: function(evt) { + var distance = this.getDistance(evt.touches); + var scale = distance / this.start.distance; + return { + distance: distance, + delta: this.last.distance - distance, + scale: scale + }; + }, + + CLASS_NAME: "OpenLayers.Handler.Pinch" +}); + diff --git a/tests/Handler/Pinch.html b/tests/Handler/Pinch.html new file mode 100644 index 0000000000..2924e229f2 --- /dev/null +++ b/tests/Handler/Pinch.html @@ -0,0 +1,264 @@ + + + + + + +
+ + diff --git a/tests/list-tests.html b/tests/list-tests.html index be92040d0f..505d05e404 100644 --- a/tests/list-tests.html +++ b/tests/list-tests.html @@ -118,6 +118,7 @@
  • Handler/Box.html
  • Handler/Click.html
  • Handler/Drag.html
  • +
  • Handler/Pinch.html
  • Handler/Feature.html
  • Handler/Hover.html
  • Handler/Keyboard.html