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); }); });