diff --git a/bin/check-example.js b/bin/check-example.js new file mode 100644 index 0000000000..7995118519 --- /dev/null +++ b/bin/check-example.js @@ -0,0 +1,30 @@ +// +// A PhantomJS script used to check that the hosted examples load +// without errors. This script is executed by the build tool's +// check-examples target. +// +var args = require('system').args; +if (args.length != 2) { + phantom.exit(2); +} +var examplePath = args[1]; +var page = require('webpage').create(); +page.onError = function(msg, trace) { + var msgStack = ['JavaScript ERROR: ' + msg]; + if (trace) { + msgStack.push('TRACE:'); + trace.forEach(function(t) { + msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function + '")' : '')); + }); + } + console.error(msgStack.join('\n')); + phantom.exit(1); +}; +page.open(examplePath, function(s) { + var exitCode = 0; + if (s != 'success') { + exitCode = 1; + console.error('PAGE LOAD ERROR'); + } + phantom.exit(exitCode); +}); diff --git a/build.py b/build.py index 4fb0b399f5..9494b18f1b 100755 --- a/build.py +++ b/build.py @@ -95,7 +95,7 @@ def report_sizes(t): virtual('all', 'build-all', 'build', 'examples', 'precommit') -virtual('precommit', 'lint', 'build-all', 'test', 'build', 'build-examples', 'doc') +virtual('precommit', 'lint', 'build-all', 'test', 'build', 'build-examples', 'check-examples', 'doc') virtual('build', 'build/ol.css', 'build/ol.js', 'build/ol-simple.js', 'build/ol-whitespace.js') @@ -263,7 +263,7 @@ def _strip_comments(lines): yield line -@target('build/check-requires-timestamp', SRC, INTERNAL_SRC, EXTERNAL_SRC, EXAMPLES_SRC) +@target('build/check-requires-timestamp', SRC, INTERNAL_SRC, EXTERNAL_SRC, EXAMPLES_SRC, SPEC) def build_check_requires_timestamp(t): unused_count = 0 all_provides = set() @@ -273,7 +273,8 @@ def build_check_requires_timestamp(t): require_linenos = {} uses = set() lineno = 0 - for line in open(filename): + lines = open(filename).readlines() + for line in lines: lineno += 1 m = re.match(r'goog.provide\(\'(.*)\'\);', line) if m: @@ -283,6 +284,7 @@ def build_check_requires_timestamp(t): if m: require_linenos[m.group(1)] = lineno continue + for line in lines: for require in require_linenos.iterkeys(): if require in line: uses.add(require) @@ -378,6 +380,17 @@ def hostexamples(t): t.cp('examples/example-list.js', 'examples/example-list.xml', 'examples/Jugl.js', 'build/gh-pages/%(BRANCH)s/examples/') +@target('check-examples', 'hostexamples', phony=True) +def check_examples(t): + directory = 'build/gh-pages/%(BRANCH)s/' + examples = ['build/gh-pages/%(BRANCH)s/' + e for e in EXAMPLES] + all_examples = examples + \ + [e + '?mode=simple' for e in examples] + \ + [e + '?mode=whitespace' for e in examples] + for example in all_examples: + t.run('%(PHANTOMJS)s', 'bin/check-example.js', example) + + @target(PROJ4JS, PROJ4JS_ZIP) def proj4js(t): from zipfile import ZipFile diff --git a/build/ol-simple.json b/build/ol-simple.json index ed07e263c8..f6163a713b 100644 --- a/build/ol-simple.json +++ b/build/ol-simple.json @@ -1,5 +1,15 @@ { + // If ambiguate-properties and disambiguate-properties are set to true + // we get function names like "ol_control_Control_prototype$setMap" in + // the compiled code when using the SIMPLE compilation. It looks like + // "ambiguate-properties" and "disambiguate-properties" are only + // appropriate for ADVANCED compilation. + + "ambiguate-properties": false, + + "disambiguate-properties": false, + "id": "ol-simple", "externs": [ diff --git a/build/ol-whitespace.json b/build/ol-whitespace.json index 5564f8a11e..aebd93fa65 100644 --- a/build/ol-whitespace.json +++ b/build/ol-whitespace.json @@ -2,6 +2,17 @@ "id": "ol-whitespace", + // If ambiguate-properties and disambiguate-properties are set to true + // we get function names like "ol_control_Control_prototype$setMap" in + // the compiled code when using the SIMPLE compilation. It looks like + // "ambiguate-properties" and "disambiguate-properties" are only + // appropriate for ADVANCED compilation. To be sure we also don't + // set them for WHITESPACE. + + "ambiguate-properties": false, + + "disambiguate-properties": false, + "externs": [ "//json.js", "externs/bingmaps.js", diff --git a/css/ol.css b/css/ol.css index 197439505e..1a2ede8923 100644 --- a/css/ol.css +++ b/css/ol.css @@ -28,6 +28,24 @@ width: 100%; height: 100%; } +.ol-scale-line { + background: rgba(0,60,136,0.3); + border-radius: 4px; + bottom: 8px; + left: 8px; + padding: 2px; + position: absolute; +} +.ol-scale-line-inner { + border: 1px solid #eeeeee; + border-top: none; + color: #eeeeee; + font-size: 10px; + font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif; + text-align: center; + margin: 1px; + padding: 0px 2px; +} .ol-viewport .ol-unselectable { -webkit-touch-callout: none; -webkit-user-select: none; diff --git a/examples/epsg-4326.js b/examples/epsg-4326.js index 27fc69913b..ba95c06146 100644 --- a/examples/epsg-4326.js +++ b/examples/epsg-4326.js @@ -1,21 +1,14 @@ -goog.require('goog.debug.Console'); -goog.require('goog.debug.Logger'); -goog.require('goog.debug.Logger.Level'); goog.require('ol.Collection'); goog.require('ol.Coordinate'); goog.require('ol.Map'); goog.require('ol.RendererHint'); goog.require('ol.View2D'); +goog.require('ol.control.ScaleLineUnits'); goog.require('ol.layer.TileLayer'); goog.require('ol.projection'); goog.require('ol.source.TiledWMS'); -if (goog.DEBUG) { - goog.debug.Console.autoInstall(); - goog.debug.Logger.getLogger('ol').setLevel(goog.debug.Logger.Level.INFO); -} - var epsg4326 = ol.projection.getFromCode('EPSG:4326'); // We give the single image source a set of resolutions. This prevents the @@ -47,6 +40,8 @@ var map = new ol.Map({ layers: layers, // The OSgeo server does not set cross origin headers, so we cannot use WebGL renderers: [ol.RendererHint.CANVAS, ol.RendererHint.DOM], + scaleLineControl: true, + scaleLineUnits: ol.control.ScaleLineUnits.DEGREES, target: 'map', view: new ol.View2D({ projection: epsg4326, diff --git a/examples/full-screen.js b/examples/full-screen.js index e696c2fea1..8ab4ca96ea 100644 --- a/examples/full-screen.js +++ b/examples/full-screen.js @@ -15,6 +15,7 @@ var layer = new ol.layer.TileLayer({ var map = new ol.Map({ layers: new ol.Collection([layer]), renderers: ol.RendererHints.createFromQueryData(), + scaleLineControl: true, target: 'map', view: new ol.View2D({ center: new ol.Coordinate(0, 0), diff --git a/examples/two-layers.js b/examples/two-layers.js index 78451c0669..e325376b7f 100644 --- a/examples/two-layers.js +++ b/examples/two-layers.js @@ -1,4 +1,3 @@ -goog.require('ol.BingMapsStyle'); goog.require('ol.Collection'); goog.require('ol.Coordinate'); goog.require('ol.Map'); @@ -14,7 +13,7 @@ var layers = new ol.Collection([ new ol.layer.TileLayer({ source: new ol.source.BingMaps({ key: 'AgtFlPYDnymLEe9zJ5PCkghbNiFZE9aAtTy3mPaEnEBXqLHtFuTcKoZ-miMC3w7R', - style: ol.BingMapsStyle.AERIAL + style: 'Aerial' }) }), new ol.layer.TileLayer({ diff --git a/examples/wms-capabilities.html b/examples/wms-capabilities.html index c119fdc92e..3fde09bcf8 100644 --- a/examples/wms-capabilities.html +++ b/examples/wms-capabilities.html @@ -35,7 +35,7 @@ wms capabilities example -
+

     

WMS GetCapabilities parsing example

diff --git a/examples/wms-capabilities.js b/examples/wms-capabilities.js index 09d8ed7061..8566372599 100644 --- a/examples/wms-capabilities.js +++ b/examples/wms-capabilities.js @@ -13,7 +13,8 @@ xhr.open('GET', url, true); xhr.onload = function() { if (xhr.status == 200) { result = parser.read(xhr.responseXML); - document.getElementById('log').innerHTML = window.JSON.stringify(result); + document.getElementById('log').innerHTML = + window.JSON.stringify(result, undefined, 2); } }; xhr.send(); diff --git a/readme.md b/readme.md index 85925eddb5..b94f437aa9 100644 --- a/readme.md +++ b/readme.md @@ -5,7 +5,13 @@ ## Hosted Examples -The examples are hosted on GitHub (as GitHub pages). See http://openlayers.github.com/ol3/master/examples/. +The examples are hosted on GitHub (as GitHub pages): http://openlayers.github.com/ol3/master/examples/. + +By default the examples use the `ol.js` script, which is compiled using Closure Compiler's ADVANVCED mode. +By appending `?mode=simple` or `?mode=whitespace` to the URL you can make the example page load `ol-simple.js` +or `ol-whitespace.js` instead of `ol.js`. As their names suggest it, `ol-simple.js` and `ol-whitespace.js` +are compiled using the SIMPLE and WHITESPACE modes, respectively. For example: +http://openlayers.github.com/ol3/master/examples/full-screen.html?mode=simple. ## Build OpenLayers 3 @@ -15,7 +21,7 @@ Run build.py: Windows users should run `build` instead. -## Run examples locally +## Run Examples locally Run the [Plovr](http://plovr.com/) web server with: @@ -33,18 +39,20 @@ and explore the `examples/` directory, for example by opening You can turn off compilation by appending `?mode=RAW` to the URL, for example . (By default mode is `ADVANCED`.) +Run examples without Plovr: + The examples can also be run against the `ol.js` standalone lib, without Plovr, just like the examples [hosted](http://openlayers.github.com/ol3/master/examples/) -on GitHub. You will want to run the examples against the standalone lib to verify -that will work correctly when copied on GitHub (as GitHub pages). Start by executing -the `hostexamples` build target: +on GitHub. Start by executing the `hostexamples` build target: $ ./build.py hostexamples -This will build `ol.js` and `ol.css`, creates the examples index page, and copy everything to -`build/gh-pages//`, where `` is the name of the local checked -out Git branch. You can now open the `build/gh-pages/examples` directory -in the browser, for example: . +This will build `ol.js`, `ol-simple.js`, `ol-whitespace.js`, and `ol.css`, create the examples index page, +and copy everything to `build/gh-pages//`, where `` is the name of the local +checked out Git branch. You can now open the examples index page in the browser, for example: +. To make an example use `ol-simple.js` or +`ol-whitespace.js` instead of `ol.js` append `?mode=simple` or `?mode=whitespace` to the example +URL. ## Run tests diff --git a/src/objectliterals.exports b/src/objectliterals.exports index 3e0d0e4f1a..dd819ccd2d 100644 --- a/src/objectliterals.exports +++ b/src/objectliterals.exports @@ -10,10 +10,13 @@ @exportObjectLiteralProperty ol.MapOptions.mouseWheelZoomDelta number|undefined @exportObjectLiteralProperty ol.MapOptions.renderer ol.RendererHint|undefined @exportObjectLiteralProperty ol.MapOptions.renderers Array.|undefined +@exportObjectLiteralProperty ol.MapOptions.scaleLineControl boolean|undefined +@exportObjectLiteralProperty ol.MapOptions.scaleLineUnits ol.control.ScaleLineUnits|undefined @exportObjectLiteralProperty ol.MapOptions.shiftDragZoom boolean|undefined @exportObjectLiteralProperty ol.MapOptions.target Element|string @exportObjectLiteralProperty ol.MapOptions.touchPan boolean|undefined -@exportObjectLiteralProperty ol.MapOptions.touchRotateZoom boolean|undefined +@exportObjectLiteralProperty ol.MapOptions.touchRotate boolean|undefined +@exportObjectLiteralProperty ol.MapOptions.touchZoom boolean|undefined @exportObjectLiteralProperty ol.MapOptions.view ol.IView|undefined @exportObjectLiteralProperty ol.MapOptions.zoomControl boolean|undefined @exportObjectLiteralProperty ol.MapOptions.zoomDelta number|undefined @@ -57,6 +60,12 @@ @exportObjectLiteralProperty ol.control.AttributionOptions.map ol.Map|undefined @exportObjectLiteralProperty ol.control.AttributionOptions.target Element|undefined +@exportObjectLiteral ol.control.ScaleLineOptions +@exportObjectLiteralProperty ol.control.ScaleLineOptions.map ol.Map|undefined +@exportObjectLiteralProperty ol.control.ScaleLineOptions.minWidth number|undefined +@exportObjectLiteralProperty ol.control.ScaleLineOptions.target Element|undefined +@exportObjectLiteralProperty ol.control.ScaleLineOptions.units ol.control.ScaleLineUnits|undefined + @exportObjectLiteral ol.control.MousePositionOptions @exportObjectLiteralProperty ol.control.MousePositionOptions.coordinateFormat ol.CoordinateFormatType|undefined @exportObjectLiteralProperty ol.control.MousePositionOptions.map ol.Map|undefined @@ -87,7 +96,7 @@ @exportObjectLiteral ol.source.BingMapsOptions @exportObjectLiteralProperty ol.source.BingMapsOptions.culture string|undefined @exportObjectLiteralProperty ol.source.BingMapsOptions.key string -@exportObjectLiteralProperty ol.source.BingMapsOptions.style ol.BingMapsStyle +@exportObjectLiteralProperty ol.source.BingMapsOptions.style string @exportObjectLiteral ol.source.DebugTileSourceOptions @exportObjectLiteralProperty ol.source.DebugTileSourceOptions.extent ol.Extent|undefined @@ -134,6 +143,7 @@ @exportObjectLiteralProperty ol.tilegrid.TileGridOptions.origins Array.|undefined @exportObjectLiteralProperty ol.tilegrid.TileGridOptions.resolutions !Array. @exportObjectLiteralProperty ol.tilegrid.TileGridOptions.tileSize ol.Size|undefined +@exportObjectLiteralProperty ol.tilegrid.TileGridOptions.tileSizes Array.|undefined @exportObjectLiteral ol.tilegrid.XYZOptions @exportObjectLiteralProperty ol.tilegrid.XYZOptions.maxZoom number diff --git a/src/ol/control/mousepositioncontrol.js b/src/ol/control/mousepositioncontrol.js index 09abf92d4b..60a667f4a0 100644 --- a/src/ol/control/mousepositioncontrol.js +++ b/src/ol/control/mousepositioncontrol.js @@ -8,6 +8,7 @@ goog.require('goog.dom'); goog.require('goog.events'); goog.require('goog.events.EventType'); goog.require('goog.style'); +goog.require('ol.Coordinate'); goog.require('ol.CoordinateFormatType'); goog.require('ol.MapEvent'); goog.require('ol.MapEventType'); @@ -177,7 +178,9 @@ ol.control.MousePosition.prototype.updateHTML_ = function(pixel) { var map = this.getMap(); var coordinate = map.getCoordinateFromPixel(pixel); if (!goog.isNull(coordinate)) { - coordinate = this.transform_(coordinate); + var vertex = [coordinate.x, coordinate.y]; + vertex = this.transform_(vertex, vertex); + coordinate = new ol.Coordinate(vertex[0], vertex[1]); if (goog.isDef(this.coordinateFormat_)) { html = this.coordinateFormat_(coordinate); } else { diff --git a/src/ol/control/scaleline.exports b/src/ol/control/scaleline.exports new file mode 100644 index 0000000000..6d0cbe1cd1 --- /dev/null +++ b/src/ol/control/scaleline.exports @@ -0,0 +1,9 @@ +@exportClass ol.control.ScaleLine ol.control.ScaleLineOptions +@exportProperty ol.control.ScaleLine.prototype.setMap + +@exportSymbol ol.control.ScaleLineUnits +@exportProperty ol.control.ScaleLineUnits.DEGREES +@exportProperty ol.control.ScaleLineUnits.IMPERIAL +@exportProperty ol.control.ScaleLineUnits.NAUTICAL +@exportProperty ol.control.ScaleLineUnits.METRIC +@exportProperty ol.control.ScaleLineUnits.US diff --git a/src/ol/control/scalelinecontrol.js b/src/ol/control/scalelinecontrol.js new file mode 100644 index 0000000000..a2144e502c --- /dev/null +++ b/src/ol/control/scalelinecontrol.js @@ -0,0 +1,277 @@ +goog.provide('ol.control.ScaleLine'); +goog.provide('ol.control.ScaleLineUnits'); + +goog.require('goog.dom'); +goog.require('goog.style'); +goog.require('ol.FrameState'); +goog.require('ol.MapEvent'); +goog.require('ol.MapEventType'); +goog.require('ol.ProjectionUnits'); +goog.require('ol.TransformFunction'); +goog.require('ol.control.Control'); +goog.require('ol.projection'); +goog.require('ol.sphere.NORMAL'); + + +/** + * @enum {string} + */ +ol.control.ScaleLineUnits = { + DEGREES: 'degrees', + IMPERIAL: 'imperial', + NAUTICAL: 'nautical', + METRIC: 'metric', + US: 'us' +}; + + + +/** + * @constructor + * @extends {ol.control.Control} + * @param {ol.control.ScaleLineOptions=} opt_options Options. + */ +ol.control.ScaleLine = function(opt_options) { + + var options = opt_options || {}; + + /** + * @private + * @type {Element} + */ + this.innerElement_ = goog.dom.createDom(goog.dom.TagName.DIV, { + 'class': 'ol-scale-line-inner' + }); + + /** + * @private + * @type {Element} + */ + this.element_ = goog.dom.createDom(goog.dom.TagName.DIV, { + 'class': 'ol-scale-line ol-unselectable' + }, this.innerElement_); + + /** + * @private + * @type {number} + */ + this.minWidth_ = goog.isDef(options.minWidth) ? options.minWidth : 64; + + /** + * @private + * @type {ol.control.ScaleLineUnits} + */ + this.units_ = goog.isDef(options.units) ? + options.units : ol.control.ScaleLineUnits.METRIC; + + /** + * @private + * @type {Array.} + */ + this.listenerKeys_ = null; + + /** + * @private + * @type {boolean} + */ + this.renderedVisible_ = false; + + /** + * @private + * @type {number|undefined} + */ + this.renderedWidth_; + + /** + * @private + * @type {string} + */ + this.renderedHTML_ = ''; + + /** + * @private + * @type {?ol.TransformFunction} + */ + this.toEPSG4326_ = null; + + goog.base(this, { + element: this.element_, + map: options.map, + target: options.target + }); + +}; +goog.inherits(ol.control.ScaleLine, ol.control.Control); + + +/** + * @const + * @type {Array.} + */ +ol.control.ScaleLine.LEADING_DIGITS = [1, 2, 5]; + + +/** + * @param {ol.MapEvent} mapEvent Map event. + */ +ol.control.ScaleLine.prototype.handleMapPostrender = function(mapEvent) { + var frameState = mapEvent.frameState; + this.updateElement_(mapEvent.frameState); +}; + + +/** + * @inheritDoc + */ +ol.control.ScaleLine.prototype.setMap = function(map) { + if (!goog.isNull(this.listenerKeys_)) { + goog.array.forEach(this.listenerKeys_, goog.events.unlistenByKey); + this.listenerKeys_ = null; + } + goog.base(this, 'setMap', map); + if (!goog.isNull(map)) { + this.listenerKeys_ = [ + goog.events.listen(map, ol.MapEventType.POSTRENDER, + this.handleMapPostrender, false, this) + ]; + } +}; + + +/** + * @param {?ol.FrameState} frameState Frame state. + * @private + */ +ol.control.ScaleLine.prototype.updateElement_ = function(frameState) { + + if (goog.isNull(frameState)) { + if (this.renderedVisible_) { + goog.style.showElement(this.element_, false); + this.renderedVisible_ = false; + } + return; + } + + var view2DState = frameState.view2DState; + var center = view2DState.center; + var projection = view2DState.projection; + var pointResolution = + projection.getPointResolution(view2DState.resolution, center); + var projectionUnits = projection.getUnits(); + + var cosLatitude; + if (projectionUnits == ol.ProjectionUnits.DEGREES && + (this.units_ == ol.control.ScaleLineUnits.METRIC || + this.units_ == ol.control.ScaleLineUnits.IMPERIAL)) { + + // Convert pointResolution from degrees to meters + this.toEPSG4326_ = null; + cosLatitude = Math.cos(goog.math.toRadians(center.y)); + pointResolution *= Math.PI * cosLatitude * ol.sphere.NORMAL.radius / 180; + + } else if (projectionUnits == ol.ProjectionUnits.METERS && + this.units_ == ol.control.ScaleLineUnits.DEGREES) { + + // Convert pointResolution from meters to degrees + if (goog.isNull(this.toEPSG4326_)) { + this.toEPSG4326_ = ol.projection.getTransform( + projection, ol.projection.getFromCode('EPSG:4326')); + } + var vertex = [center.x, center.y]; + vertex = this.toEPSG4326_(vertex, vertex, 2); + cosLatitude = Math.cos(goog.math.toRadians(vertex[1])); + pointResolution *= 180 / (Math.PI * cosLatitude * ol.sphere.NORMAL.radius); + + } else { + + this.toEPSG4326_ = null; + goog.asserts.assert( + ((this.units_ == ol.control.ScaleLineUnits.METRIC || + this.units_ == ol.control.ScaleLineUnits.IMPERIAL) && + projectionUnits == ol.ProjectionUnits.METERS) || + (this.units_ == ol.control.ScaleLineUnits.DEGREES && + projectionUnits == ol.ProjectionUnits.DEGREES)); + + } + + var nominalCount = this.minWidth_ * pointResolution; + var suffix = ''; + if (this.units_ == ol.control.ScaleLineUnits.DEGREES) { + if (nominalCount < 1 / 60) { + suffix = '\u2033'; // seconds + pointResolution *= 3600; + } else if (nominalCount < 1) { + suffix = '\u2032'; // minutes + pointResolution *= 60; + } else { + suffix = '\u00b0'; // degrees + } + } else if (this.units_ == ol.control.ScaleLineUnits.IMPERIAL) { + if (nominalCount < 0.9144) { + suffix = 'in'; + pointResolution /= 0.0254; + } else if (nominalCount < 1609.344) { + suffix = 'ft'; + pointResolution /= 0.3048; + } else { + suffix = 'mi'; + pointResolution /= 1609.344; + } + } else if (this.units_ == ol.control.ScaleLineUnits.NAUTICAL) { + pointResolution /= 1852; + suffix = 'nm'; + } else if (this.units_ == ol.control.ScaleLineUnits.METRIC) { + if (nominalCount < 1) { + suffix = 'mm'; + pointResolution *= 1000; + } else if (nominalCount < 1000) { + suffix = 'm'; + } else { + suffix = 'km'; + pointResolution /= 1000; + } + } else if (this.units_ == ol.control.ScaleLineUnits.US) { + if (nominalCount < 0.9144) { + suffix = 'in'; + pointResolution *= 39.37; + } else if (nominalCount < 1609.344) { + suffix = 'ft'; + pointResolution /= 0.30480061; + } else { + suffix = 'mi'; + pointResolution /= 1609.3472; + } + } else { + goog.asserts.assert(false); + } + + var i = 3 * Math.floor( + Math.log(this.minWidth_ * pointResolution) / Math.log(10)); + var count, width; + while (true) { + count = ol.control.ScaleLine.LEADING_DIGITS[i % 3] * + Math.pow(10, Math.floor(i / 3)); + width = Math.round(count / pointResolution); + if (width >= this.minWidth_) { + break; + } + ++i; + } + + var html = count + suffix; + if (this.renderedHTML_ != html) { + this.innerElement_.innerHTML = html; + this.renderedHTML_ = html; + } + + if (this.renderedWidth_ != width) { + this.innerElement_.style.width = width + 'px'; + this.renderedWidth_ = width; + } + + if (!this.renderedVisible_) { + goog.style.showElement(this.element_, true); + this.renderedVisible_ = true; + } + +}; diff --git a/src/ol/control/zoomcontrol.js b/src/ol/control/zoomcontrol.js index 1f5354e3dd..ffacacf55f 100644 --- a/src/ol/control/zoomcontrol.js +++ b/src/ol/control/zoomcontrol.js @@ -6,7 +6,6 @@ goog.require('goog.dom'); goog.require('goog.dom.TagName'); goog.require('goog.events'); goog.require('goog.events.EventType'); -goog.require('ol.BrowserFeature'); goog.require('ol.control.Control'); @@ -24,20 +23,23 @@ ol.control.ZOOM_DURATION = 250; */ ol.control.Zoom = function(zoomOptions) { - var eventType = ol.BrowserFeature.HAS_TOUCH ? - goog.events.EventType.TOUCHEND : goog.events.EventType.CLICK; - var inElement = goog.dom.createDom(goog.dom.TagName.A, { 'href': '#zoomIn', 'class': 'ol-zoom-in' }); - goog.events.listen(inElement, eventType, this.handleIn_, false, this); + goog.events.listen(inElement, [ + goog.events.EventType.TOUCHEND, + goog.events.EventType.CLICK + ], this.handleIn_, false, this); var outElement = goog.dom.createDom(goog.dom.TagName.A, { 'href': '#zoomOut', 'class': 'ol-zoom-out' }); - goog.events.listen(outElement, eventType, this.handleOut_, false, this); + goog.events.listen(outElement, [ + goog.events.EventType.TOUCHEND, + goog.events.EventType.CLICK + ], this.handleOut_, false, this); var element = goog.dom.createDom( goog.dom.TagName.DIV, 'ol-zoom ol-unselectable', inElement, outElement); diff --git a/src/ol/extent.js b/src/ol/extent.js index 3606dfc63c..5595382e7c 100644 --- a/src/ol/extent.js +++ b/src/ol/extent.js @@ -108,8 +108,10 @@ ol.Extent.prototype.getTopRight = function() { * @return {ol.Extent} Extent. */ ol.Extent.prototype.transform = function(transformFn) { - var a = transformFn(new ol.Coordinate(this.minX, this.minY)); - var b = transformFn(new ol.Coordinate(this.maxX, this.maxY)); - return new ol.Extent(Math.min(a.x, b.x), Math.min(a.y, b.y), - Math.max(a.x, b.x), Math.max(a.y, b.y)); + var input = [this.minX, this.minY, this.maxX, this.maxY]; + input = transformFn(input, input, 2); + return new ol.Extent(Math.min(input[0], input[2]), + Math.min(input[1], input[3]), + Math.max(input[0], input[2]), + Math.max(input[1], input[3])); }; diff --git a/src/ol/geolocation.js b/src/ol/geolocation.js index 201257e2eb..5920f92328 100644 --- a/src/ol/geolocation.js +++ b/src/ol/geolocation.js @@ -76,11 +76,13 @@ ol.Geolocation.prototype.disposeInternal = function() { ol.Geolocation.prototype.handleProjectionChanged_ = function() { var projection = this.getProjection(); if (goog.isDefAndNotNull(projection)) { - this.transformCoords_ = ol.projection.getTransform( + this.transformFn_ = ol.projection.getTransform( ol.projection.getFromCode('EPSG:4326'), projection); if (!goog.isNull(this.position_)) { + var vertex = [this.position_.x, this.position_.y]; + vertex = this.transformFn_(vertex, vertex, 2); this.set(ol.GeolocationProperty.POSITION, - this.transformCoords_(this.position_)); + new ol.Coordinate(vertex[0], vertex[1])); } } }; @@ -108,8 +110,10 @@ ol.Geolocation.prototype.positionChange_ = function(position) { this.set(ol.GeolocationProperty.HEADING, goog.isNull(coords.heading) ? undefined : goog.math.toRadians(coords.heading)); this.position_ = new ol.Coordinate(coords.longitude, coords.latitude); + var vertex = [coords.longitude, coords.latitude]; + vertex = this.transformFn_(vertex, vertex, 2); this.set(ol.GeolocationProperty.POSITION, - this.transformCoords_(this.position_)); + new ol.Coordinate(vertex[0], vertex[1])); this.set(ol.GeolocationProperty.SPEED, goog.isNull(coords.speed) ? undefined : coords.speed); }; @@ -230,7 +234,9 @@ goog.exportProperty( /** * @private - * @param {ol.Coordinate} coordinate Coordinate. - * @return {ol.Coordinate} Coordinate. + * @param {Array.} input Input coordinate values. + * @param {Array.=} opt_output Output array of coordinate values. + * @param {number=} opt_dimension Dimension (default is 2). + * @return {Array.} Output coordinate values. */ -ol.Geolocation.prototype.transformCoords_ = goog.functions.identity; +ol.Geolocation.prototype.transformFn_ = goog.functions.identity; diff --git a/src/ol/interaction/dragpaninteraction.js b/src/ol/interaction/dragpaninteraction.js index 4281be71fb..4827c92e2f 100644 --- a/src/ol/interaction/dragpaninteraction.js +++ b/src/ol/interaction/dragpaninteraction.js @@ -80,7 +80,7 @@ ol.interaction.DragPan.prototype.handleDragEnd = function(mapBrowserEvent) { var map = mapBrowserEvent.map; var view = map.getView(); - view.setHint(ol.ViewHint.PANNING, -1); + view.setHint(ol.ViewHint.INTERACTING, -1); if (this.kinetic_ && this.kinetic_.end()) { var distance = this.kinetic_.getDistance(); @@ -111,7 +111,7 @@ ol.interaction.DragPan.prototype.handleDragStart = function(mapBrowserEvent) { } var map = mapBrowserEvent.map; map.requestRenderFrame(); - map.getView().setHint(ol.ViewHint.PANNING, 1); + map.getView().setHint(ol.ViewHint.INTERACTING, 1); return true; } else { return false; diff --git a/src/ol/interaction/touchinteraction.js b/src/ol/interaction/touchinteraction.js index c71d5997de..1e96fe7ecb 100644 --- a/src/ol/interaction/touchinteraction.js +++ b/src/ol/interaction/touchinteraction.js @@ -31,6 +31,7 @@ ol.interaction.Touch = function() { /** * @type {Array.} + * @protected */ this.targetTouches = []; diff --git a/src/ol/interaction/touchpaninteraction.js b/src/ol/interaction/touchpaninteraction.js index 0c21c78c4b..452c43159a 100644 --- a/src/ol/interaction/touchpaninteraction.js +++ b/src/ol/interaction/touchpaninteraction.js @@ -1,5 +1,4 @@ // FIXME works for View2D only -// FIXME opt_kinetic param goog.provide('ol.interaction.TouchPan'); goog.require('goog.asserts'); @@ -16,16 +15,17 @@ goog.require('ol.interaction.Touch'); /** * @constructor * @extends {ol.interaction.Touch} + * @param {ol.Kinetic=} opt_kinetic Kinetic object. */ -ol.interaction.TouchPan = function() { +ol.interaction.TouchPan = function(opt_kinetic) { goog.base(this); /** * @private - * @type {ol.Kinetic} + * @type {ol.Kinetic|undefined} */ - this.kinetic_ = new ol.Kinetic(-0.005, 0.05, 100); + this.kinetic_ = opt_kinetic; /** * @private @@ -49,7 +49,9 @@ ol.interaction.TouchPan.prototype.handleTouchMove = function(mapBrowserEvent) { goog.asserts.assert(this.targetTouches.length >= 1); var centroid = ol.interaction.Touch.centroid(this.targetTouches); if (!goog.isNull(this.lastCentroid)) { - this.kinetic_.update(centroid.x, centroid.y); + if (this.kinetic_) { + this.kinetic_.update(centroid.x, centroid.y); + } var deltaX = this.lastCentroid.x - centroid.x; var deltaY = centroid.y - this.lastCentroid.y; var view = mapBrowserEvent.map.getView(); @@ -71,8 +73,8 @@ ol.interaction.TouchPan.prototype.handleTouchEnd = var map = mapBrowserEvent.map; var view = map.getView(); if (this.targetTouches.length == 0) { - view.setHint(ol.ViewHint.PANNING, -1); - if (this.kinetic_.end()) { + view.setHint(ol.ViewHint.INTERACTING, -1); + if (this.kinetic_ && this.kinetic_.end()) { var distance = this.kinetic_.getDistance(); var angle = this.kinetic_.getAngle(); var center = view.getCenter(); @@ -87,6 +89,7 @@ ol.interaction.TouchPan.prototype.handleTouchEnd = } return false; } else { + this.lastCentroid = null; return true; } }; @@ -107,8 +110,10 @@ ol.interaction.TouchPan.prototype.handleTouchStart = view.setCenter(mapBrowserEvent.frameState.view2DState.center); this.kineticPreRenderFn_ = null; } - this.kinetic_.begin(); - view.setHint(ol.ViewHint.PANNING, 1); + if (this.kinetic_) { + this.kinetic_.begin(); + } + view.setHint(ol.ViewHint.INTERACTING, 1); return true; } else { return false; diff --git a/src/ol/interaction/touchrotateandzoominteraction.js b/src/ol/interaction/touchrotateinteraction.js similarity index 66% rename from src/ol/interaction/touchrotateandzoominteraction.js rename to src/ol/interaction/touchrotateinteraction.js index d06d6ee93d..1ce5d02a77 100644 --- a/src/ol/interaction/touchrotateandzoominteraction.js +++ b/src/ol/interaction/touchrotateinteraction.js @@ -1,6 +1,6 @@ // FIXME works for View2D only -goog.provide('ol.interaction.TouchRotateAndZoom'); +goog.provide('ol.interaction.TouchRotate'); goog.require('goog.asserts'); goog.require('ol.View'); @@ -12,8 +12,10 @@ goog.require('ol.interaction.Touch'); /** * @constructor * @extends {ol.interaction.Touch} + * @param {number=} opt_threshold Minimal angle to start a rotation. + * Default to 0.3 (radian). */ -ol.interaction.TouchRotateAndZoom = function() { +ol.interaction.TouchRotate = function(opt_threshold) { goog.base(this); @@ -23,12 +25,6 @@ ol.interaction.TouchRotateAndZoom = function() { */ this.lastAngle_; - /** - * @private - * @type {number|undefined} - */ - this.lastDistance_; - /** * @private * @type {boolean} @@ -45,23 +41,20 @@ ol.interaction.TouchRotateAndZoom = function() { * @private * @type {number} */ - this.rotationThreshold_ = 0.3; + this.threshold_ = goog.isDef(opt_threshold) ? opt_threshold : 0.3; }; -goog.inherits(ol.interaction.TouchRotateAndZoom, ol.interaction.Touch); +goog.inherits(ol.interaction.TouchRotate, ol.interaction.Touch); /** * @inheritDoc */ -ol.interaction.TouchRotateAndZoom.prototype.handleTouchMove = +ol.interaction.TouchRotate.prototype.handleTouchMove = function(mapBrowserEvent) { goog.asserts.assert(this.targetTouches.length >= 2); - var scaleDelta = 1.0; var rotationDelta = 0.0; - var centroid = ol.interaction.Touch.centroid(this.targetTouches); - var touch0 = this.targetTouches[0]; var touch1 = this.targetTouches[1]; var dx = touch0.clientX - touch1.clientX; @@ -72,19 +65,11 @@ ol.interaction.TouchRotateAndZoom.prototype.handleTouchMove = touch1.clientY - touch0.clientY, touch1.clientX - touch0.clientX); - // distance between touches - var distance = Math.sqrt(dx * dx + dy * dy); - - if (goog.isDef(this.lastDistance_)) { - scaleDelta = this.lastDistance_ / distance; - } - this.lastDistance_ = distance; - if (goog.isDef(this.lastAngle_)) { var delta = angle - this.lastAngle_; this.rotationDelta_ += delta; if (!this.rotating_ && - Math.abs(this.rotationDelta_) > this.rotationThreshold_) { + Math.abs(this.rotationDelta_) > this.threshold_) { this.rotating_ = true; } rotationDelta = delta; @@ -94,17 +79,15 @@ ol.interaction.TouchRotateAndZoom.prototype.handleTouchMove = var map = mapBrowserEvent.map; var view = map.getView(); - // rotate / scale anchor point. + // rotate anchor point. // FIXME: should be the intersection point between the lines: // touch0,touch1 and previousTouch0,previousTouch1 var viewportPosition = goog.style.getClientPosition(map.getViewport()); + var centroid = ol.interaction.Touch.centroid(this.targetTouches); centroid.x -= viewportPosition.x; centroid.y -= viewportPosition.y; var anchor = map.getCoordinateFromPixel(centroid); - // scale, bypass the resolution constraint - view.zoom_(map, view.getResolution() * scaleDelta, anchor); - // rotate if (this.rotating_) { view.rotate(map, view.getRotation() + rotationDelta, anchor); @@ -115,14 +98,12 @@ ol.interaction.TouchRotateAndZoom.prototype.handleTouchMove = /** * @inheritDoc */ -ol.interaction.TouchRotateAndZoom.prototype.handleTouchEnd = +ol.interaction.TouchRotate.prototype.handleTouchEnd = function(mapBrowserEvent) { if (this.targetTouches.length < 2) { var map = mapBrowserEvent.map; var view = map.getView(); - // take the resolution constraint into account - view.zoomToResolution(map, view.getResolution()); - view.setHint(ol.ViewHint.PANNING, -1); + view.setHint(ol.ViewHint.INTERACTING, -1); return false; } else { return true; @@ -133,15 +114,14 @@ ol.interaction.TouchRotateAndZoom.prototype.handleTouchEnd = /** * @inheritDoc */ -ol.interaction.TouchRotateAndZoom.prototype.handleTouchStart = +ol.interaction.TouchRotate.prototype.handleTouchStart = function(mapBrowserEvent) { if (this.targetTouches.length >= 2) { var view = mapBrowserEvent.map.getView(); - this.lastDistance_ = undefined; this.lastAngle_ = undefined; this.rotating_ = false; this.rotationDelta_ = 0.0; - view.setHint(ol.ViewHint.PANNING, 1); + view.setHint(ol.ViewHint.INTERACTING, 1); return true; } else { return false; diff --git a/src/ol/interaction/touchzoominteraction.js b/src/ol/interaction/touchzoominteraction.js new file mode 100644 index 0000000000..9087c5f3b4 --- /dev/null +++ b/src/ol/interaction/touchzoominteraction.js @@ -0,0 +1,98 @@ +// FIXME works for View2D only + +goog.provide('ol.interaction.TouchZoom'); + +goog.require('goog.asserts'); +goog.require('ol.View'); +goog.require('ol.ViewHint'); +goog.require('ol.interaction.Touch'); + + + +/** + * @constructor + * @extends {ol.interaction.Touch} + */ +ol.interaction.TouchZoom = function() { + + goog.base(this); + + /** + * @private + * @type {number|undefined} + */ + this.lastDistance_; + +}; +goog.inherits(ol.interaction.TouchZoom, ol.interaction.Touch); + + +/** + * @inheritDoc + */ +ol.interaction.TouchZoom.prototype.handleTouchMove = + function(mapBrowserEvent) { + goog.asserts.assert(this.targetTouches.length >= 2); + var scaleDelta = 1.0; + + var touch0 = this.targetTouches[0]; + var touch1 = this.targetTouches[1]; + var dx = touch0.clientX - touch1.clientX; + var dy = touch0.clientY - touch1.clientY; + + // distance between touches + var distance = Math.sqrt(dx * dx + dy * dy); + + if (goog.isDef(this.lastDistance_)) { + scaleDelta = this.lastDistance_ / distance; + } + this.lastDistance_ = distance; + + var map = mapBrowserEvent.map; + var view = map.getView(); + + // scale anchor point. + var viewportPosition = goog.style.getClientPosition(map.getViewport()); + var centroid = ol.interaction.Touch.centroid(this.targetTouches); + centroid.x -= viewportPosition.x; + centroid.y -= viewportPosition.y; + var anchor = map.getCoordinateFromPixel(centroid); + + // scale, bypass the resolution constraint + view.zoom_(map, view.getResolution() * scaleDelta, anchor); + +}; + + +/** + * @inheritDoc + */ +ol.interaction.TouchZoom.prototype.handleTouchEnd = + function(mapBrowserEvent) { + if (this.targetTouches.length < 2) { + var map = mapBrowserEvent.map; + var view = map.getView(); + // take the resolution constraint into account + view.zoomToResolution(map, view.getResolution()); + view.setHint(ol.ViewHint.INTERACTING, -1); + return false; + } else { + return true; + } +}; + + +/** + * @inheritDoc + */ +ol.interaction.TouchZoom.prototype.handleTouchStart = + function(mapBrowserEvent) { + if (this.targetTouches.length >= 2) { + var view = mapBrowserEvent.map.getView(); + this.lastDistance_ = undefined; + view.setHint(ol.ViewHint.INTERACTING, 1); + return true; + } else { + return false; + } +}; diff --git a/src/ol/map.js b/src/ol/map.js index 7978e829d4..9dfcee6d75 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -45,6 +45,7 @@ goog.require('ol.View'); goog.require('ol.View2D'); goog.require('ol.control.Attribution'); goog.require('ol.control.Control'); +goog.require('ol.control.ScaleLine'); goog.require('ol.control.Zoom'); goog.require('ol.interaction.DblClickZoom'); goog.require('ol.interaction.DragPan'); @@ -55,7 +56,8 @@ goog.require('ol.interaction.KeyboardPan'); goog.require('ol.interaction.KeyboardZoom'); goog.require('ol.interaction.MouseWheelZoom'); goog.require('ol.interaction.TouchPan'); -goog.require('ol.interaction.TouchRotateAndZoom'); +goog.require('ol.interaction.TouchRotate'); +goog.require('ol.interaction.TouchZoom'); goog.require('ol.interaction.condition'); goog.require('ol.layer.Layer'); goog.require('ol.projection'); @@ -925,6 +927,16 @@ ol.Map.createControls_ = function(mapOptions) { controls.push(new ol.control.Attribution({})); } + var scaleLineControl = goog.isDef(mapOptions.scaleLineControl) ? + mapOptions.scaleLineControl : false; + if (scaleLineControl) { + var scaleLineUnits = goog.isDef(mapOptions.scaleLineUnits) ? + mapOptions.scaleLineUnits : undefined; + controls.push(new ol.control.ScaleLine({ + units: scaleLineUnits + })); + } + var zoomControl = goog.isDef(mapOptions.zoomControl) ? mapOptions.zoomControl : true; if (zoomControl) { @@ -966,13 +978,20 @@ ol.Map.createInteractions_ = function(mapOptions) { var touchPan = goog.isDef(mapOptions.touchPan) ? mapOptions.touchPan : true; if (touchPan) { - interactions.push(new ol.interaction.TouchPan()); + interactions.push(new ol.interaction.TouchPan( + new ol.Kinetic(-0.005, 0.05, 100))); } - var touchRotateZoom = goog.isDef(mapOptions.touchRotateZoom) ? - mapOptions.touchRotateZoom : true; - if (touchRotateZoom) { - interactions.push(new ol.interaction.TouchRotateAndZoom()); + var touchRotate = goog.isDef(mapOptions.touchRotate) ? + mapOptions.touchRotate : true; + if (touchRotate) { + interactions.push(new ol.interaction.TouchRotate()); + } + + var touchZoom = goog.isDef(mapOptions.touchZoom) ? + mapOptions.touchZoom : true; + if (touchZoom) { + interactions.push(new ol.interaction.TouchZoom()); } var dragPan = goog.isDef(mapOptions.dragPan) ? diff --git a/src/ol/mapbrowserevent.js b/src/ol/mapbrowserevent.js index 792585eff0..e86b83728d 100644 --- a/src/ol/mapbrowserevent.js +++ b/src/ol/mapbrowserevent.js @@ -201,7 +201,7 @@ ol.MapBrowserEventHandler.prototype.click_ = function(browserEvent) { newEvent = new ol.MapBrowserEvent( ol.MapBrowserEvent.EventType.DBLCLICK, this.map_, browserEvent); this.dispatchEvent(newEvent); - } else if (type == goog.events.EventType.CLICK) { + } else { newEvent = new ol.MapBrowserEvent( ol.MapBrowserEvent.EventType.CLICK, this.map_, browserEvent); this.dispatchEvent(newEvent); diff --git a/src/ol/parser/ogc/wmtscapabilities_v1_0_0.js b/src/ol/parser/ogc/wmtscapabilities_v1_0_0.js index 1d1390248a..9260038a63 100644 --- a/src/ol/parser/ogc/wmtscapabilities_v1_0_0.js +++ b/src/ol/parser/ogc/wmtscapabilities_v1_0_0.js @@ -94,17 +94,19 @@ ol.parser.ogc.WMTSCapabilities_v1_0_0 = function() { obj['matrixHeight'] = parseInt(this.getChildValue(node), 10); }, 'ResourceURL': function(node, obj) { - obj['resourceUrl'] = obj['resourceUrl'] || {}; var resourceType = node.getAttribute('resourceType'); + var format = node.getAttribute('format'); + var template = node.getAttribute('template'); if (!obj['resourceUrls']) { - obj['resourceUrls'] = []; + obj['resourceUrls'] = {}; } - var resourceUrl = obj['resourceUrl'][resourceType] = { - 'format': node.getAttribute('format'), - 'template': node.getAttribute('template'), - 'resourceType': resourceType - }; - obj['resourceUrls'].push(resourceUrl); + if (!obj['resourceUrls'][resourceType]) { + obj['resourceUrls'][resourceType] = {}; + } + if (!obj['resourceUrls'][resourceType][format]) { + obj['resourceUrls'][resourceType][format] = []; + } + obj['resourceUrls'][resourceType][format].push(template); }, 'WSDL': function(node, obj) { obj['wsdl'] = {}; diff --git a/src/ol/projection.exports b/src/ol/projection.exports index 613ac99a3c..e82e78498f 100644 --- a/src/ol/projection.exports +++ b/src/ol/projection.exports @@ -2,6 +2,7 @@ @exportProperty ol.Projection.prototype.getAxisOrientation @exportProperty ol.Projection.prototype.getCode @exportProperty ol.Projection.prototype.getExtent +@exportProperty ol.Projection.prototype.getPointResolution @exportProperty ol.Projection.prototype.getUnits @exportSymbol ol.ProjectionUnits diff --git a/src/ol/projection.js b/src/ol/projection.js index 6c1e321f14..91d00d3fd5 100644 --- a/src/ol/projection.js +++ b/src/ol/projection.js @@ -8,6 +8,7 @@ goog.require('goog.object'); goog.require('ol.Coordinate'); goog.require('ol.Extent'); goog.require('ol.TransformFunction'); +goog.require('ol.sphere.NORMAL'); /** @@ -85,6 +86,14 @@ ol.Projection.prototype.getExtent = function() { }; +/** + * @param {number} resolution Resolution. + * @param {ol.Coordinate} point Point. + * @return {number} Point resolution. + */ +ol.Projection.prototype.getPointResolution = goog.abstractMethod; + + /** * @return {ol.ProjectionUnits} Units. */ @@ -121,10 +130,49 @@ ol.Proj4jsProjection_ = function(code, proj4jsProj) { */ this.proj4jsProj_ = proj4jsProj; + /** + * @private + * @type {?ol.TransformFunction} + */ + this.toEPSG4326_ = null; + }; goog.inherits(ol.Proj4jsProjection_, ol.Projection); +/** + * @inheritDoc + */ +ol.Proj4jsProjection_.prototype.getPointResolution = + function(resolution, point) { + if (this.getUnits() == ol.ProjectionUnits.DEGREES) { + return resolution; + } else { + // Estimate point resolution by transforming the center pixel to EPSG:4326, + // measuring its width and height on the normal sphere, and taking the + // average of the width and height. + if (goog.isNull(this.toEPSG4326_)) { + this.toEPSG4326_ = ol.projection.getTransform( + this, ol.projection.getProj4jsProjectionFromCode_('EPSG:4326')); + } + var vertices = [ + point.x - resolution / 2, point.y, + point.x + resolution / 2, point.y, + point.x, point.y - resolution / 2, + point.x, point.y + resolution / 2 + ]; + vertices = this.toEPSG4326_(vertices, vertices, 2); + var width = ol.sphere.NORMAL.haversineDistance( + new ol.Coordinate(vertices[0], vertices[1]), + new ol.Coordinate(vertices[2], vertices[3])); + var height = ol.sphere.NORMAL.haversineDistance( + new ol.Coordinate(vertices[4], vertices[5]), + new ol.Coordinate(vertices[6], vertices[7])); + return (width + height) / 2; + } +}; + + /** * @return {Proj4js.Proj} Proj4js projection. */ @@ -397,14 +445,33 @@ ol.projection.getTransform = function(source, destination) { var destinationProj4jsProj = proj4jsDestination.getProj4jsProj(); transform = /** - * @param {ol.Coordinate} coordinate Coordinate. - * @return {ol.Coordinate} Coordinate. + * @param {Array.} input Input coordinate values. + * @param {Array.=} opt_output Output array of coordinates. + * @param {number=} opt_dimension Dimension. + * @return {Array.} Output coordinate values. */ - function(coordinate) { - var proj4jsPoint = new Proj4js.Point(coordinate.x, coordinate.y); - proj4jsPoint = Proj4js.transform( - sourceProj4jsProj, destinationProj4jsProj, proj4jsPoint); - return new ol.Coordinate(proj4jsPoint.x, proj4jsPoint.y); + function(input, opt_output, opt_dimension) { + var length = input.length, + dimension = opt_dimension > 1 ? opt_dimension : 2, + output = opt_output; + if (!goog.isDef(output)) { + if (dimension > 2) { + // preserve values beyond second dimension + output = input.slice(); + } else { + output = new Array(length); + } + } + goog.asserts.assert(output.length % dimension === 0); + var proj4jsPoint; + for (var i = 0; i < length; i += dimension) { + proj4jsPoint = new Proj4js.Point(input[i], input[i + 1]); + proj4jsPoint = Proj4js.transform( + sourceProj4jsProj, destinationProj4jsProj, proj4jsPoint); + output[i] = proj4jsPoint.x; + output[i + 1] = proj4jsPoint.y; + } + return output; }; ol.projection.addTransform(source, destination, transform); } @@ -418,7 +485,7 @@ ol.projection.getTransform = function(source, destination) { /** * Given the projection codes this method searches for a transformation function - * to convert coordinate from the source projection to the destination + * to convert a coordinates array from the source projection to the destination * projection. * * @param {string} sourceCode Source code. @@ -433,20 +500,42 @@ ol.projection.getTransformFromCodes = function(sourceCode, destinationCode) { /** - * @param {ol.Coordinate} point Point. - * @return {ol.Coordinate} Unaltered point (same reference). + * @param {Array.} input Input coordinate array. + * @param {Array.=} opt_output Output array of coordinate values. + * @param {number=} opt_dimension Dimension. + * @return {Array.} Input coordinate array (same array as input). */ -ol.projection.identityTransform = function(point) { - return point; +ol.projection.identityTransform = function(input, opt_output, opt_dimension) { + if (goog.isDef(opt_output) && input !== opt_output) { + // TODO: consider making this a warning instead + goog.asserts.assert(false, 'This should not be used internally.'); + for (var i = 0, ii = input.length; i < ii; ++i) { + opt_output[i] = input[i]; + } + input = opt_output; + } + return input; }; /** - * @param {ol.Coordinate} point Point. - * @return {ol.Coordinate} Equal point (different reference). + * @param {Array.} input Input coordinate array. + * @param {Array.=} opt_output Output array of coordinate values. + * @param {number=} opt_dimension Dimension. + * @return {Array.} Output coordinate array (new array, same coordinate + * values). */ -ol.projection.cloneTransform = function(point) { - return new ol.Coordinate(point.x, point.y); +ol.projection.cloneTransform = function(input, opt_output, opt_dimension) { + var output; + if (goog.isDef(opt_output)) { + for (var i = 0, ii = input.length; i < ii; ++i) { + opt_output[i] = input[i]; + } + output = opt_output; + } else { + output = input.slice(); + } + return output; }; @@ -460,7 +549,9 @@ ol.projection.cloneTransform = function(point) { */ ol.projection.transform = function(point, source, destination) { var transformFn = ol.projection.getTransform(source, destination); - return transformFn(point); + var vertex = [point.x, point.y]; + vertex = transformFn(vertex, vertex, 2); + return new ol.Coordinate(vertex[0], vertex[1]); }; @@ -474,5 +565,7 @@ ol.projection.transformWithCodes = function(point, sourceCode, destinationCode) { var transformFn = ol.projection.getTransformFromCodes( sourceCode, destinationCode); - return transformFn(point); + var vertex = [point.x, point.y]; + vertex = transformFn(vertex, vertex, 2); + return new ol.Coordinate(vertex[0], vertex[1]); }; diff --git a/src/ol/projection/epsg3857.js b/src/ol/projection/epsg3857.js index 991eca5410..93a99f8a62 100644 --- a/src/ol/projection/epsg3857.js +++ b/src/ol/projection/epsg3857.js @@ -1,10 +1,10 @@ goog.provide('ol.projection.EPSG3857'); goog.require('goog.array'); -goog.require('ol.Coordinate'); goog.require('ol.Extent'); goog.require('ol.Projection'); goog.require('ol.ProjectionUnits'); +goog.require('ol.math'); goog.require('ol.projection'); @@ -73,26 +73,68 @@ ol.projection.EPSG3857.PROJECTIONS = goog.array.map( /** * Transformation from EPSG:4326 to EPSG:3857. * - * @param {ol.Coordinate} point Point. - * @return {ol.Coordinate} Point. + * @param {Array.} input Input array of coordinate values. + * @param {Array.=} opt_output Output array of coordinate values. + * @param {number=} opt_dimension Dimension (default is 2). + * @return {Array.} Output array of coordinate values. */ -ol.projection.EPSG3857.fromEPSG4326 = function(point) { - var x = ol.projection.EPSG3857.RADIUS * Math.PI * point.x / 180; - var y = ol.projection.EPSG3857.RADIUS * - Math.log(Math.tan(Math.PI * (point.y + 90) / 360)); - return new ol.Coordinate(x, y); +ol.projection.EPSG3857.fromEPSG4326 = function( + input, opt_output, opt_dimension) { + var length = input.length, + dimension = opt_dimension > 1 ? opt_dimension : 2, + output = opt_output; + if (!goog.isDef(output)) { + if (dimension > 2) { + // preserve values beyond second dimension + output = input.slice(); + } else { + output = new Array(length); + } + } + goog.asserts.assert(output.length % dimension === 0); + for (var i = 0; i < length; i += dimension) { + output[i] = ol.projection.EPSG3857.RADIUS * Math.PI * input[i] / 180; + output[i + 1] = ol.projection.EPSG3857.RADIUS * + Math.log(Math.tan(Math.PI * (input[i + 1] + 90) / 360)); + } + return output; }; /** * Transformation from EPSG:3857 to EPSG:4326. * - * @param {ol.Coordinate} point Point. - * @return {ol.Coordinate} Point. + * @param {Array.} input Input array of coordinate values. + * @param {Array.=} opt_output Output array of coordinate values. + * @param {number=} opt_dimension Dimension (default is 2). + * @return {Array.} Output array of coordinate values. */ -ol.projection.EPSG3857.toEPSG4326 = function(point) { - var x = 180 * point.x / (ol.projection.EPSG3857.RADIUS * Math.PI); - var y = 360 * Math.atan( - Math.exp(point.y / ol.projection.EPSG3857.RADIUS)) / Math.PI - 90; - return new ol.Coordinate(x, y); +ol.projection.EPSG3857.toEPSG4326 = function(input, opt_output, opt_dimension) { + var length = input.length, + dimension = opt_dimension > 1 ? opt_dimension : 2, + output = opt_output; + if (!goog.isDef(output)) { + if (dimension > 2) { + // preserve values beyond second dimension + output = input.slice(); + } else { + output = new Array(length); + } + } + goog.asserts.assert(output.length % dimension === 0); + for (var i = 0; i < length; i += dimension) { + output[i] = 180 * input[i] / (ol.projection.EPSG3857.RADIUS * Math.PI); + output[i + 1] = 360 * Math.atan( + Math.exp(input[i + 1] / ol.projection.EPSG3857.RADIUS)) / Math.PI - 90; + } + return output; +}; + + +/** + * @inheritDoc + */ +ol.projection.EPSG3857.prototype.getPointResolution = + function(resolution, point) { + return resolution / ol.math.cosh(point.y / ol.projection.EPSG3857.RADIUS); }; diff --git a/src/ol/projection/epsg4326.js b/src/ol/projection/epsg4326.js index 05b2c760d7..1c5d7215aa 100644 --- a/src/ol/projection/epsg4326.js +++ b/src/ol/projection/epsg4326.js @@ -41,3 +41,12 @@ ol.projection.EPSG4326.PROJECTIONS = [ new ol.projection.EPSG4326('urn:ogc:def:crs:EPSG:6.6:4326', 'neu'), new ol.projection.EPSG4326('urn:ogc:def:crs:OGC:1.3:CRS84') ]; + + +/** + * @inheritDoc + */ +ol.projection.EPSG4326.prototype.getPointResolution = + function(resolution, point) { + return resolution; +}; diff --git a/src/ol/renderer/canvas/canvasimagelayerrenderer.js b/src/ol/renderer/canvas/canvasimagelayerrenderer.js index 61eb2b898d..fa62818db7 100644 --- a/src/ol/renderer/canvas/canvasimagelayerrenderer.js +++ b/src/ol/renderer/canvas/canvasimagelayerrenderer.js @@ -78,7 +78,7 @@ ol.renderer.canvas.ImageLayer.prototype.renderFrame = var hints = frameState.viewHints; - if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.PANNING]) { + if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING]) { image = imageSource.getImage(frameState.extent, viewResolution); if (!goog.isNull(image)) { var imageState = image.getState(); diff --git a/src/ol/renderer/canvas/canvastilelayerrenderer.js b/src/ol/renderer/canvas/canvastilelayerrenderer.js index 8204edcf33..9c338b7818 100644 --- a/src/ol/renderer/canvas/canvastilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvastilelayerrenderer.js @@ -91,8 +91,8 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame = var tileSource = tileLayer.getTileSource(); var tileSourceKey = goog.getUid(tileSource).toString(); var tileGrid = tileSource.getTileGrid(); - var tileSize = tileGrid.getTileSize(); var z = tileGrid.getZForResolution(view2DState.resolution); + var tileSize = tileGrid.getTileSize(z); var tileResolution = tileGrid.getResolution(z); var tileRange = tileGrid.getTileRangeForExtentAndResolution( frameState.extent, tileResolution); @@ -174,6 +174,7 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame = var currentZ, i, scale, tileCoordKey, tileExtent, tilesToDraw; for (i = 0; i < zs.length; ++i) { currentZ = zs[i]; + tileSize = tileGrid.getTileSize(currentZ); tilesToDraw = tilesToDrawByZ[currentZ]; if (currentZ == z) { for (tileCoordKey in tilesToDraw) { diff --git a/src/ol/renderer/dom/domimagelayerrenderer.js b/src/ol/renderer/dom/domimagelayerrenderer.js index 7190d8c268..769b944848 100644 --- a/src/ol/renderer/dom/domimagelayerrenderer.js +++ b/src/ol/renderer/dom/domimagelayerrenderer.js @@ -66,7 +66,7 @@ ol.renderer.dom.ImageLayer.prototype.renderFrame = var hints = frameState.viewHints; - if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.PANNING]) { + if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING]) { var image_ = imageSource.getImage(frameState.extent, viewResolution); if (!goog.isNull(image_)) { var imageState = image_.getState(); diff --git a/src/ol/renderer/dom/domtilelayerrenderer.js b/src/ol/renderer/dom/domtilelayerrenderer.js index 9b5dd26b32..22cfd29744 100644 --- a/src/ol/renderer/dom/domtilelayerrenderer.js +++ b/src/ol/renderer/dom/domtilelayerrenderer.js @@ -138,7 +138,6 @@ ol.renderer.dom.TileLayer.prototype.renderFrame = /** @type {Object.} */ var newTileLayerZKeys = {}; - var tileSize = tileGrid.getTileSize(); var iz, tileCoordKey, tileCoordOrigin, tileLayerZ, tileLayerZKey, tilesToDraw; for (iz = 0; iz < zs.length; ++iz) { tileLayerZKey = zs[iz]; @@ -200,7 +199,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame = } } else { if (!frameState.viewHints[ol.ViewHint.ANIMATING] && - !frameState.viewHints[ol.ViewHint.PANNING]) { + !frameState.viewHints[ol.ViewHint.INTERACTING]) { tileLayerZ.removeTilesOutsideExtent(frameState.extent); } } @@ -293,7 +292,7 @@ ol.renderer.dom.TileLayerZ_.prototype.addTile = function(tile) { if (tileCoordKey in this.tiles_) { return; } - var tileSize = this.tileGrid_.getTileSize(); + var tileSize = this.tileGrid_.getTileSize(tileCoord.z); var image = tile.getImage(this); var style = image.style; style.position = 'absolute'; diff --git a/src/ol/renderer/maprenderer.js b/src/ol/renderer/maprenderer.js index d3cceb36d1..dfd69e5464 100644 --- a/src/ol/renderer/maprenderer.js +++ b/src/ol/renderer/maprenderer.js @@ -119,7 +119,9 @@ ol.renderer.Map.prototype.calculateMatrices2D = function(frameState) { * @protected * @return {ol.renderer.Layer} layerRenderer Layer renderer. */ -ol.renderer.Map.prototype.createLayerRenderer = goog.functions.NULL; +ol.renderer.Map.prototype.createLayerRenderer = function(layer) { + return new ol.renderer.Layer(this, layer); +}; /** diff --git a/src/ol/renderer/webgl/webglimagelayerrenderer.js b/src/ol/renderer/webgl/webglimagelayerrenderer.js index 5d0341f3c1..b0edbca02c 100644 --- a/src/ol/renderer/webgl/webglimagelayerrenderer.js +++ b/src/ol/renderer/webgl/webglimagelayerrenderer.js @@ -45,7 +45,7 @@ ol.renderer.webgl.ImageLayer = function(mapRenderer, imageLayer) { * @private * @type {!goog.vec.Mat4.Number} */ - this.vertexCoordMatrix_ = goog.vec.Mat4.createNumber(); + this.projectionMatrix_ = goog.vec.Mat4.createNumber(); }; goog.inherits(ol.renderer.webgl.ImageLayer, ol.renderer.webgl.Layer); @@ -118,8 +118,8 @@ ol.renderer.webgl.ImageLayer.prototype.getTexture = function() { /** * @inheritDoc */ -ol.renderer.webgl.ImageLayer.prototype.getVertexCoordMatrix = function() { - return this.vertexCoordMatrix_; +ol.renderer.webgl.ImageLayer.prototype.getProjectionMatrix = function() { + return this.projectionMatrix_; }; @@ -159,7 +159,7 @@ ol.renderer.webgl.ImageLayer.prototype.renderFrame = var hints = frameState.viewHints; - if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.PANNING]) { + if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING]) { var image_ = imageSource.getImage(frameState.extent, viewResolution); if (!goog.isNull(image_)) { var imageState = image_.getState(); @@ -187,7 +187,7 @@ ol.renderer.webgl.ImageLayer.prototype.renderFrame = var canvas = this.getMapRenderer().getCanvas(); - this.updateVertexCoordMatrix_(canvas.width, canvas.height, + this.updateProjectionMatrix_(canvas.width, canvas.height, viewCenter, viewResolution, viewRotation, image.getExtent()); // Translate and scale to flip the Y coord. @@ -213,24 +213,24 @@ ol.renderer.webgl.ImageLayer.prototype.renderFrame = * @param {number} viewRotation View rotation. * @param {ol.Extent} imageExtent Image extent. */ -ol.renderer.webgl.ImageLayer.prototype.updateVertexCoordMatrix_ = +ol.renderer.webgl.ImageLayer.prototype.updateProjectionMatrix_ = function(canvasWidth, canvasHeight, viewCenter, viewResolution, viewRotation, imageExtent) { var canvasExtentWidth = canvasWidth * viewResolution; var canvasExtentHeight = canvasHeight * viewResolution; - var vertexCoordMatrix = this.vertexCoordMatrix_; - goog.vec.Mat4.makeIdentity(vertexCoordMatrix); - goog.vec.Mat4.scale(vertexCoordMatrix, + var projectionMatrix = this.projectionMatrix_; + goog.vec.Mat4.makeIdentity(projectionMatrix); + goog.vec.Mat4.scale(projectionMatrix, 2 / canvasExtentWidth, 2 / canvasExtentHeight, 1); - goog.vec.Mat4.rotateZ(vertexCoordMatrix, -viewRotation); - goog.vec.Mat4.translate(vertexCoordMatrix, + goog.vec.Mat4.rotateZ(projectionMatrix, -viewRotation); + goog.vec.Mat4.translate(projectionMatrix, imageExtent.minX - viewCenter.x, imageExtent.minY - viewCenter.y, 0); - goog.vec.Mat4.scale(vertexCoordMatrix, + goog.vec.Mat4.scale(projectionMatrix, imageExtent.getWidth() / 2, imageExtent.getHeight() / 2, 1); - goog.vec.Mat4.translate(vertexCoordMatrix, 1, 1, 0); + goog.vec.Mat4.translate(projectionMatrix, 1, 1, 0); }; diff --git a/src/ol/renderer/webgl/webgllayerrenderer.js b/src/ol/renderer/webgl/webgllayerrenderer.js index 067a4e054c..7199246d4b 100644 --- a/src/ol/renderer/webgl/webgllayerrenderer.js +++ b/src/ol/renderer/webgl/webgllayerrenderer.js @@ -100,7 +100,7 @@ ol.renderer.webgl.Layer.prototype.getTexture = goog.abstractMethod; /** * @return {!goog.vec.Mat4.Number} Matrix. */ -ol.renderer.webgl.Layer.prototype.getVertexCoordMatrix = goog.abstractMethod; +ol.renderer.webgl.Layer.prototype.getProjectionMatrix = goog.abstractMethod; /** diff --git a/src/ol/renderer/webgl/webglmaprenderer.js b/src/ol/renderer/webgl/webglmaprenderer.js index 62b03fc489..0870c376db 100644 --- a/src/ol/renderer/webgl/webglmaprenderer.js +++ b/src/ol/renderer/webgl/webglmaprenderer.js @@ -48,17 +48,17 @@ ol.renderer.webgl.map.shader.Fragment = function() { goog.base(this, [ 'precision mediump float;', '', - 'uniform mat4 uColorMatrix;', - 'uniform float uOpacity;', - 'uniform sampler2D uTexture;', + 'uniform mat4 u_colorMatrix;', + 'uniform float u_opacity;', + 'uniform sampler2D u_texture;', '', - 'varying vec2 vTexCoord;', + 'varying vec2 v_texCoord;', '', 'void main(void) {', '', - ' vec4 texColor = texture2D(uTexture, vTexCoord);', - ' vec4 color = uColorMatrix * vec4(texColor.rgb, 1.);', - ' color.a = texColor.a * uOpacity;', + ' vec4 texColor = texture2D(u_texture, v_texCoord);', + ' vec4 color = u_colorMatrix * vec4(texColor.rgb, 1.);', + ' color.a = texColor.a * u_opacity;', '', ' gl_FragColor = color;', '', @@ -77,17 +77,17 @@ goog.addSingletonGetter(ol.renderer.webgl.map.shader.Fragment); */ ol.renderer.webgl.map.shader.Vertex = function() { goog.base(this, [ - 'attribute vec2 aPosition;', - 'attribute vec2 aTexCoord;', + 'attribute vec2 a_position;', + 'attribute vec2 a_texCoord;', '', - 'uniform mat4 uTexCoordMatrix;', - 'uniform mat4 uVertexCoordMatrix;', + 'uniform mat4 u_texCoordMatrix;', + 'uniform mat4 u_projectionMatrix;', '', - 'varying vec2 vTexCoord;', + 'varying vec2 v_texCoord;', '', 'void main(void) {', - ' gl_Position = uVertexCoordMatrix * vec4(aPosition, 0., 1.);', - ' vTexCoord = (uTexCoordMatrix * vec4(aTexCoord, 0., 1.)).st;', + ' gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.);', + ' v_texCoord = (u_texCoordMatrix * vec4(a_texCoord, 0., 1.)).st;', '}' ].join('\n')); }; @@ -157,13 +157,13 @@ ol.renderer.webgl.Map = function(container, map) { /** * @private - * @type {{aPosition: number, - * aTexCoord: number, - * uColorMatrix: WebGLUniformLocation, - * uOpacity: WebGLUniformLocation, - * uTexture: WebGLUniformLocation, - * uTexCoordMatrix: WebGLUniformLocation, - * uVertexCoordMatrix: WebGLUniformLocation}|null} + * @type {{a_position: number, + * a_texCoord: number, + * u_colorMatrix: WebGLUniformLocation, + * u_opacity: WebGLUniformLocation, + * u_texture: WebGLUniformLocation, + * u_texCoordMatrix: WebGLUniformLocation, + * u_projectionMatrix: WebGLUniformLocation}|null} */ this.locations_ = null; @@ -522,13 +522,13 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) { gl.useProgram(program); if (goog.isNull(this.locations_)) { this.locations_ = { - aPosition: gl.getAttribLocation(program, 'aPosition'), - aTexCoord: gl.getAttribLocation(program, 'aTexCoord'), - uColorMatrix: gl.getUniformLocation(program, 'uColorMatrix'), - uTexCoordMatrix: gl.getUniformLocation(program, 'uTexCoordMatrix'), - uVertexCoordMatrix: gl.getUniformLocation(program, 'uVertexCoordMatrix'), - uOpacity: gl.getUniformLocation(program, 'uOpacity'), - uTexture: gl.getUniformLocation(program, 'uTexture') + a_position: gl.getAttribLocation(program, 'a_position'), + a_texCoord: gl.getAttribLocation(program, 'a_texCoord'), + u_colorMatrix: gl.getUniformLocation(program, 'u_colorMatrix'), + u_texCoordMatrix: gl.getUniformLocation(program, 'u_texCoordMatrix'), + u_projectionMatrix: gl.getUniformLocation(program, 'u_projectionMatrix'), + u_opacity: gl.getUniformLocation(program, 'u_opacity'), + u_texture: gl.getUniformLocation(program, 'u_texture') }; } @@ -546,13 +546,13 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) { gl.bindBuffer(goog.webgl.ARRAY_BUFFER, this.arrayBuffer_); } - gl.enableVertexAttribArray(this.locations_.aPosition); + gl.enableVertexAttribArray(this.locations_.a_position); gl.vertexAttribPointer( - this.locations_.aPosition, 2, goog.webgl.FLOAT, false, 16, 0); - gl.enableVertexAttribArray(this.locations_.aTexCoord); + this.locations_.a_position, 2, goog.webgl.FLOAT, false, 16, 0); + gl.enableVertexAttribArray(this.locations_.a_texCoord); gl.vertexAttribPointer( - this.locations_.aTexCoord, 2, goog.webgl.FLOAT, false, 16, 8); - gl.uniform1i(this.locations_.uTexture, 0); + this.locations_.a_texCoord, 2, goog.webgl.FLOAT, false, 16, 8); + gl.uniform1i(this.locations_.u_texture, 0); goog.array.forEach(frameState.layersArray, function(layer) { var layerState = frameState.layerStates[goog.getUid(layer)]; @@ -561,14 +561,14 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) { } var layerRenderer = this.getLayerRenderer(layer); gl.uniformMatrix4fv( - this.locations_.uTexCoordMatrix, false, + this.locations_.u_texCoordMatrix, false, layerRenderer.getTexCoordMatrix()); gl.uniformMatrix4fv( - this.locations_.uVertexCoordMatrix, false, - layerRenderer.getVertexCoordMatrix()); + this.locations_.u_projectionMatrix, false, + layerRenderer.getProjectionMatrix()); gl.uniformMatrix4fv( - this.locations_.uColorMatrix, false, layerRenderer.getColorMatrix()); - gl.uniform1f(this.locations_.uOpacity, layer.getOpacity()); + this.locations_.u_colorMatrix, false, layerRenderer.getColorMatrix()); + gl.uniform1f(this.locations_.u_opacity, layer.getOpacity()); gl.bindTexture(goog.webgl.TEXTURE_2D, layerRenderer.getTexture()); gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4); }, this); diff --git a/src/ol/renderer/webgl/webgltilelayerrenderer.js b/src/ol/renderer/webgl/webgltilelayerrenderer.js index 9b75e0d0b1..39d736c435 100644 --- a/src/ol/renderer/webgl/webgltilelayerrenderer.js +++ b/src/ol/renderer/webgl/webgltilelayerrenderer.js @@ -145,7 +145,7 @@ ol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) { * @private * @type {!goog.vec.Mat4.Number} */ - this.vertexCoordMatrix_ = goog.vec.Mat4.createNumberIdentity(); + this.projectionMatrix_ = goog.vec.Mat4.createNumberIdentity(); /** * @private @@ -246,8 +246,8 @@ ol.renderer.webgl.TileLayer.prototype.getTexture = function() { /** * @inheritDoc */ -ol.renderer.webgl.TileLayer.prototype.getVertexCoordMatrix = function() { - return this.vertexCoordMatrix_; +ol.renderer.webgl.TileLayer.prototype.getProjectionMatrix = function() { + return this.projectionMatrix_; }; @@ -299,7 +299,7 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = } else { var tileRangeSize = tileRange.getSize(); - var tileSize = tileGrid.getTileSize(); + var tileSize = tileGrid.getTileSize(z); var maxDimension = Math.max( tileRangeSize.width * tileSize.width, diff --git a/src/ol/source/bingmaps.exports b/src/ol/source/bingmaps.exports index 516bf8777c..8f2a2384f2 100644 --- a/src/ol/source/bingmaps.exports +++ b/src/ol/source/bingmaps.exports @@ -1,7 +1 @@ @exportSymbol ol.source.BingMaps -@exportSymbol ol.BingMapsStyle -@exportProperty ol.BingMapsStyle.AERIAL -@exportProperty ol.BingMapsStyle.AERIAL_WITH_LABELS -@exportProperty ol.BingMapsStyle.ROAD -@exportProperty ol.BingMapsStyle.ORDNANCE_SURVEY -@exportProperty ol.BingMapsStyle.COLLINS_BART diff --git a/src/ol/source/bingmapssource.js b/src/ol/source/bingmapssource.js index 1e5355904c..7cd7a27155 100644 --- a/src/ol/source/bingmapssource.js +++ b/src/ol/source/bingmapssource.js @@ -1,4 +1,3 @@ -goog.provide('ol.BingMapsStyle'); goog.provide('ol.source.BingMaps'); goog.require('goog.Uri'); @@ -15,18 +14,6 @@ goog.require('ol.source.ImageTileSource'); goog.require('ol.tilegrid.XYZ'); -/** - * @enum {string} - */ -ol.BingMapsStyle = { - AERIAL: 'Aerial', - AERIAL_WITH_LABELS: 'AerialWithLabels', - ROAD: 'Road', - ORDNANCE_SURVEY: 'OrdnanceSurvey', - COLLINS_BART: 'CollinsBart' -}; - - /** * @constructor diff --git a/src/ol/source/debugtilesource.js b/src/ol/source/debugtilesource.js index 8cd712d584..e553081ae3 100644 --- a/src/ol/source/debugtilesource.js +++ b/src/ol/source/debugtilesource.js @@ -33,7 +33,7 @@ ol.DebugTile_ = function(tileCoord, tileGrid) { * @private * @type {ol.Size} */ - this.tileSize_ = tileGrid.getTileSize(); + this.tileSize_ = tileGrid.getTileSize(tileCoord.z); /** * @private diff --git a/src/ol/source/tiledwmssource.js b/src/ol/source/tiledwmssource.js index c3e3838b98..9c7eb5ec8c 100644 --- a/src/ol/source/tiledwmssource.js +++ b/src/ol/source/tiledwmssource.js @@ -46,9 +46,6 @@ ol.source.TiledWMS = function(tiledWMSOptions) { 'FORMAT': 'image/png', 'TRANSPARENT': true }; - var tileSize = tileGrid.getTileSize(); - baseParams['WIDTH'] = tileSize.width; - baseParams['HEIGHT'] = tileSize.height; baseParams[version >= '1.3' ? 'CRS' : 'SRS'] = projection.getCode(); goog.object.extend(baseParams, tiledWMSOptions.params); diff --git a/src/ol/sphere/normal.js b/src/ol/sphere/normal.js new file mode 100644 index 0000000000..e07bf000b4 --- /dev/null +++ b/src/ol/sphere/normal.js @@ -0,0 +1,10 @@ +goog.provide('ol.sphere.NORMAL'); + +goog.require('ol.Sphere'); + + +/** + * The normal sphere. + * @const {ol.Sphere} + */ +ol.sphere.NORMAL = new ol.Sphere(6370997); diff --git a/src/ol/sphere/wgs84.js b/src/ol/sphere/wgs84.js new file mode 100644 index 0000000000..e30aafeb4b --- /dev/null +++ b/src/ol/sphere/wgs84.js @@ -0,0 +1,10 @@ +goog.provide('ol.sphere.WGS84'); + +goog.require('ol.Sphere'); + + +/** + * A sphere with radius equal to the semi-major axis of the WGS84 ellipsoid. + * @const {ol.Sphere} + */ +ol.sphere.WGS84 = new ol.Sphere(6378137); diff --git a/src/ol/tilegrid/tilegrid.js b/src/ol/tilegrid/tilegrid.js index 7b65dd5cdb..415557d93e 100644 --- a/src/ol/tilegrid/tilegrid.js +++ b/src/ol/tilegrid/tilegrid.js @@ -58,6 +58,19 @@ ol.tilegrid.TileGrid = function(tileGridOptions) { this.origins_ = tileGridOptions.origins; goog.asserts.assert(this.origins_.length == this.resolutions_.length); } + goog.asserts.assert( + (goog.isNull(this.origin_) && !goog.isNull(this.origins_)) || + (!goog.isNull(this.origin_) && goog.isNull(this.origins_))); + + /** + * @private + * @type {Array.} + */ + this.tileSizes_ = null; + if (goog.isDef(tileGridOptions.tileSizes)) { + this.tileSizes_ = tileGridOptions.tileSizes; + goog.asserts.assert(this.tileSizes_.length == this.resolutions_.length); + } /** * @private @@ -65,7 +78,11 @@ ol.tilegrid.TileGrid = function(tileGridOptions) { */ this.tileSize_ = goog.isDef(tileGridOptions.tileSize) ? tileGridOptions.tileSize : - new ol.Size(ol.DEFAULT_TILE_SIZE, ol.DEFAULT_TILE_SIZE); + goog.isNull(this.tileSizes_) ? + new ol.Size(ol.DEFAULT_TILE_SIZE, ol.DEFAULT_TILE_SIZE) : null; + goog.asserts.assert( + (goog.isNull(this.tileSize_) && !goog.isNull(this.tileSizes_)) || + (!goog.isNull(this.tileSize_) && goog.isNull(this.tileSizes_))); }; @@ -114,7 +131,7 @@ ol.tilegrid.TileGrid.prototype.getOrigin = function(z) { ol.tilegrid.TileGrid.prototype.getPixelBoundsForTileCoordAndResolution = function(tileCoord, resolution) { var scale = resolution / this.getResolution(tileCoord.z); - var tileSize = this.getTileSize(); + var tileSize = this.getTileSize(tileCoord.z); tileSize = new ol.Size(tileSize.width / scale, tileSize.height / scale); var minX, maxX, minY, maxY; @@ -152,7 +169,7 @@ ol.tilegrid.TileGrid.prototype.getResolutions = function() { ol.tilegrid.TileGrid.prototype.getTileRangeExtent = function(z, tileRange) { var origin = this.getOrigin(z); var resolution = this.getResolution(z); - var tileSize = this.tileSize_; + var tileSize = this.getTileSize(z); var minX = origin.x + tileRange.minX * tileSize.width * resolution; var minY = origin.y + tileRange.minY * tileSize.height * resolution; var maxX = origin.x + (tileRange.maxX + 1) * tileSize.width * resolution; @@ -194,7 +211,7 @@ ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndZ = function(extent, z) { ol.tilegrid.TileGrid.prototype.getTileCoordCenter = function(tileCoord) { var origin = this.getOrigin(tileCoord.z); var resolution = this.getResolution(tileCoord.z); - var tileSize = this.tileSize_; + var tileSize = this.getTileSize(tileCoord.z); var x = origin.x + (tileCoord.x + 0.5) * tileSize.width * resolution; var y = origin.y + (tileCoord.y + 0.5) * tileSize.height * resolution; return new ol.Coordinate(x, y); @@ -208,7 +225,7 @@ ol.tilegrid.TileGrid.prototype.getTileCoordCenter = function(tileCoord) { ol.tilegrid.TileGrid.prototype.getTileCoordExtent = function(tileCoord) { var origin = this.getOrigin(tileCoord.z); var resolution = this.getResolution(tileCoord.z); - var tileSize = this.tileSize_; + var tileSize = this.getTileSize(tileCoord.z); var minX = origin.x + tileCoord.x * tileSize.width * resolution; var minY = origin.y + tileCoord.y * tileSize.height * resolution; var maxX = minX + tileSize.width * resolution; @@ -246,7 +263,7 @@ ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution_ = function( var z = this.getZForResolution(resolution); var scale = resolution / this.getResolution(z); var origin = this.getOrigin(z); - var tileSize = this.getTileSize(); + var tileSize = this.getTileSize(z); var x = scale * (coordinate.x - origin.x) / (resolution * tileSize.width); var y = scale * (coordinate.y - origin.y) / (resolution * tileSize.height); @@ -286,10 +303,17 @@ ol.tilegrid.TileGrid.prototype.getTileCoordResolution = function(tileCoord) { /** + * @param {number} z Z. * @return {ol.Size} Tile size. */ -ol.tilegrid.TileGrid.prototype.getTileSize = function() { - return this.tileSize_; +ol.tilegrid.TileGrid.prototype.getTileSize = function(z) { + if (!goog.isNull(this.tileSize_)) { + return this.tileSize_; + } else { + goog.asserts.assert(!goog.isNull(this.tileSizes_)); + goog.asserts.assert(0 <= z && z < this.tileSizes_.length); + return this.tileSizes_[z]; + } }; diff --git a/src/ol/tileurlfunction.js b/src/ol/tileurlfunction.js index e5e3dfc3e6..d64c57ec9e 100644 --- a/src/ol/tileurlfunction.js +++ b/src/ol/tileurlfunction.js @@ -86,7 +86,11 @@ ol.TileUrlFunction.createBboxParam = var bboxValues = axisOrientation.substr(0, 2) == 'ne' ? [tileExtent.minY, tileExtent.minX, tileExtent.maxY, tileExtent.maxX] : [tileExtent.minX, tileExtent.minY, tileExtent.maxX, tileExtent.maxY]; - return goog.uri.utils.appendParam(baseUrl, 'BBOX', bboxValues.join(',')); + var tileSize = tileGrid.getTileSize(tileCoord.z); + return goog.uri.utils.appendParams(baseUrl, + 'BBOX', bboxValues.join(','), + 'HEIGHT', tileSize.height, + 'WIDTH', tileSize.width); } }; }; diff --git a/src/ol/transformfunction.js b/src/ol/transformfunction.js index a8be2c0f28..b5fb315d69 100644 --- a/src/ol/transformfunction.js +++ b/src/ol/transformfunction.js @@ -1,9 +1,12 @@ goog.provide('ol.TransformFunction'); -goog.require('ol.Coordinate'); - /** - * @typedef {function(ol.Coordinate): ol.Coordinate} + * A transform function accepts an array of input coordinate values, an optional + * output array, and an optional dimension (default should be 2). The function + * transforms the input coordinate values, populates the output array, and + * returns the output array. + * + * @typedef {function(Array., Array.=, number=): Array.} */ ol.TransformFunction; diff --git a/src/ol/view.js b/src/ol/view.js index f9303af991..61fba43f46 100644 --- a/src/ol/view.js +++ b/src/ol/view.js @@ -11,7 +11,7 @@ goog.require('ol.Object'); */ ol.ViewHint = { ANIMATING: 0, - PANNING: 1 + INTERACTING: 1 }; diff --git a/test/spec/ol/color.test.js b/test/spec/ol/color.test.js index 3daeb97b0c..1e79f7f7f7 100644 --- a/test/spec/ol/color.test.js +++ b/test/spec/ol/color.test.js @@ -71,3 +71,5 @@ describe('ol.Color', function() { }); }); + +goog.require('ol.Color'); diff --git a/test/spec/ol/ellipsoid.test.js b/test/spec/ol/ellipsoid.test.js index cf65f8d23f..9692792ecd 100644 --- a/test/spec/ol/ellipsoid.test.js +++ b/test/spec/ol/ellipsoid.test.js @@ -388,4 +388,5 @@ describe('ol.Ellipsoid', function() { goog.require('ol.Coordinate'); +goog.require('ol.Ellipsoid'); goog.require('ol.ellipsoid.WGS84'); diff --git a/test/spec/ol/extent.test.js b/test/spec/ol/extent.test.js index e3f0f4a321..9737ab9334 100644 --- a/test/spec/ol/extent.test.js +++ b/test/spec/ol/extent.test.js @@ -52,17 +52,17 @@ describe('ol.Extent', function() { expect(extent.containsCoordinate( new ol.Coordinate(3, 1))).toBeFalsy(); expect(extent.containsCoordinate( - new ol.Coordinate(3, 5))).toBeFalsy(); + new ol.Coordinate(3, 5))).toBeFalsy(); expect(extent.containsCoordinate( - new ol.Coordinate(4, 1))).toBeFalsy(); + new ol.Coordinate(4, 1))).toBeFalsy(); expect(extent.containsCoordinate( - new ol.Coordinate(4, 2))).toBeFalsy(); + new ol.Coordinate(4, 2))).toBeFalsy(); expect(extent.containsCoordinate( - new ol.Coordinate(4, 3))).toBeFalsy(); + new ol.Coordinate(4, 3))).toBeFalsy(); expect(extent.containsCoordinate( - new ol.Coordinate(4, 4))).toBeFalsy(); + new ol.Coordinate(4, 4))).toBeFalsy(); expect(extent.containsCoordinate( - new ol.Coordinate(4, 5))).toBeFalsy(); + new ol.Coordinate(4, 5))).toBeFalsy(); }); }); }); @@ -84,8 +84,8 @@ describe('ol.Extent', function() { }); it('takes arbitrary function', function() { - var transformFn = function(coordinate) { - return new ol.Coordinate(-coordinate.x, -coordinate.y); + var transformFn = function(input) { + return [-input[0], -input[1], -input[2], -input[3]]; }; var sourceExtent = new ol.Extent(-15, -30, 45, 60); var destinationExtent = sourceExtent.transform(transformFn); @@ -100,5 +100,6 @@ describe('ol.Extent', function() { }); }); +goog.require('ol.Coordinate'); goog.require('ol.Extent'); goog.require('ol.projection'); diff --git a/test/spec/ol/layer/layer.test.js b/test/spec/ol/layer/layer.test.js index 299279a1ee..2b5c567162 100644 --- a/test/spec/ol/layer/layer.test.js +++ b/test/spec/ol/layer/layer.test.js @@ -276,4 +276,6 @@ describe('ol.layer.Layer', function() { }); +goog.require('ol.layer.Layer'); goog.require('ol.projection'); +goog.require('ol.source.Source'); diff --git a/test/spec/ol/lrucache.test.js b/test/spec/ol/lrucache.test.js index 587724e36a..6cf2768a69 100644 --- a/test/spec/ol/lrucache.test.js +++ b/test/spec/ol/lrucache.test.js @@ -187,3 +187,5 @@ describe('ol.structs.LRUCache', function() { }); }); + +goog.require('ol.structs.LRUCache'); diff --git a/test/spec/ol/map.test.js b/test/spec/ol/map.test.js index db5ed7f546..776d268400 100644 --- a/test/spec/ol/map.test.js +++ b/test/spec/ol/map.test.js @@ -79,7 +79,8 @@ describe('ol.Map', function() { mouseWheelZoom: false, shiftDragZoom: false, touchPan: false, - touchRotateZoom: false + touchRotate: false, + touchZoom: false }; }); @@ -245,6 +246,9 @@ goog.require('ol.Collection'); goog.require('ol.Coordinate'); goog.require('ol.Map'); goog.require('ol.RendererHint'); +goog.require('ol.RendererHints'); goog.require('ol.View2D'); +goog.require('ol.interaction.DblClickZoom'); +goog.require('ol.interaction.MouseWheelZoom'); goog.require('ol.layer.TileLayer'); goog.require('ol.source.XYZ'); diff --git a/test/spec/ol/parser/ogc/wmtscapabilities_v1_0_0.test.js b/test/spec/ol/parser/ogc/wmtscapabilities_v1_0_0.test.js index af7b43cd8d..2f5a012fe2 100644 --- a/test/spec/ol/parser/ogc/wmtscapabilities_v1_0_0.test.js +++ b/test/spec/ol/parser/ogc/wmtscapabilities_v1_0_0.test.js @@ -105,26 +105,24 @@ describe('ol.parser.ogc.wmtscapabilities_v1_0_0', function() { expect(wgs84Bbox.maxX).toEqual(180.0); expect(wgs84Bbox.minY).toEqual(-90.0); expect(wgs84Bbox.maxY).toEqual(90.0); - expect(layer.resourceUrl.tile.format).toEqual('image/png'); - var tpl = 'http://www.example.com/wmts/coastlines/{TileMatrix}/' + - '{TileRow}/{TileCol}.png'; - expect(layer.resourceUrl.tile.template).toEqual(tpl); - var format = 'application/gml+xml; version=3.1'; - expect(layer.resourceUrl.FeatureInfo.format).toEqual(format); - tpl = 'http://www.example.com/wmts/coastlines/{TileMatrixSet}/' + - '{TileMatrix}/{TileRow}/{TileCol}/{J}/{I}.xml'; - expect(layer.resourceUrl.FeatureInfo.template).toEqual(tpl); - expect(layer.resourceUrls[0].format).toEqual('image/png'); - expect(layer.resourceUrls[0].resourceType).toEqual('tile'); - tpl = 'http://www.example.com/wmts/coastlines/{TileMatrix}/' + + expect(layer.resourceUrls.hasOwnProperty('tile')).toBeTruthy(); + var format = 'image/png'; + expect(layer.resourceUrls.tile.hasOwnProperty(format)).toBeTruthy(); + expect(layer.resourceUrls.tile[format].length).toEqual(2); + var tpl = 'http://a.example.com/wmts/coastlines/{TileMatrix}/' + '{TileRow}/{TileCol}.png'; - expect(layer.resourceUrls[0].template).toEqual(tpl); + expect(layer.resourceUrls.tile[format][0]).toEqual(tpl); + tpl = 'http://b.example.com/wmts/coastlines/{TileMatrix}/' + + '{TileRow}/{TileCol}.png'; + expect(layer.resourceUrls.tile[format][1]).toEqual(tpl); + expect(layer.resourceUrls.hasOwnProperty('FeatureInfo')).toBeTruthy(); format = 'application/gml+xml; version=3.1'; - expect(layer.resourceUrls[1].format).toEqual(format); - expect(layer.resourceUrls[1].resourceType).toEqual('FeatureInfo'); + expect(layer.resourceUrls.FeatureInfo.hasOwnProperty(format)) + .toBeTruthy(); + expect(layer.resourceUrls.FeatureInfo[format].length).toEqual(1); tpl = 'http://www.example.com/wmts/coastlines/{TileMatrixSet}/' + '{TileMatrix}/{TileRow}/{TileCol}/{J}/{I}.xml'; - expect(layer.resourceUrls[1].template).toEqual(tpl); + expect(layer.resourceUrls.FeatureInfo[format][0]).toEqual(tpl); expect(dimensions.length).toEqual(1); expect(dimensions[0].title).toEqual('Time'); expect(dimensions[0]['abstract']).toEqual('Monthly datasets'); @@ -180,4 +178,5 @@ describe('ol.parser.ogc.wmtscapabilities_v1_0_0', function() { }); goog.require('goog.net.XhrIo'); +goog.require('ol.Extent'); goog.require('ol.parser.ogc.WMTSCapabilities'); diff --git a/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/ogcsample.xml b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/ogcsample.xml index 9f0f1bc690..0421214ffc 100644 --- a/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/ogcsample.xml +++ b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/ogcsample.xml @@ -74,7 +74,9 @@ coastlines + template="http://a.example.com/wmts/coastlines/{TileMatrix}/{TileRow}/{TileCol}.png" /> +