diff --git a/examples/standalone/wms-standalone.html b/examples/standalone/wms-standalone.html new file mode 100644 index 0000000000..2544878635 --- /dev/null +++ b/examples/standalone/wms-standalone.html @@ -0,0 +1,23 @@ + + + + + + + + + ol3 full-screen demo + + + +
+ + + diff --git a/examples/wms.html b/examples/wms.html new file mode 100644 index 0000000000..5ed1d5392d --- /dev/null +++ b/examples/wms.html @@ -0,0 +1,47 @@ + + + + + + + + + wms example + + +
+
+

Tiled WMS example

+
Example of a tiled WMS layer.
+
+

See the + wms.js source + to see how this is done.

+
+
+
+
wms, tile, tilelayer
+ + + diff --git a/examples/wms.js b/examples/wms.js new file mode 100644 index 0000000000..7f53e21c07 --- /dev/null +++ b/examples/wms.js @@ -0,0 +1,33 @@ +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.source.MapQuestOpenAerial'); +goog.require('ol.source.TiledWMS'); + + +if (goog.DEBUG) { + goog.debug.Console.autoInstall(); + goog.debug.Logger.getLogger('ol').setLevel(goog.debug.Logger.Level.INFO); +} + + +var layers = new ol.Collection([ + new ol.layer.TileLayer({ + source: new ol.source.MapQuestOpenAerial() + }), + new ol.layer.TileLayer({ + source: new ol.source.TiledWMS({ + url: 'http://demo.opengeo.org/geoserver/wms', + params: {'LAYERS': 'topp:states', 'TILED': true} + }) + }) +]); +var map = new ol.Map({ + center: new ol.Coordinate(-10997148, 4569099), + layers: layers, + target: 'map', + zoom: 4 +}); diff --git a/src/objectliterals.exports b/src/objectliterals.exports index bd7499907b..1117bd1909 100644 --- a/src/objectliterals.exports +++ b/src/objectliterals.exports @@ -59,3 +59,14 @@ @exportObjectLiteralProperty ol.source.BingMapsOptions.culture string|undefined @exportObjectLiteralProperty ol.source.BingMapsOptions.key string @exportObjectLiteralProperty ol.source.BingMapsOptions.style ol.BingMapsStyle + +@exportObjectLiteral ol.source.TiledWMSOptions +@exportObjectLiteralProperty ol.source.TiledWMSOptions.params Object +@exportObjectLiteralProperty ol.source.TiledWMSOptions.version string|undefined +@exportObjectLiteralProperty ol.source.TiledWMSOptions.crossOrigin string|undefined +@exportObjectLiteralProperty ol.source.TiledWMSOptions.extent ol.Extent|undefined +@exportObjectLiteralProperty ol.source.TiledWMSOptions.tileGrid ol.tilegrid.TileGrid|undefined +@exportObjectLiteralProperty ol.source.TiledWMSOptions.maxZoom number|undefined +@exportObjectLiteralProperty ol.source.TiledWMSOptions.projection ol.Projection|undefined +@exportObjectLiteralProperty ol.source.TiledWMSOptions.url string|undefined +@exportObjectLiteralProperty ol.source.TiledWMSOptions.urls Array.|undefined diff --git a/src/ol/source/tiledwms.exports b/src/ol/source/tiledwms.exports new file mode 100644 index 0000000000..7d26e4f685 --- /dev/null +++ b/src/ol/source/tiledwms.exports @@ -0,0 +1 @@ +@exportSymbol ol.source.TiledWMS \ No newline at end of file diff --git a/src/ol/source/tiledwmssource.js b/src/ol/source/tiledwmssource.js new file mode 100644 index 0000000000..efbfe447df --- /dev/null +++ b/src/ol/source/tiledwmssource.js @@ -0,0 +1,131 @@ +// FIXME add minZoom support + +goog.provide('ol.source.TiledWMS'); +goog.provide('ol.source.TiledWMSOptions'); + +goog.require('goog.asserts'); +goog.require('goog.object'); +goog.require('ol.Attribution'); +goog.require('ol.Projection'); +goog.require('ol.TileCoord'); +goog.require('ol.TileUrlFunction'); +goog.require('ol.source.TileSource'); +goog.require('ol.tilegrid.TileGrid'); + + +/** + * @typedef {{attributions: (Array.|undefined), + * params: Object, + * version: (string|undefined), + * crossOrigin: (string|undefined), + * extent: (ol.Extent|undefined), + * tileGrid: (ol.tilegrid.TileGrid|undefined), + * maxZoom: (number|undefined), + * projection: (ol.Projection|undefined), + * url: (string|undefined), + * urls: (Array.|undefined)}} + */ +ol.source.TiledWMSOptions; + + + +/** + * @constructor + * @extends {ol.source.TileSource} + * @param {ol.source.TiledWMSOptions} tiledWMSOptions options. + */ +ol.source.TiledWMS = function(tiledWMSOptions) { + goog.asserts.assert(tiledWMSOptions.params); + + var projection = goog.isDef(tiledWMSOptions.projection) ? + tiledWMSOptions.projection : ol.Projection.getFromCode('EPSG:3857'); + + var extent = goog.isDef(tiledWMSOptions.extent) ? + tiledWMSOptions.extent : projection.getExtent(); + + var version = goog.isDef(tiledWMSOptions.version) ? + tiledWMSOptions.version : '1.3'; + + var tileGrid = tiledWMSOptions.tileGrid; + if (!goog.isDef(tileGrid)) { + // FIXME Factor this out to a more central/generic place. + var size = Math.max(extent.maxX - extent.minX, extent.maxY - extent.minY); + var maxZoom = goog.isDef(tiledWMSOptions.maxZoom) ? + tiledWMSOptions.maxZoom : 18; + var resolutions = new Array(maxZoom + 1); + for (var z = 0, zz = resolutions.length; z < zz; ++z) { + resolutions[z] = size / (256 << z); + } + tileGrid = new ol.tilegrid.TileGrid({ + origin: extent.getTopLeft(), + resolutions: resolutions + }); + } + + function tileUrlFunction(tileCoord) { + if (goog.isNull(tileCoord)) { + return undefined; + } + var tileSize = tileGrid.getTileSize(); + var tileExtent = tileGrid.getTileCoordExtent(tileCoord); + var params = { + 'SERVICE': 'WMS', + 'VERSION': version, + 'REQUEST': 'GetMap', + 'WIDTH': tileSize.width, + 'HEIGHT': tileSize.height, + 'STYLES': '', + 'FORMAT': 'image/png', + 'TRANSPARENT': true, + // FIXME Projection dependant axis order. + 'BBOX': [ + tileExtent.minX, tileExtent.minY, tileExtent.maxX, tileExtent.maxY + ].join(',') + }; + params[version >= '1.3' ? 'CRS' : 'SRS'] = projection.getCode(); + goog.object.extend(params, tiledWMSOptions.params); + var url = tiledWMSOptions.urls ? + tiledWMSOptions.urls[goog.math.modulo( + tileCoord.hash(), tiledWMSOptions.urls.length)] : + tiledWMSOptions.url; + for (var param in params) { + url += (~url.indexOf('?') ? '&' : '?') + + param + '=' + encodeURIComponent(params[param]); + } + return url; + } + + function tileCoordTransform(tileCoord) { + if (tileGrid.getResolutions().length <= tileCoord.z) { + return null; + } + var x = tileCoord.x; + var projectionExtent = projection.getExtent(); + // FIXME do we want a wrapDateLine param? The code below will break maps + // with projections that do not span the whole world width. + if (extent.minX === projectionExtent.minX && + extent.maxX === projectionExtent.maxX) { + var n = 1 << tileCoord.z; + x = goog.math.modulo(x, n); + } + var tileExtent = tileGrid.getTileCoordExtent( + new ol.TileCoord(tileCoord.z, x, tileCoord.y)); + // FIXME We shouldn't need a typecast here. + if (!tileExtent.intersects(/** @type {ol.Extent} */ (extent))) { + return null; + } + return new ol.TileCoord(tileCoord.z, x, tileCoord.y); + } + + goog.base(this, { + attributions: tiledWMSOptions.attributions, + crossOrigin: tiledWMSOptions.crossOrigin, + extent: extent, + tileGrid: tileGrid, + projection: projection, + tileUrlFunction: ol.TileUrlFunction.withTileCoordTransform( + tileCoordTransform, tileUrlFunction) + }); + +}; +goog.inherits(ol.source.TiledWMS, ol.source.TileSource);