diff --git a/build.py b/build.py
index 3c3aa7cb5b..f3bdd9b16a 100755
--- a/build.py
+++ b/build.py
@@ -290,6 +290,7 @@ def examples_star_json(name, match):
"externs/bootstrap.js",
"externs/closure-compiler.js",
"externs/example.js",
+ "externs/fastclick.js",
"externs/geojson.js",
"externs/jquery-1.9.js",
"externs/proj4js.js",
diff --git a/config/examples-all.json b/config/examples-all.json
index 12e017f984..29e51fb47e 100644
--- a/config/examples-all.json
+++ b/config/examples-all.json
@@ -15,6 +15,7 @@
"externs/bootstrap.js",
"externs/closure-compiler.js",
"externs/example.js",
+ "externs/fastclick.js",
"externs/geojson.js",
"externs/jquery-1.9.js",
"externs/proj4js.js",
diff --git a/config/jsdoc/api/template/static/scripts/main.js b/config/jsdoc/api/template/static/scripts/main.js
index 84f6ffb542..9a368453c6 100644
--- a/config/jsdoc/api/template/static/scripts/main.js
+++ b/config/jsdoc/api/template/static/scripts/main.js
@@ -57,8 +57,8 @@ $(function () {
var unstable = $('.unstable');
var stabilityToggle = $('#stability-toggle');
stabilityToggle.change(function() {
- unstable.toggle(!this.checked);
+ unstable.toggleClass('hidden', this.checked);
return false;
});
- unstable.toggle(!stabilityToggle[0].checked);
+ unstable.toggleClass('hidden', stabilityToggle[0].checked);
});
diff --git a/config/jsdoc/api/template/static/styles/jaguar.css b/config/jsdoc/api/template/static/styles/jaguar.css
index c3f55f84b7..b44fadeff4 100644
--- a/config/jsdoc/api/template/static/styles/jaguar.css
+++ b/config/jsdoc/api/template/static/styles/jaguar.css
@@ -372,7 +372,7 @@ footer {
.main .readme table ul li {
margin-bottom: 0;
}
-.unstable {
+.hidden {
display: none;
}
#stability {
diff --git a/config/jsdoc/api/template/tmpl/navigation.tmpl b/config/jsdoc/api/template/tmpl/navigation.tmpl
index fc69e8e64c..7a41bfed9b 100644
--- a/config/jsdoc/api/template/tmpl/navigation.tmpl
+++ b/config/jsdoc/api/template/tmpl/navigation.tmpl
@@ -64,6 +64,23 @@ var self = this;
}
?>
+
diff --git a/examples/mobile-full-screen.html b/examples/mobile-full-screen.html
index e249c4dce5..1afd9087f0 100644
--- a/examples/mobile-full-screen.html
+++ b/examples/mobile-full-screen.html
@@ -18,6 +18,7 @@
+
diff --git a/examples/mobile-full-screen.js b/examples/mobile-full-screen.js
index 986bb92572..22967b7bb6 100644
--- a/examples/mobile-full-screen.js
+++ b/examples/mobile-full-screen.js
@@ -32,3 +32,11 @@ geolocation.once('change:position', function() {
view.setCenter(geolocation.getPosition());
view.setResolution(2.388657133911758);
});
+
+// Use FastClick to eliminate the 300ms delay between a physical tap
+// and the firing of a click event on mobile browsers.
+// See http://updates.html5rocks.com/2013/12/300ms-tap-delay-gone-away
+// for more information.
+$(function() {
+ FastClick.attach(document.body);
+});
diff --git a/externs/fastclick.js b/externs/fastclick.js
new file mode 100644
index 0000000000..676200f2b8
--- /dev/null
+++ b/externs/fastclick.js
@@ -0,0 +1,25 @@
+/**
+ * @fileoverview Externs for FastClick 1.0.3
+ * @see https://github.com/ftlabs/fastclick
+ * @externs
+ */
+
+/**
+ * @type {Object}
+ * @const
+ */
+var FastClick = {};
+
+/**
+ * @typedef {{
+ * touchBoundary: (number|undefined),
+ * tapDelay: (number|undefined)
+ * }}
+ */
+FastClick.AttachOptions;
+
+/**
+ * @param {Element} layer
+ * @param {FastClick.AttachOptions=} opt_options
+ */
+FastClick.attach = function(layer, opt_options) {};
diff --git a/externs/jquery-1.9.js b/externs/jquery-1.9.js
index bf081de308..38d21c0393 100644
--- a/externs/jquery-1.9.js
+++ b/externs/jquery-1.9.js
@@ -36,6 +36,44 @@ var jQuerySelector;
/** @typedef {function(...)|Array.} */
var jQueryCallback;
+/** @typedef {
+ {
+ accepts: (Object.|undefined),
+ async: (?boolean|undefined),
+ beforeSend: (function(jQuery.jqXHR, (jQueryAjaxSettings|Object.))|undefined),
+ cache: (?boolean|undefined),
+ complete: (function(jQuery.jqXHR, string)|undefined),
+ contents: (Object.|undefined),
+ contentType: (?string|undefined),
+ context: (Object., ?>|jQueryAjaxSettings|undefined),
+ converters: (Object.|undefined),
+ crossDomain: (?boolean|undefined),
+ data: (Object., ?>|?string|Array.>|undefined),
+ dataFilter: (function(string, string):Object.,?>|undefined),
+ dataType: (?string|undefined),
+ error: (function(jQuery.jqXHR, string, string)|undefined),
+ global: (?boolean|undefined),
+ headers: (Object., ?>|undefined),
+ ifModified: (?boolean|undefined),
+ isLocal: (?boolean|undefined),
+ jsonp: (?string|undefined),
+ jsonpCallback: (?string|function()|undefined),
+ mimeType: (?string|undefined),
+ password: (?string|undefined),
+ processData: (?boolean|undefined),
+ scriptCharset: (?string|undefined),
+ statusCode: (Object.|undefined),
+ success: (function(?, string, jQuery.jqXHR)|undefined),
+ timeout: (?number|undefined),
+ traditional: (?boolean|undefined),
+ type: (?string|undefined),
+ url: (?string|undefined),
+ username: (?string|undefined),
+ xhr: (function():(ActiveXObject|XMLHttpRequest)|undefined),
+ xhrFields: (Object., ?>|undefined)
+ }} */
+var jQueryAjaxSettings;
+
/**
* @constructor
* @param {(jQuerySelector|Element|Object|Array.|jQuery|string|
@@ -86,105 +124,61 @@ jQuery.prototype.addClass = function(arg1) {};
jQuery.prototype.after = function(arg1, content) {};
/**
- * @param {(string|Object.)} arg1
- * @param {Object.=} settings
+ * @param {(string|jQueryAjaxSettings|Object.)} arg1
+ * @param {(jQueryAjaxSettings|Object.)=} settings
* @return {jQuery.jqXHR}
*/
jQuery.ajax = function(arg1, settings) {};
/**
- * @param {(string|Object.)} arg1
- * @param {Object.=} settings
+ * @param {(string|jQueryAjaxSettings|Object.)} arg1
+ * @param {(jQueryAjaxSettings|Object.)=} settings
* @return {jQuery.jqXHR}
*/
$.ajax = function(arg1, settings) {};
/**
- * @param {function(!jQuery.event,XMLHttpRequest,Object.)} handler
+ * @param {function(!jQuery.event,XMLHttpRequest,(jQueryAjaxSettings|Object.))} handler
* @return {!jQuery}
*/
jQuery.prototype.ajaxComplete = function(handler) {};
/**
- * @param {function(!jQuery.event,jQuery.jqXHR,Object.,*)} handler
+ * @param {function(!jQuery.event,jQuery.jqXHR,(jQueryAjaxSettings|Object.),*)} handler
* @return {!jQuery}
*/
jQuery.prototype.ajaxError = function(handler) {};
/**
- * @param {(string|
- * function(Object.,Object.,jQuery.jqXHR))} dataTypes
- * @param {function(Object.,Object.,jQuery.jqXHR)=} handler
+ * @param {(string|function((jQueryAjaxSettings|Object.),(jQueryAjaxSettings|Object.),jQuery.jqXHR))} dataTypes
+ * @param {function((jQueryAjaxSettings|Object.),(jQueryAjaxSettings|Object.),jQuery.jqXHR)=} handler
*/
jQuery.ajaxPrefilter = function(dataTypes, handler) {};
/**
- * @param {(string|
- * function(Object.,Object.,jQuery.jqXHR))} dataTypes
- * @param {function(Object.,Object.,jQuery.jqXHR)=} handler
+ * @param {(string|function((jQueryAjaxSettings|Object.),(jQueryAjaxSettings|Object.),jQuery.jqXHR))} dataTypes
+ * @param {function((jQueryAjaxSettings|Object.),(jQueryAjaxSettings|Object.),jQuery.jqXHR)=} handler
*/
$.ajaxPrefilter = function(dataTypes, handler) {};
/**
- * @param {function(!jQuery.event,jQuery.jqXHR,Object.)} handler
+ * @param {function(!jQuery.event,jQuery.jqXHR,(jQueryAjaxSettings|Object.))} handler
* @return {!jQuery}
*/
jQuery.prototype.ajaxSend = function(handler) {};
-/** @const */
-jQuery.ajaxSettings = {};
+/** @const {jQueryAjaxSettings|Object.} */
+jQuery.ajaxSettings;
-/** @const */
+/** @const {jQueryAjaxSettings|Object.} */
$.ajaxSettings = {};
-/** @type {Object.} */
-jQuery.ajaxSettings.accepts = {};
-
-/** @type {Object.} */
-$.ajaxSettings.accepts = {};
-
-/** @type {boolean} */
-jQuery.ajaxSettings.async;
-
-/** @type {boolean} */
-$.ajaxSettings.async;
-
-/** @type {Object.} */
-jQuery.ajaxSettings.contents = {};
-
-/** @type {Object.} */
-$.ajaxSettings.contents = {};
-
-/** @type {string} */
-jQuery.ajaxSettings.contentType;
-
-/** @type {string} */
-$.ajaxSettings.contentType;
-
-/** @type {Object.} */
-jQuery.ajaxSettings.converters = {};
-
-/** @type {Object.} */
-$.ajaxSettings.converters = {};
-
/** @type {Object.} */
jQuery.ajaxSettings.flatOptions = {};
/** @type {Object.} */
$.ajaxSettings.flatOptions = {};
-/** @type {boolean} */
-jQuery.ajaxSettings.global;
-
-/** @type {boolean} */
-$.ajaxSettings.global;
-
-/** @type {boolean} */
-jQuery.ajaxSettings.isLocal;
-
-/** @type {boolean} */
-$.ajaxSettings.isLocal;
-
/** @type {boolean} */
jQuery.ajaxSettings.processData;
@@ -197,34 +191,10 @@ jQuery.ajaxSettings.responseFields = {};
/** @type {Object.} */
$.ajaxSettings.responseFields = {};
-/** @type {boolean} */
-jQuery.ajaxSettings.traditional;
-
-/** @type {boolean} */
-$.ajaxSettings.traditional;
-
-/** @type {string} */
-jQuery.ajaxSettings.type;
-
-/** @type {string} */
-$.ajaxSettings.type;
-
-/** @type {string} */
-jQuery.ajaxSettings.url;
-
-/** @type {string} */
-$.ajaxSettings.url;
-
-/** @return {XMLHttpRequest|ActiveXObject} */
-jQuery.ajaxSettings.xhr = function() {};
-
-/** @return {XMLHttpRequest|ActiveXObject} */
-$.ajaxSettings.xhr = function() {};
-
-/** @param {Object.} options */
+/** @param {jQueryAjaxSettings|Object.} options */
jQuery.ajaxSetup = function(options) {};
-/** @param {Object.} options */
+/** @param {jQueryAjaxSettings|Object.} options */
$.ajaxSetup = function(options) {};
/**
@@ -240,7 +210,7 @@ jQuery.prototype.ajaxStart = function(handler) {};
jQuery.prototype.ajaxStop = function(handler) {};
/**
- * @param {function(!jQuery.event,XMLHttpRequest,Object.)} handler
+ * @param {function(!jQuery.event,XMLHttpRequest,(jQueryAjaxSettings|Object.), ?)} handler
* @return {!jQuery}
*/
jQuery.prototype.ajaxSuccess = function(handler) {};
@@ -834,8 +804,9 @@ jQuery.prototype.fadeTo = function(duration, opacity, arg3, callback) {};
jQuery.prototype.fadeToggle = function(duration, easing, callback) {};
/**
- * @param {(jQuerySelector|function(number)|Element|jQuery)} arg1
+ * @param {(jQuerySelector|function(number,Element)|Element|jQuery)} arg1
* @return {!jQuery}
+ * @see http://api.jquery.com/filter/
*/
jQuery.prototype.filter = function(arg1) {};
diff --git a/externs/oli.js b/externs/oli.js
index 1504e0f21d..cf6c31f5a1 100644
--- a/externs/oli.js
+++ b/externs/oli.js
@@ -130,6 +130,7 @@ oli.control.Control = function() {};
oli.control.Control.prototype.setMap = function(map) {};
+
/**
* @type {Object}
*/
@@ -137,6 +138,20 @@ oli.interaction;
+/**
+ * @interface
+ */
+oli.interaction.Interaction = function() {};
+
+/**
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} Whether the map browser event should continue
+ * through the chain of interactions. `false` means stop, `true`
+ * means continue.
+ */
+oli.interaction.Interaction.prototype.handleMapBrowserEvent = function(e) {};
+
+
/**
* @interface
*/
diff --git a/externs/olx.js b/externs/olx.js
index 5f938f19a7..3e731883b0 100644
--- a/externs/olx.js
+++ b/externs/olx.js
@@ -474,7 +474,9 @@ olx.ViewOptions.prototype.constrainRotation;
/**
- * Enable rotation. Default is `true`.
+ * Enable rotation. Default is `true`. If `false` a rotation constraint that
+ * always sets the rotation to zero is used. The `constrainRotation` option
+ * has no effect if `enableRotation` is `false`.
* @type {boolean|undefined}
* @api
*/
diff --git a/src/ol/control/attributioncontrol.js b/src/ol/control/attributioncontrol.js
index c14051509c..6953af7843 100644
--- a/src/ol/control/attributioncontrol.js
+++ b/src/ol/control/attributioncontrol.js
@@ -12,7 +12,6 @@ goog.require('goog.style');
goog.require('ol.Attribution');
goog.require('ol.control.Control');
goog.require('ol.css');
-goog.require('ol.pointer.PointerEventHandler');
@@ -97,10 +96,6 @@ ol.control.Attribution = function(opt_options) {
'title': tipLabel
}, this.labelSpan_);
- var buttonHandler = new ol.pointer.PointerEventHandler(button);
- this.registerDisposable(buttonHandler);
- goog.events.listen(buttonHandler, ol.pointer.EventType.POINTERUP,
- this.handlePointerUp_, false, this);
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
@@ -330,19 +325,7 @@ ol.control.Attribution.prototype.insertLogos_ = function(frameState) {
* @private
*/
ol.control.Attribution.prototype.handleClick_ = function(event) {
- if (event.screenX !== 0 && event.screenY !== 0) {
- return;
- }
- this.handleToggle_();
-};
-
-
-/**
- * @param {ol.pointer.PointerEvent} pointerEvent The event to handle
- * @private
- */
-ol.control.Attribution.prototype.handlePointerUp_ = function(pointerEvent) {
- pointerEvent.browserEvent.preventDefault();
+ event.preventDefault();
this.handleToggle_();
};
diff --git a/src/ol/control/fullscreencontrol.js b/src/ol/control/fullscreencontrol.js
index 6fe367bfaa..8b688e38f2 100644
--- a/src/ol/control/fullscreencontrol.js
+++ b/src/ol/control/fullscreencontrol.js
@@ -10,7 +10,6 @@ goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.control.Control');
goog.require('ol.css');
-goog.require('ol.pointer.PointerEventHandler');
@@ -45,10 +44,7 @@ ol.control.FullScreen = function(opt_options) {
'type': 'button',
'title': tipLabel
});
- var buttonHandler = new ol.pointer.PointerEventHandler(button);
- this.registerDisposable(buttonHandler);
- goog.events.listen(buttonHandler,
- ol.pointer.EventType.POINTERUP, this.handlePointerUp_, false, this);
+
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
@@ -88,19 +84,7 @@ goog.inherits(ol.control.FullScreen, ol.control.Control);
* @private
*/
ol.control.FullScreen.prototype.handleClick_ = function(event) {
- if (event.screenX !== 0 && event.screenY !== 0) {
- return;
- }
- this.handleFullScreen_();
-};
-
-
-/**
- * @param {ol.pointer.PointerEvent} pointerEvent The event to handle
- * @private
- */
-ol.control.FullScreen.prototype.handlePointerUp_ = function(pointerEvent) {
- pointerEvent.browserEvent.preventDefault();
+ event.preventDefault();
this.handleFullScreen_();
};
diff --git a/src/ol/control/overviewmapcontrol.js b/src/ol/control/overviewmapcontrol.js
index 0e8da6cdc8..a7b5abcdae 100644
--- a/src/ol/control/overviewmapcontrol.js
+++ b/src/ol/control/overviewmapcontrol.js
@@ -19,7 +19,6 @@ goog.require('ol.control.Control');
goog.require('ol.coordinate');
goog.require('ol.css');
goog.require('ol.extent');
-goog.require('ol.pointer.PointerEventHandler');
@@ -84,10 +83,6 @@ ol.control.OverviewMap = function(opt_options) {
'title': tipLabel
}, this.labelSpan_);
- var buttonHandler = new ol.pointer.PointerEventHandler(button);
- this.registerDisposable(buttonHandler);
- goog.events.listen(buttonHandler, ol.pointer.EventType.POINTERUP,
- this.handlePointerUp_, false, this);
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
@@ -419,19 +414,7 @@ ol.control.OverviewMap.prototype.calculateCoordinateRotate_ = function(
* @private
*/
ol.control.OverviewMap.prototype.handleClick_ = function(event) {
- if (event.screenX !== 0 && event.screenY !== 0) {
- return;
- }
- this.handleToggle_();
-};
-
-
-/**
- * @param {ol.pointer.PointerEvent} pointerEvent The event to handle
- * @private
- */
-ol.control.OverviewMap.prototype.handlePointerUp_ = function(pointerEvent) {
- pointerEvent.browserEvent.preventDefault();
+ event.preventDefault();
this.handleToggle_();
};
diff --git a/src/ol/control/rotatecontrol.js b/src/ol/control/rotatecontrol.js
index 60c7823cae..8f70495f83 100644
--- a/src/ol/control/rotatecontrol.js
+++ b/src/ol/control/rotatecontrol.js
@@ -11,7 +11,6 @@ goog.require('ol.animation');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.easing');
-goog.require('ol.pointer.PointerEventHandler');
@@ -49,10 +48,6 @@ ol.control.Rotate = function(opt_options) {
'title': tipLabel
}, this.label_);
- var handler = new ol.pointer.PointerEventHandler(button);
- this.registerDisposable(handler);
- goog.events.listen(handler, ol.pointer.EventType.POINTERUP,
- ol.control.Rotate.prototype.handlePointerUp_, false, this);
goog.events.listen(button, goog.events.EventType.CLICK,
ol.control.Rotate.prototype.handleClick_, false, this);
@@ -103,19 +98,7 @@ goog.inherits(ol.control.Rotate, ol.control.Control);
* @private
*/
ol.control.Rotate.prototype.handleClick_ = function(event) {
- if (event.screenX !== 0 && event.screenY !== 0) {
- return;
- }
- this.resetNorth_();
-};
-
-
-/**
- * @param {ol.pointer.PointerEvent} pointerEvent The event to handle
- * @private
- */
-ol.control.Rotate.prototype.handlePointerUp_ = function(pointerEvent) {
- pointerEvent.browserEvent.preventDefault();
+ event.preventDefault();
this.resetNorth_();
};
diff --git a/src/ol/control/zoomcontrol.js b/src/ol/control/zoomcontrol.js
index 5d613a7788..d9ec25bb8d 100644
--- a/src/ol/control/zoomcontrol.js
+++ b/src/ol/control/zoomcontrol.js
@@ -8,7 +8,6 @@ goog.require('ol.animation');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.easing');
-goog.require('ol.pointer.PointerEventHandler');
@@ -47,11 +46,6 @@ ol.control.Zoom = function(opt_options) {
'title': zoomInTipLabel
}, zoomInLabel);
- var inElementHandler = new ol.pointer.PointerEventHandler(inElement);
- this.registerDisposable(inElementHandler);
- goog.events.listen(inElementHandler,
- ol.pointer.EventType.POINTERUP, goog.partial(
- ol.control.Zoom.prototype.handlePointerUp_, delta), false, this);
goog.events.listen(inElement,
goog.events.EventType.CLICK, goog.partial(
ol.control.Zoom.prototype.handleClick_, delta), false, this);
@@ -69,11 +63,6 @@ ol.control.Zoom = function(opt_options) {
'title': zoomOutTipLabel
}, zoomOutLabel);
- var outElementHandler = new ol.pointer.PointerEventHandler(outElement);
- this.registerDisposable(outElementHandler);
- goog.events.listen(outElementHandler,
- ol.pointer.EventType.POINTERUP, goog.partial(
- ol.control.Zoom.prototype.handlePointerUp_, -delta), false, this);
goog.events.listen(outElement,
goog.events.EventType.CLICK, goog.partial(
ol.control.Zoom.prototype.handleClick_, -delta), false, this);
@@ -111,20 +100,7 @@ goog.inherits(ol.control.Zoom, ol.control.Control);
* @private
*/
ol.control.Zoom.prototype.handleClick_ = function(delta, event) {
- if (event.screenX !== 0 && event.screenY !== 0) {
- return;
- }
- this.zoomByDelta_(delta);
-};
-
-
-/**
- * @param {number} delta Zoom delta.
- * @param {ol.pointer.PointerEvent} pointerEvent The event to handle
- * @private
- */
-ol.control.Zoom.prototype.handlePointerUp_ = function(delta, pointerEvent) {
- pointerEvent.browserEvent.preventDefault();
+ event.preventDefault();
this.zoomByDelta_(delta);
};
diff --git a/src/ol/control/zoomtoextentcontrol.js b/src/ol/control/zoomtoextentcontrol.js
index 6f79e2ed7b..0af782407d 100644
--- a/src/ol/control/zoomtoextentcontrol.js
+++ b/src/ol/control/zoomtoextentcontrol.js
@@ -7,7 +7,6 @@ goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.control.Control');
goog.require('ol.css');
-goog.require('ol.pointer.PointerEventHandler');
@@ -40,10 +39,6 @@ ol.control.ZoomToExtent = function(opt_options) {
'title': tipLabel
});
- var buttonHandler = new ol.pointer.PointerEventHandler(button);
- this.registerDisposable(buttonHandler);
- goog.events.listen(buttonHandler, ol.pointer.EventType.POINTERUP,
- this.handlePointerUp_, false, this);
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
@@ -71,19 +66,7 @@ goog.inherits(ol.control.ZoomToExtent, ol.control.Control);
* @private
*/
ol.control.ZoomToExtent.prototype.handleClick_ = function(event) {
- if (event.screenX !== 0 && event.screenY !== 0) {
- return;
- }
- this.handleZoomToExtent_();
-};
-
-
-/**
- * @param {ol.pointer.PointerEvent} pointerEvent The event to handle
- * @private
- */
-ol.control.ZoomToExtent.prototype.handlePointerUp_ = function(pointerEvent) {
- pointerEvent.browserEvent.preventDefault();
+ event.preventDefault();
this.handleZoomToExtent_();
};
diff --git a/src/ol/featureoverlay.js b/src/ol/featureoverlay.js
index bc85d270ad..162d024dac 100644
--- a/src/ol/featureoverlay.js
+++ b/src/ol/featureoverlay.js
@@ -176,6 +176,8 @@ ol.FeatureOverlay.prototype.handleMapPostCompose_ = function(event) {
var frameState = event.frameState;
var pixelRatio = frameState.pixelRatio;
var resolution = frameState.viewState.resolution;
+ var squaredTolerance = ol.renderer.vector.getSquaredTolerance(resolution,
+ pixelRatio);
var i, ii, styles, featureStyleFunction;
this.features_.forEach(function(feature) {
featureStyleFunction = feature.getStyleFunction();
@@ -189,8 +191,7 @@ ol.FeatureOverlay.prototype.handleMapPostCompose_ = function(event) {
ii = styles.length;
for (i = 0; i < ii; ++i) {
ol.renderer.vector.renderFeature(replayGroup, feature, styles[i],
- ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
- feature, this.handleImageChange_, this);
+ squaredTolerance, feature, this.handleImageChange_, this);
}
}, this);
};
diff --git a/src/ol/format/polylineformat.js b/src/ol/format/polylineformat.js
index 07f61873cf..cab6513231 100644
--- a/src/ol/format/polylineformat.js
+++ b/src/ol/format/polylineformat.js
@@ -5,12 +5,17 @@ goog.require('ol.Feature');
goog.require('ol.format.Feature');
goog.require('ol.format.TextFeature');
goog.require('ol.geom.LineString');
+goog.require('ol.geom.flat.flip');
goog.require('ol.geom.flat.inflate');
goog.require('ol.proj');
/**
+ * @classdesc
+ * Feature format for reading and writing data in the Encoded
+ * Polyline Algorithm Format.
+ *
* @constructor
* @extends {ol.format.TextFeature}
* @param {olx.format.PolylineOptions=} opt_options
@@ -250,7 +255,8 @@ ol.format.Polyline.encodeUnsignedInteger = function(num) {
/**
- * Read the feature from the Polyline source.
+ * Read the feature from the Polyline source. The coordinates are assumed to be
+ * in two dimensions and in latitude, longitude order.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
@@ -311,6 +317,8 @@ ol.format.Polyline.prototype.readGeometry;
ol.format.Polyline.prototype.readGeometryFromText =
function(text, opt_options) {
var flatCoordinates = ol.format.Polyline.decodeDeltas(text, 2, this.factor_);
+ ol.geom.flat.flip.flipXY(
+ flatCoordinates, 0, flatCoordinates.length, 2, flatCoordinates);
var coordinates = ol.geom.flat.inflate.coordinates(
flatCoordinates, 0, flatCoordinates.length, 2);
@@ -387,5 +395,7 @@ ol.format.Polyline.prototype.writeGeometryText =
geometry, true, this.adaptOptions(opt_options)));
var flatCoordinates = geometry.getFlatCoordinates();
var stride = geometry.getStride();
+ ol.geom.flat.flip.flipXY(
+ flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates);
return ol.format.Polyline.encodeDeltas(flatCoordinates, stride, this.factor_);
};
diff --git a/src/ol/interaction/drawinteraction.js b/src/ol/interaction/drawinteraction.js
index 3451b5749d..5ce00a70d0 100644
--- a/src/ol/interaction/drawinteraction.js
+++ b/src/ol/interaction/drawinteraction.js
@@ -286,7 +286,7 @@ ol.interaction.Draw.prototype.handlePointerUp = function(event) {
this.startDrawing_(event);
} else if (this.mode_ === ol.interaction.DrawMode.POINT ||
this.atFinish_(event)) {
- this.finishDrawing_(event);
+ this.finishDrawing();
} else {
this.addToDrawing_(event);
}
@@ -481,10 +481,9 @@ ol.interaction.Draw.prototype.addToDrawing_ = function(event) {
/**
* Stop drawing and add the sketch feature to the target layer.
- * @param {ol.MapBrowserEvent} event Event.
- * @private
+ * @api
*/
-ol.interaction.Draw.prototype.finishDrawing_ = function(event) {
+ol.interaction.Draw.prototype.finishDrawing = function() {
var sketchFeature = this.abortDrawing_();
goog.asserts.assert(!goog.isNull(sketchFeature));
var coordinates;
diff --git a/src/ol/interaction/interaction.js b/src/ol/interaction/interaction.js
index 9b41a7d2de..76b15d261b 100644
--- a/src/ol/interaction/interaction.js
+++ b/src/ol/interaction/interaction.js
@@ -33,6 +33,7 @@ ol.interaction.InteractionProperty = {
*
* @constructor
* @extends {ol.Object}
+ * @implements {oli.interaction.Interaction}
* @api
*/
ol.interaction.Interaction = function() {
@@ -76,10 +77,16 @@ ol.interaction.Interaction.prototype.getMap = function() {
/**
+ * Method called by the map to notify the interaction that a browser
+ * event was dispatched on the map. If the interaction wants to handle
+ * that event it can return `false` to prevent the propagation of the
+ * event to other interactions in the map's interactions chain.
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} Whether the map browser event should continue
- * through the chain of interactions. false means stop, true
+ * through the chain of interactions. `false` means stop, `true`
* means continue.
+ * @function
+ * @api
*/
ol.interaction.Interaction.prototype.handleMapBrowserEvent =
goog.abstractMethod;
diff --git a/src/ol/renderer/canvas/canvasmaprenderer.js b/src/ol/renderer/canvas/canvasmaprenderer.js
index cac28502a2..a6c9bb056f 100644
--- a/src/ol/renderer/canvas/canvasmaprenderer.js
+++ b/src/ol/renderer/canvas/canvasmaprenderer.js
@@ -104,21 +104,23 @@ ol.renderer.canvas.Map.prototype.dispatchComposeEvent_ =
var viewState = frameState.viewState;
var resolution = viewState.resolution;
var rotation = viewState.rotation;
+
ol.vec.Mat4.makeTransform2D(this.transform_,
- this.canvas_.width / 2,
- this.canvas_.height / 2,
- pixelRatio / viewState.resolution,
- -pixelRatio / viewState.resolution,
- -viewState.rotation,
+ this.canvas_.width / 2, this.canvas_.height / 2,
+ pixelRatio / resolution, -pixelRatio / resolution,
+ -rotation,
-viewState.center[0], -viewState.center[1]);
+
+ var tolerance = ol.renderer.vector.getTolerance(resolution, pixelRatio);
+ var replayGroup = new ol.render.canvas.ReplayGroup(tolerance, extent,
+ resolution);
+
var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio,
extent, this.transform_, rotation);
- var replayGroup = new ol.render.canvas.ReplayGroup(
- ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,
- resolution);
var composeEvent = new ol.render.Event(type, map, vectorContext,
replayGroup, frameState, context, null);
map.dispatchEvent(composeEvent);
+
replayGroup.finish();
if (!replayGroup.isEmpty()) {
replayGroup.replay(context, extent, pixelRatio, this.transform_,
diff --git a/src/ol/view.js b/src/ol/view.js
index e779d19cee..2a02b6b555 100644
--- a/src/ol/view.js
+++ b/src/ol/view.js
@@ -77,14 +77,19 @@ ol.ViewHint = {
* the "next" resolution. And releasing the fingers after pinch-zooming
* snaps to the closest resolution (with an animation).
*
- * So the *resolution constraint* snaps to specific resolutions. It is
+ * The *resolution constraint* snaps to specific resolutions. It is
* determined by the following options: `resolutions`, `maxResolution`,
* `maxZoom`, and `zoomFactor`. If `resolutions` is set, the other three
* options are ignored. See documentation for each option for more
* information.
*
- * The *rotation constraint* is currently not configurable. It snaps the
- * rotation value to zero when approaching the horizontal.
+ * The *rotation constraint* snaps to specific angles. It is determined
+ * by the following options: `enableRotation` and `constrainRotation`.
+ * By default the rotation value is snapped to zero when approaching the
+ * horizontal.
+ *
+ * The *center constraint* is determined by the `extent` option. By
+ * default the center is not constrained at all.
*
* @constructor
* @extends {ol.Object}
diff --git a/test/spec/ol/format/polylineformat.test.js b/test/spec/ol/format/polylineformat.test.js
index 2c09ff8dfc..1137d7c6c9 100644
--- a/test/spec/ol/format/polylineformat.test.js
+++ b/test/spec/ol/format/polylineformat.test.js
@@ -17,7 +17,10 @@ describe('ol.format.Polyline', function() {
flatPoints = [-120.20000, 38.50000,
-120.95000, 40.70000,
-126.45300, 43.25200];
- encodedFlatPoints = '~ps|U_p~iFnnqC_ulLvxq`@_mqN';
+ flippedFlatPoints = [38.50000, -120.20000,
+ 40.70000, -120.95000,
+ 43.25200, -126.45300];
+ encodedFlatPoints = '_p~iF~ps|U_ulLnnqC_mqNvxq`@';
points3857 = [
ol.proj.transform([-120.20000, 38.50000], 'EPSG:4326', 'EPSG:3857'),
ol.proj.transform([-120.95000, 40.70000], 'EPSG:4326', 'EPSG:3857'),
@@ -42,7 +45,7 @@ describe('ol.format.Polyline', function() {
it('returns expected value', function() {
var encodeDeltas = ol.format.Polyline.encodeDeltas;
- expect(encodeDeltas(flatPoints, 2)).to.eql(encodedFlatPoints);
+ expect(encodeDeltas(flippedFlatPoints, 2)).to.eql(encodedFlatPoints);
});
});
@@ -50,7 +53,7 @@ describe('ol.format.Polyline', function() {
it('returns expected value', function() {
var decodeDeltas = ol.format.Polyline.decodeDeltas;
- expect(decodeDeltas(encodedFlatPoints, 2)).to.eql(flatPoints);
+ expect(decodeDeltas(encodedFlatPoints, 2)).to.eql(flippedFlatPoints);
});
});