diff --git a/examples/data/osm/map.osm b/examples/data/osm/map.osm deleted file mode 100644 index 135e798e1d..0000000000 --- a/examples/data/osm/map.osm +++ /dev/null @@ -1,2223 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/tile-vector.html b/examples/tile-vector.html new file mode 100644 index 0000000000..e6b7167c85 --- /dev/null +++ b/examples/tile-vector.html @@ -0,0 +1,51 @@ + + + + + + + + + + + Tile vector example + + + + + +
+ +
+
+
+
+
+ +
+ +
+

Tile vector example

+

Example of vector tiles from openstreetmap.us.

+
+

See the tile-vector.js source to see how this is done.

+
+
tile-vector, openstreetmap
+
+ +
+ +
+ + + + + + + diff --git a/examples/tile-vector.js b/examples/tile-vector.js new file mode 100644 index 0000000000..d980e62bbc --- /dev/null +++ b/examples/tile-vector.js @@ -0,0 +1,85 @@ +goog.require('ol.Map'); +goog.require('ol.View2D'); +goog.require('ol.format.TopoJSON'); +goog.require('ol.layer.Vector'); +goog.require('ol.proj'); +goog.require('ol.source.TileVector'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Stroke'); +goog.require('ol.style.Style'); +goog.require('ol.tilegrid.XYZ'); + +var waterLayer = new ol.layer.Vector({ + source: new ol.source.TileVector({ + format: new ol.format.TopoJSON({ + defaultProjection: 'EPSG:4326' + }), + projection: 'EPSG:3857', + tileGrid: new ol.tilegrid.XYZ({ + maxZoom: 19 + }), + url: 'http://{a-c}.tile.openstreetmap.us/' + + 'vectiles-water-areas/{z}/{x}/{y}.topojson' + }), + style: new ol.style.Style({ + fill: new ol.style.Fill({ + color: '#9db9e8' + }) + }) +}); + +var roadStyleCache = {}; +var roadLayer = new ol.layer.Vector({ + source: new ol.source.TileVector({ + format: new ol.format.TopoJSON({ + defaultProjection: 'EPSG:4326' + }), + projection: 'EPSG:3857', + tileGrid: new ol.tilegrid.XYZ({ + maxZoom: 19 + }), + url: 'http://{a-c}.tile.openstreetmap.us/' + + 'vectiles-highroad/{z}/{x}/{y}.topojson' + }), + style: function(feature, resolution) { + var kind = feature.get('kind'); + var railway = feature.get('railway'); + var sort_key = feature.get('sort_key'); + var styleKey = kind + '/' + railway + '/' + sort_key; + var styleArray = roadStyleCache[styleKey]; + if (!styleArray) { + var color, width; + if (railway) { + color = '#7de'; + width = 1; + } else { + color = { + 'major_road': '#776', + 'minor_road': '#ccb', + 'highway': '#f39' + }[kind]; + width = kind == 'highway' ? 1.5 : 1; + } + styleArray = [new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: color, + width: width + }), + zIndex: sort_key + })]; + roadStyleCache[styleKey] = styleArray; + } + return styleArray; + } +}); + +var map = new ol.Map({ + layers: [waterLayer, roadLayer], + renderer: 'canvas', + target: document.getElementById('map'), + view: new ol.View2D({ + center: ol.proj.transform([-74.0064, 40.7142], 'EPSG:4326', 'EPSG:3857'), + maxZoom: 19, + zoom: 14 + }) +}); diff --git a/examples/vector-osm.html b/examples/vector-osm.html index 6a0e5ea7ef..67400eee6f 100644 --- a/examples/vector-osm.html +++ b/examples/vector-osm.html @@ -32,11 +32,11 @@

OSM XML example

-

Example of using the OSM XML source.

+

Example of using the OSM XML source. Vector data is loaded dynamically from a server using a tiling strategy.

See the vector-osm.js source to see how this is done.

-
vector, osm, xml
+
vector, osm, xml, loading, server
diff --git a/examples/vector-osm.js b/examples/vector-osm.js index 7f870fd26e..5834ef230e 100644 --- a/examples/vector-osm.js +++ b/examples/vector-osm.js @@ -1,13 +1,17 @@ goog.require('ol.Map'); goog.require('ol.View2D'); +goog.require('ol.format.OSMXML'); goog.require('ol.layer.Tile'); goog.require('ol.layer.Vector'); +goog.require('ol.loadingstrategy'); +goog.require('ol.proj'); goog.require('ol.source.BingMaps'); -goog.require('ol.source.OSMXML'); +goog.require('ol.source.ServerVector'); goog.require('ol.style.Circle'); goog.require('ol.style.Fill'); goog.require('ol.style.Stroke'); goog.require('ol.style.Style'); +goog.require('ol.tilegrid.XYZ'); var styles = { 'amenity': { @@ -83,9 +87,21 @@ var styles = { } }; -var vectorSource = new ol.source.OSMXML({ - projection: 'EPSG:3857', - url: 'data/osm/map.osm' +var vectorSource = new ol.source.ServerVector({ + format: new ol.format.OSMXML(), + loader: function(extent, resolution, projection) { + var transform = ol.proj.getTransform(projection, 'EPSG:4326'); + var epsg4326Extent = transform(extent, []); + var url = 'http://overpass-api.de/api/xapi?map?bbox=' + + epsg4326Extent.join(','); + $.ajax(url).then(function(response) { + vectorSource.addFeatures(vectorSource.readFeatures(response)); + }); + }, + strategy: ol.loadingstrategy.createTile(new ol.tilegrid.XYZ({ + maxZoom: 19 + })), + projection: 'EPSG:3857' }); var vector = new ol.layer.Vector({ @@ -117,6 +133,7 @@ var map = new ol.Map({ target: document.getElementById('map'), view: new ol.View2D({ center: [739218, 5906096], + maxZoom: 19, zoom: 17 }) }); diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 3083d5e950..f3b1a22684 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -668,6 +668,15 @@ * @todo stability experimental */ +/** + * @typedef {Object} olx.source.FormatVectorOptions + * @property {Array.|undefined} attributions Attributions. + * @property {ol.Extent|undefined} extent Extent. + * @property {ol.format.Feature} format Format. + * @property {string|undefined} logo Logo. + * @property {ol.proj.ProjectionLike} projection Projection. + */ + /** * @typedef {Object} olx.source.GeoJSONOptions * @property {Array.|undefined} attributions Attributions. @@ -698,6 +707,25 @@ * @property {Array.|undefined} urls URLs. */ +/** + * @typedef {Object} olx.source.TileVectorOptions + * @property {Array.|undefined} attributions Attributions. + * @property {ol.proj.ProjectionLike} defaultProjection Default projection. + * @property {ol.Extent|undefined} extent Extent. + * @property {string|undefined} logo Logo. + * @property {GeoJSONObject|undefined} object Object. + * @property {ol.proj.ProjectionLike} projection Destination projection. If + * provided, features will be transformed to this projection. If not + * provided, features will not be transformed. + * @property {ol.tilegrid.TileGrid} tileGrid Tile grid. + * @property {ol.TileUrlFunctionType|undefined} tileUrlFunction Optional + * function to get tile URL given a tile coordinate and the projection. + * Required if url or urls are not provided. + * @property {string|undefined} url URL template. Must include `{x}`, `{y}`, + * and `{z}` placeholders. + * @property {Array.|undefined} urls An array of URL templates. + */ + /** * @typedef {Object} olx.source.TopoJSONOptions * @property {Array.|undefined} attributions Attributions. @@ -895,6 +923,17 @@ * @property {string} url Url. */ +/** + * @typedef {Object} olx.source.ServerVectorOptions + * @property {Array.|undefined} attributions Attributions. + * @property {ol.Extent|undefined} extent Extent. + * @property {ol.format.Feature} format Format. + * @property {function(this: ol.source.ServerVector, ol.Extent, number, ol.proj.Projection)} loader Loading function. + * @property {function(ol.Extent, number): Array.|undefined} strategy Loading strategy. Default is `ol.loadingstrategy.bbox`. + * @property {string|undefined} logo Logo. + * @property {ol.proj.ProjectionLike} projection Projection. + */ + /** * @typedef {Object} olx.source.TileJSONOptions * @property {null|string|undefined} crossOrigin crossOrigin setting for image @@ -952,7 +991,7 @@ */ /** - * @typedef {Object} olx.source.VectorFileOptions + * @typedef {Object} olx.source.StaticVectorOptions * @property {ArrayBuffer|undefined} arrayBuffer Array buffer. * @property {Array.|undefined} attributions Attributions. * @property {Document|undefined} doc Document. diff --git a/src/ol/extent.js b/src/ol/extent.js index ba146637fc..10f36db01d 100644 --- a/src/ol/extent.js +++ b/src/ol/extent.js @@ -597,6 +597,17 @@ ol.extent.isEmpty = function(extent) { }; +/** + * @param {ol.Extent} extent Extent. + * @return {boolean} Is infinite. + * @todo stability experimental + */ +ol.extent.isInfinite = function(extent) { + return extent[0] == -Infinity || extent[1] == -Infinity || + extent[2] == Infinity || extent[3] == Infinity; +}; + + /** * @param {ol.Extent} extent Extent. * @param {ol.Coordinate} coordinate Coordinate. diff --git a/src/ol/format/osmxmlformat.exports b/src/ol/format/osmxmlformat.exports new file mode 100644 index 0000000000..e9bb1a6835 --- /dev/null +++ b/src/ol/format/osmxmlformat.exports @@ -0,0 +1 @@ +@exportSymbol ol.format.OSMXML diff --git a/src/ol/loadingstrategy.exports b/src/ol/loadingstrategy.exports new file mode 100644 index 0000000000..711262d776 --- /dev/null +++ b/src/ol/loadingstrategy.exports @@ -0,0 +1,3 @@ +@exportSymbol ol.loadingstrategy.all +@exportSymbol ol.loadingstrategy.bbox +@exportSymbol ol.loadingstrategy.createTile diff --git a/src/ol/loadingstrategy.js b/src/ol/loadingstrategy.js new file mode 100644 index 0000000000..58a5dd4b3b --- /dev/null +++ b/src/ol/loadingstrategy.js @@ -0,0 +1,52 @@ +goog.provide('ol.loadingstrategy'); + +goog.require('ol.TileCoord'); + + +/** + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @return {Array.} Extents. + */ +ol.loadingstrategy.all = function(extent, resolution) { + return [[-Infinity, -Infinity, Infinity, Infinity]]; +}; + + +/** + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @return {Array.} Extents. + */ +ol.loadingstrategy.bbox = function(extent, resolution) { + return [extent]; +}; + + +/** + * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. + * @return {function(ol.Extent, number): Array.} Loading strategy. + */ +ol.loadingstrategy.createTile = function(tileGrid) { + return ( + /** + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @return {Array.} Extents. + */ + function(extent, resolution) { + var z = tileGrid.getZForResolution(resolution); + var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); + /** @type {Array.} */ + var extents = []; + var tileCoord = new ol.TileCoord(z, 0, 0); + for (tileCoord.x = tileRange.minX; tileCoord.x <= tileRange.maxX; + ++tileCoord.x) { + for (tileCoord.y = tileRange.minY; tileCoord.y <= tileRange.maxY; + ++tileCoord.y) { + extents.push(tileGrid.getTileCoordExtent(tileCoord)); + } + } + return extents; + }); +}; diff --git a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js index 4a59c94c9d..aa148b4d77 100644 --- a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js +++ b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js @@ -170,7 +170,9 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame = } var frameStateExtent = frameState.extent; - var frameStateResolution = frameState.view2DState.resolution; + var view2DState = frameState.view2DState; + var projection = view2DState.projection; + var resolution = view2DState.resolution; var pixelRatio = frameState.pixelRatio; var vectorLayerRevision = vectorLayer.getRevision(); var vectorLayerRenderOrder = vectorLayer.getRenderOrder(); @@ -179,7 +181,7 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame = } if (!this.dirty_ && - this.renderedResolution_ == frameStateResolution && + this.renderedResolution_ == resolution && this.renderedRevision_ == vectorLayerRevision && this.renderedRenderOrder_ == vectorLayerRenderOrder && ol.extent.containsExtent(this.renderedExtent_, frameStateExtent)) { @@ -204,9 +206,10 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame = if (!goog.isDef(styleFunction)) { styleFunction = ol.feature.defaultStyleFunction; } - var tolerance = frameStateResolution / (2 * pixelRatio); - var replayGroup = new ol.render.canvas.ReplayGroup(tolerance, extent, - frameStateResolution); + var tolerance = resolution / (2 * pixelRatio); + var replayGroup = + new ol.render.canvas.ReplayGroup(tolerance, extent, resolution); + vectorSource.loadFeatures(extent, resolution, projection); var renderFeature = /** * @param {ol.Feature} feature Feature. @@ -215,19 +218,28 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame = function(feature) { goog.asserts.assert(goog.isDef(styleFunction)); var dirty = this.renderFeature( - feature, frameStateResolution, pixelRatio, styleFunction, replayGroup); + feature, resolution, pixelRatio, styleFunction, replayGroup); this.dirty_ = this.dirty_ || dirty; }; if (!goog.isNull(vectorLayerRenderOrder)) { - var features = vectorSource.getFeaturesInExtent(extent); + /** @type {Array.} */ + var features = []; + vectorSource.forEachFeatureInExtentAtResolution(extent, resolution, + /** + * @param {ol.Feature} feature Feature. + */ + function(feature) { + features.push(feature); + }, this); goog.array.sort(features, vectorLayerRenderOrder); goog.array.forEach(features, renderFeature, this); } else { - vectorSource.forEachFeatureInExtent(extent, renderFeature, this); + vectorSource.forEachFeatureInExtentAtResolution( + extent, resolution, renderFeature, this); } replayGroup.finish(); - this.renderedResolution_ = frameStateResolution; + this.renderedResolution_ = resolution; this.renderedRevision_ = vectorLayerRevision; this.renderedRenderOrder_ = vectorLayerRenderOrder; this.replayGroup_ = replayGroup; diff --git a/src/ol/source/bingmapssource.js b/src/ol/source/bingmapssource.js index edc223891a..fa93ddb4d5 100644 --- a/src/ol/source/bingmapssource.js +++ b/src/ol/source/bingmapssource.js @@ -91,6 +91,7 @@ ol.source.BingMaps.prototype.handleImageryMetadataResponse = this.tileGrid = tileGrid; var culture = this.culture_; + var sourceProjection = this.getProjection(); this.tileUrlFunction = ol.TileUrlFunction.withTileCoordTransform( tileGrid.createTileCoordTransform(), ol.TileUrlFunction.createFromTileUrlFunctions( @@ -102,7 +103,6 @@ ol.source.BingMaps.prototype.handleImageryMetadataResponse = .replace('{culture}', culture); return ( /** - * @this {ol.source.BingMaps} * @param {ol.TileCoord} tileCoord Tile coordinate. * @param {number} pixelRatio Pixel ratio. * @param {ol.proj.Projection} projection Projection. @@ -110,7 +110,7 @@ ol.source.BingMaps.prototype.handleImageryMetadataResponse = */ function(tileCoord, pixelRatio, projection) { goog.asserts.assert(ol.proj.equivalent( - projection, this.getProjection())); + projection, sourceProjection)); if (goog.isNull(tileCoord)) { return undefined; } else { diff --git a/src/ol/source/formatvectorsource.js b/src/ol/source/formatvectorsource.js new file mode 100644 index 0000000000..3b3ad39fd6 --- /dev/null +++ b/src/ol/source/formatvectorsource.js @@ -0,0 +1,135 @@ +// FIXME consider delaying feature reading so projection can be provided by +// consumer (e.g. the view) + +goog.provide('ol.source.FormatVector'); + +goog.require('goog.asserts'); +goog.require('goog.dispose'); +goog.require('goog.events'); +goog.require('goog.net.EventType'); +goog.require('goog.net.XhrIo'); +goog.require('goog.net.XhrIo.ResponseType'); +goog.require('goog.userAgent'); +goog.require('ol.BrowserFeature'); +goog.require('ol.format.FormatType'); +goog.require('ol.proj'); +goog.require('ol.source.State'); +goog.require('ol.source.Vector'); +goog.require('ol.xml'); + + + +/** + * @constructor + * @extends {ol.source.Vector} + * @param {olx.source.FormatVectorOptions} options Options. + * @todo stability experimental + */ +ol.source.FormatVector = function(options) { + + goog.base(this, { + attributions: options.attributions, + extent: options.extent, + logo: options.logo, + projection: options.projection + }); + + /** + * @protected + * @type {ol.format.Feature} + */ + this.format = options.format; + +}; +goog.inherits(ol.source.FormatVector, ol.source.Vector); + + +/** + * @param {goog.Uri|string} url URL. + * @param {function(this: T, Array.)} callback Callback. + * @param {T} thisArg Value to use as `this` when executing `callback`. + * @template T + */ +ol.source.FormatVector.prototype.loadFeaturesFromURL = + function(url, callback, thisArg) { + var xhrIo = new goog.net.XhrIo(); + var type = this.format.getType(); + var responseType; + // FIXME maybe use ResponseType.DOCUMENT? + if (type == ol.format.FormatType.BINARY && + ol.BrowserFeature.HAS_ARRAY_BUFFER) { + responseType = goog.net.XhrIo.ResponseType.ARRAY_BUFFER; + } else { + responseType = goog.net.XhrIo.ResponseType.TEXT; + } + xhrIo.setResponseType(responseType); + goog.events.listen(xhrIo, goog.net.EventType.COMPLETE, + /** + * @param {Event} event Event. + * @private + * @this {ol.source.FormatVector} + */ + function(event) { + var xhrIo = event.target; + goog.asserts.assertInstanceof(xhrIo, goog.net.XhrIo); + if (xhrIo.isSuccess()) { + var type = this.format.getType(); + /** @type {ArrayBuffer|Document|Node|Object|string|undefined} */ + var source; + if (type == ol.format.FormatType.BINARY && + ol.BrowserFeature.HAS_ARRAY_BUFFER) { + source = xhrIo.getResponse(); + goog.asserts.assertInstanceof(source, ArrayBuffer); + } else if (type == ol.format.FormatType.JSON) { + source = xhrIo.getResponseText(); + } else if (type == ol.format.FormatType.TEXT) { + source = xhrIo.getResponseText(); + } else if (type == ol.format.FormatType.XML) { + if (!goog.userAgent.IE) { + source = xhrIo.getResponseXml(); + } + if (!goog.isDefAndNotNull(source)) { + source = ol.xml.load(xhrIo.getResponseText()); + } + } else { + goog.asserts.fail(); + } + if (goog.isDefAndNotNull(source)) { + callback.call(thisArg, this.readFeatures(source)); + } else { + this.setState(ol.source.State.ERROR); + goog.asserts.fail(); + } + } else { + this.setState(ol.source.State.ERROR); + } + goog.dispose(xhrIo); + }, false, this); + xhrIo.send(url); +}; + + +/** + * @param {ArrayBuffer|Document|Node|Object|string} source Source. + * @return {Array.} Features. + */ +ol.source.FormatVector.prototype.readFeatures = function(source) { + var format = this.format; + var features = format.readFeatures(source); + var featureProjection = format.readProjection(source); + var projection = this.getProjection(); + if (!goog.isNull(projection)) { + if (!ol.proj.equivalent(featureProjection, projection)) { + var transform = ol.proj.getTransform(featureProjection, projection); + var i, ii; + for (i = 0, ii = features.length; i < ii; ++i) { + var feature = features[i]; + var geometry = feature.getGeometry(); + if (!goog.isNull(geometry)) { + geometry.transform(transform); + } + } + } + } + return features; +}; diff --git a/src/ol/source/geojsonsource.js b/src/ol/source/geojsonsource.js index 1ee7532fd3..230a79b105 100644 --- a/src/ol/source/geojsonsource.js +++ b/src/ol/source/geojsonsource.js @@ -1,13 +1,13 @@ goog.provide('ol.source.GeoJSON'); goog.require('ol.format.GeoJSON'); -goog.require('ol.source.VectorFile'); +goog.require('ol.source.StaticVector'); /** * @constructor - * @extends {ol.source.VectorFile} + * @extends {ol.source.StaticVector} * @fires {@link ol.source.VectorEvent} ol.source.VectorEvent * @param {olx.source.GeoJSONOptions=} opt_options Options. * @todo stability experimental @@ -31,4 +31,4 @@ ol.source.GeoJSON = function(opt_options) { }); }; -goog.inherits(ol.source.GeoJSON, ol.source.VectorFile); +goog.inherits(ol.source.GeoJSON, ol.source.StaticVector); diff --git a/src/ol/source/gpxsource.js b/src/ol/source/gpxsource.js index 1db7f23603..447751e7dd 100644 --- a/src/ol/source/gpxsource.js +++ b/src/ol/source/gpxsource.js @@ -1,13 +1,13 @@ goog.provide('ol.source.GPX'); goog.require('ol.format.GPX'); -goog.require('ol.source.VectorFile'); +goog.require('ol.source.StaticVector'); /** * @constructor - * @extends {ol.source.VectorFile} + * @extends {ol.source.StaticVector} * @fires {@link ol.source.VectorEvent} ol.source.VectorEvent * @param {olx.source.GPXOptions=} opt_options Options. * @todo stability experimental @@ -30,4 +30,4 @@ ol.source.GPX = function(opt_options) { }); }; -goog.inherits(ol.source.GPX, ol.source.VectorFile); +goog.inherits(ol.source.GPX, ol.source.StaticVector); diff --git a/src/ol/source/igcsource.js b/src/ol/source/igcsource.js index c8f19cddfd..320dda80da 100644 --- a/src/ol/source/igcsource.js +++ b/src/ol/source/igcsource.js @@ -1,13 +1,13 @@ goog.provide('ol.source.IGC'); goog.require('ol.format.IGC'); -goog.require('ol.source.VectorFile'); +goog.require('ol.source.StaticVector'); /** * @constructor - * @extends {ol.source.VectorFile} + * @extends {ol.source.StaticVector} * @fires {@link ol.source.VectorEvent} ol.source.VectorEvent * @param {olx.source.IGCOptions=} opt_options Options. * @todo stability experimental @@ -27,4 +27,4 @@ ol.source.IGC = function(opt_options) { }); }; -goog.inherits(ol.source.IGC, ol.source.VectorFile); +goog.inherits(ol.source.IGC, ol.source.StaticVector); diff --git a/src/ol/source/imagevectorsource.js b/src/ol/source/imagevectorsource.js index f7bf16b53c..7f27f19ce6 100644 --- a/src/ol/source/imagevectorsource.js +++ b/src/ol/source/imagevectorsource.js @@ -106,7 +106,7 @@ ol.source.ImageVector.prototype.canvasFunctionInternal_ = resolution); var loading = false; - this.source_.forEachFeatureInExtent(extent, + this.source_.forEachFeatureInExtentAtResolution(extent, resolution, /** * @param {ol.Feature} feature Feature. */ diff --git a/src/ol/source/kmlsource.js b/src/ol/source/kmlsource.js index 00b3891a54..c94b70bf69 100644 --- a/src/ol/source/kmlsource.js +++ b/src/ol/source/kmlsource.js @@ -1,13 +1,13 @@ goog.provide('ol.source.KML'); goog.require('ol.format.KML'); -goog.require('ol.source.VectorFile'); +goog.require('ol.source.StaticVector'); /** * @constructor - * @extends {ol.source.VectorFile} + * @extends {ol.source.StaticVector} * @fires {@link ol.source.VectorEvent} ol.source.VectorEvent * @param {olx.source.KMLOptions=} opt_options Options. * @todo stability experimental @@ -32,4 +32,4 @@ ol.source.KML = function(opt_options) { }); }; -goog.inherits(ol.source.KML, ol.source.VectorFile); +goog.inherits(ol.source.KML, ol.source.StaticVector); diff --git a/src/ol/source/osmxmlsource.js b/src/ol/source/osmxmlsource.js index b93ca145b2..2baecbaa20 100644 --- a/src/ol/source/osmxmlsource.js +++ b/src/ol/source/osmxmlsource.js @@ -1,13 +1,13 @@ goog.provide('ol.source.OSMXML'); goog.require('ol.format.OSMXML'); -goog.require('ol.source.VectorFile'); +goog.require('ol.source.StaticVector'); /** * @constructor - * @extends {ol.source.VectorFile} + * @extends {ol.source.StaticVector} * @fires {@link ol.source.VectorEvent} ol.source.VectorEvent * @param {olx.source.OSMXMLOptions=} opt_options Options. */ @@ -29,4 +29,4 @@ ol.source.OSMXML = function(opt_options) { }); }; -goog.inherits(ol.source.OSMXML, ol.source.VectorFile); +goog.inherits(ol.source.OSMXML, ol.source.StaticVector); diff --git a/src/ol/source/servervectorsource.exports b/src/ol/source/servervectorsource.exports new file mode 100644 index 0000000000..8d0a5d6a63 --- /dev/null +++ b/src/ol/source/servervectorsource.exports @@ -0,0 +1,2 @@ +@exportSymbol ol.source.ServerVector +@exportProperty ol.source.ServerVector.prototype.readFeatures diff --git a/src/ol/source/servervectorsource.js b/src/ol/source/servervectorsource.js new file mode 100644 index 0000000000..f10085c2b8 --- /dev/null +++ b/src/ol/source/servervectorsource.js @@ -0,0 +1,99 @@ +// FIXME cache expiration + +goog.provide('ol.source.ServerVector'); + +goog.require('ol.extent'); +goog.require('ol.loadingstrategy'); +goog.require('ol.source.FormatVector'); +goog.require('ol.structs.RBush'); + + + +/** + * @constructor + * @extends {ol.source.FormatVector} + * @param {olx.source.ServerVectorOptions} options Options. + */ +ol.source.ServerVector = function(options) { + + goog.base(this, { + attributions: options.attributions, + extent: options.extent, + format: options.format, + logo: options.logo, + projection: options.projection + }); + + /** + * @private + * @type {ol.structs.RBush.<{extent: ol.Extent}>} + */ + this.loadedExtents_ = new ol.structs.RBush(); + + /** + * @private + * @type {function(this: ol.source.ServerVector, ol.Extent, number, + * ol.proj.Projection): string} + */ + this.loader_ = options.loader; + + /** + * @private + * @type {function(ol.Extent, number): Array.} + */ + this.strategy_ = goog.isDef(options.strategy) ? + options.strategy : ol.loadingstrategy.bbox; + + /** + * @private + * @type {Object.} + */ + this.loadedFeatures_ = {}; + +}; +goog.inherits(ol.source.ServerVector, ol.source.FormatVector); + + +/** + * @inheritDoc + */ +ol.source.ServerVector.prototype.addFeaturesInternal = function(features) { + /** @type {Array.} */ + var notLoadedFeatures = []; + var i, ii; + for (i = 0, ii = features.length; i < ii; ++i) { + var feature = features[i]; + var featureId = feature.getId(); + if (!(featureId in this.loadedFeatures_)) { + notLoadedFeatures.push(feature); + this.loadedFeatures_[featureId] = true; + } + } + goog.base(this, 'addFeaturesInternal', notLoadedFeatures); +}; + + +/** + * @inheritDoc + */ +ol.source.ServerVector.prototype.loadFeatures = + function(extent, resolution, projection) { + var loadedExtents = this.loadedExtents_; + var extentsToLoad = this.strategy_(extent, resolution); + var i, ii; + for (i = 0, ii = extentsToLoad.length; i < ii; ++i) { + var extentToLoad = extentsToLoad[i]; + var alreadyLoaded = loadedExtents.forEachInExtent(extentToLoad, + /** + * @param {{extent: ol.Extent}} object Object. + * @return {boolean} Contains. + */ + function(object) { + return ol.extent.containsExtent(object.extent, extentToLoad); + }); + if (!alreadyLoaded) { + this.loader_.call(this, extentToLoad, resolution, projection); + loadedExtents.insert(extentToLoad, {extent: extentToLoad.slice()}); + } + } +}; diff --git a/src/ol/source/staticvectorsource.exports b/src/ol/source/staticvectorsource.exports new file mode 100644 index 0000000000..1c283475e6 --- /dev/null +++ b/src/ol/source/staticvectorsource.exports @@ -0,0 +1 @@ +@exportSymbol ol.source.StaticVector diff --git a/src/ol/source/staticvectorsource.js b/src/ol/source/staticvectorsource.js new file mode 100644 index 0000000000..6ebc8ad278 --- /dev/null +++ b/src/ol/source/staticvectorsource.js @@ -0,0 +1,76 @@ +goog.provide('ol.source.StaticVector'); + +goog.require('ol.source.FormatVector'); +goog.require('ol.source.State'); + + + +/** + * @constructor + * @extends {ol.source.FormatVector} + * @fires {@link ol.source.VectorEvent} ol.source.VectorEvent + * @param {olx.source.StaticVectorOptions} options Options. + * @todo stability experimental + */ +ol.source.StaticVector = function(options) { + + goog.base(this, { + attributions: options.attributions, + extent: options.extent, + format: options.format, + logo: options.logo, + projection: options.projection + }); + + if (goog.isDef(options.arrayBuffer)) { + this.addFeaturesInternal(this.readFeatures(options.arrayBuffer)); + } + + if (goog.isDef(options.doc)) { + this.addFeaturesInternal(this.readFeatures(options.doc)); + } + + if (goog.isDef(options.node)) { + this.addFeaturesInternal(this.readFeatures(options.node)); + } + + if (goog.isDef(options.object)) { + this.addFeaturesInternal(this.readFeatures(options.object)); + } + + if (goog.isDef(options.text)) { + this.addFeaturesInternal(this.readFeatures(options.text)); + } + + if (goog.isDef(options.url) || goog.isDef(options.urls)) { + this.setState(ol.source.State.LOADING); + if (goog.isDef(options.url)) { + this.loadFeaturesFromURL(options.url, + /** + * @param {Array.} features Features. + * @this {ol.source.StaticVector} + */ + function(features) { + this.addFeaturesInternal(features); + this.setState(ol.source.State.READY); + }, this); + } + if (goog.isDef(options.urls)) { + var urls = options.urls; + var i, ii; + for (i = 0, ii = urls.length; i < ii; ++i) { + this.loadFeaturesFromURL(urls[i], + /** + * @param {Array.} features Features. + * @this {ol.source.StaticVector} + */ + function(features) { + this.addFeaturesInternal(features); + this.setState(ol.source.State.READY); + }, this); + } + } + } + +}; +goog.inherits(ol.source.StaticVector, ol.source.FormatVector); diff --git a/src/ol/source/tilevectorsource.exports b/src/ol/source/tilevectorsource.exports new file mode 100644 index 0000000000..aca6bdb3e8 --- /dev/null +++ b/src/ol/source/tilevectorsource.exports @@ -0,0 +1 @@ +@exportSymbol ol.source.TileVector diff --git a/src/ol/source/tilevectorsource.js b/src/ol/source/tilevectorsource.js new file mode 100644 index 0000000000..cf64f35430 --- /dev/null +++ b/src/ol/source/tilevectorsource.js @@ -0,0 +1,245 @@ +goog.provide('ol.source.TileVector'); + +goog.require('goog.array'); +goog.require('goog.object'); +goog.require('ol.TileCoord'); +goog.require('ol.TileUrlFunction'); +goog.require('ol.source.FormatVector'); +goog.require('ol.source.State'); +goog.require('ol.tilegrid.TileGrid'); + + + +/** + * @constructor + * @extends {ol.source.FormatVector} + * @param {olx.source.TileVectorOptions} options Options. + */ +ol.source.TileVector = function(options) { + + goog.base(this, { + attributions: options.attributions, + extent: options.extent, + format: options.format, + logo: options.logo, + projection: options.projection + }); + + var tileGrid = options.tileGrid; + + /** + * @private + * @type {ol.tilegrid.TileGrid} + */ + this.tileGrid_ = options.tileGrid; + + /** + * @private + * @type {ol.TileUrlFunctionType} + */ + this.tileUrlFunction_ = ol.TileUrlFunction.nullTileUrlFunction; + + /** + * @private + * @type {ol.TileCoordTransformType} + */ + this.tileCoordTransform_ = tileGrid.createTileCoordTransform({ + extent: options.extent + }); + + /** + * @private + * @type {Object.>} + */ + this.tiles_ = {}; + + if (goog.isDef(options.tileUrlFunction)) { + this.setTileUrlFunction(options.tileUrlFunction); + } else if (goog.isDef(options.urls)) { + this.setUrls(options.urls); + } else if (goog.isDef(options.url)) { + this.setUrl(options.url); + } + +}; +goog.inherits(ol.source.TileVector, ol.source.FormatVector); + + +/** + * @inheritDoc + */ +ol.source.TileVector.prototype.addFeature = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.source.TileVector.prototype.addFeatures = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.source.TileVector.prototype.clear = function() { + goog.object.clear(this.tiles_); +}; + + +/** + * @inheritDoc + */ +ol.source.TileVector.prototype.forEachFeature = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.source.TileVector.prototype.forEachFeatureInExtent = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.source.TileVector.prototype.forEachFeatureInExtentAtResolution = + function(extent, resolution, f, opt_this) { + var tileGrid = this.tileGrid_; + var tiles = this.tiles_; + var z = tileGrid.getZForResolution(resolution); + var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); + var x, y; + for (x = tileRange.minX; x <= tileRange.maxX; ++x) { + for (y = tileRange.minY; y <= tileRange.maxY; ++y) { + var tileKey = this.getTileKeyZXY_(z, x, y); + var features = tiles[tileKey]; + if (goog.isDef(features)) { + var i, ii; + for (i = 0, ii = features.length; i < ii; ++i) { + var result = f.call(opt_this, features[i]); + if (result) { + return result; + } + } + } + } + } + return undefined; +}; + + +/** + * @inheritDoc + */ +ol.source.TileVector.prototype.getClosestFeatureToCoordinate = + goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.source.TileVector.prototype.getExtent = goog.abstractMethod; + + +/** + * @inheritDoc + */ +ol.source.TileVector.prototype.getFeatures = function() { + var tiles = this.tiles_; + var features = []; + var tileKey; + for (tileKey in tiles) { + goog.array.extend(features, tiles[tileKey]); + } + return features; +}; + + +/** + * @inheritDoc + */ +ol.source.TileVector.prototype.getFeaturesInExtent = goog.abstractMethod; + + +/** + * @param {number} z Z. + * @param {number} x X. + * @param {number} y Y. + * @private + * @return {string} Tile key. + */ +ol.source.TileVector.prototype.getTileKeyZXY_ = function(z, x, y) { + return z + '/' + x + '/' + y; +}; + + +/** + * @inheritDoc + */ +ol.source.TileVector.prototype.loadFeatures = + function(extent, resolution, projection) { + var tileCoordTransform = this.tileCoordTransform_; + var tileGrid = this.tileGrid_; + var tileUrlFunction = this.tileUrlFunction_; + var tiles = this.tiles_; + var z = tileGrid.getZForResolution(resolution); + var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); + var tileCoord = new ol.TileCoord(z, 0, 0); + var x, y; + for (x = tileRange.minX; x <= tileRange.maxX; ++x) { + for (y = tileRange.minY; y <= tileRange.maxY; ++y) { + var tileKey = this.getTileKeyZXY_(z, x, y); + if (!(tileKey in tiles)) { + tileCoord.z = z; + tileCoord.x = x; + tileCoord.y = y; + tileCoordTransform(tileCoord, projection, tileCoord); + var url = tileUrlFunction(tileCoord, 1, projection); + if (goog.isDef(url)) { + tiles[tileKey] = []; + this.loadFeaturesFromURL(url, goog.partial( + /** + * @param {string} tileKey Tile key. + * @param {Array.} features Features. + * @this {ol.source.TileVector} + */ + function(tileKey, features) { + tiles[tileKey] = features; + this.setState(ol.source.State.READY); + }, tileKey), this); + } + } + } + } +}; + + +/** + * @inheritDoc + */ +ol.source.TileVector.prototype.removeFeature = goog.abstractMethod; + + +/** + * @param {ol.TileUrlFunctionType} tileUrlFunction Tile URL function. + */ +ol.source.TileVector.prototype.setTileUrlFunction = function(tileUrlFunction) { + this.tileUrlFunction_ = tileUrlFunction; + this.dispatchChangeEvent(); +}; + + +/** + * @param {string} url URL. + * @todo stability experimental + */ +ol.source.TileVector.prototype.setUrl = function(url) { + this.setTileUrlFunction(ol.TileUrlFunction.createFromTemplates( + ol.TileUrlFunction.expandUrl(url))); +}; + + +/** + * @param {Array.} urls URLs. + */ +ol.source.TileVector.prototype.setUrls = function(urls) { + this.setTileUrlFunction(ol.TileUrlFunction.createFromTemplates(urls)); +}; diff --git a/src/ol/source/topojsonsource.js b/src/ol/source/topojsonsource.js index 991c72afb8..cd65cf76ba 100644 --- a/src/ol/source/topojsonsource.js +++ b/src/ol/source/topojsonsource.js @@ -1,13 +1,13 @@ goog.provide('ol.source.TopoJSON'); goog.require('ol.format.TopoJSON'); -goog.require('ol.source.VectorFile'); +goog.require('ol.source.StaticVector'); /** * @constructor - * @extends {ol.source.VectorFile} + * @extends {ol.source.StaticVector} * @fires {@link ol.source.VectorEvent} ol.source.VectorEvent * @param {olx.source.TopoJSONOptions=} opt_options Options. * @todo stability experimental @@ -30,4 +30,4 @@ ol.source.TopoJSON = function(opt_options) { }); }; -goog.inherits(ol.source.TopoJSON, ol.source.VectorFile); +goog.inherits(ol.source.TopoJSON, ol.source.StaticVector); diff --git a/src/ol/source/vectorfilesource.exports b/src/ol/source/vectorfilesource.exports deleted file mode 100644 index acd6140571..0000000000 --- a/src/ol/source/vectorfilesource.exports +++ /dev/null @@ -1 +0,0 @@ -@exportSymbol ol.source.VectorFile diff --git a/src/ol/source/vectorfilesource.js b/src/ol/source/vectorfilesource.js deleted file mode 100644 index 885a69335a..0000000000 --- a/src/ol/source/vectorfilesource.js +++ /dev/null @@ -1,168 +0,0 @@ -// FIXME consider delaying feature reading so projection can be provided by -// consumer (e.g. the view) - -goog.provide('ol.source.VectorFile'); - -goog.require('goog.asserts'); -goog.require('goog.dispose'); -goog.require('goog.events'); -goog.require('goog.net.EventType'); -goog.require('goog.net.XhrIo'); -goog.require('goog.net.XhrIo.ResponseType'); -goog.require('goog.userAgent'); -goog.require('ol.BrowserFeature'); -goog.require('ol.format.FormatType'); -goog.require('ol.proj'); -goog.require('ol.source.State'); -goog.require('ol.source.Vector'); -goog.require('ol.xml'); - - - -/** - * @constructor - * @extends {ol.source.Vector} - * @fires {@link ol.source.VectorEvent} ol.source.VectorEvent - * @param {olx.source.VectorFileOptions=} opt_options Options. - * @todo stability experimental - */ -ol.source.VectorFile = function(opt_options) { - - var options = goog.isDef(opt_options) ? opt_options : {}; - - goog.base(this, { - attributions: options.attributions, - extent: options.extent, - logo: options.logo, - projection: options.projection - }); - - /** - * @type {ol.format.Feature} - * @protected - */ - this.format = options.format; - - if (goog.isDef(options.doc)) { - this.readFeatures_(options.doc); - } - - if (goog.isDef(options.node)) { - this.readFeatures_(options.node); - } - - if (goog.isDef(options.object)) { - this.readFeatures_(options.object); - } - - if (goog.isDef(options.text)) { - this.readFeatures_(options.text); - } - - if (goog.isDef(options.arrayBuffer)) { - this.readFeatures_(options.arrayBuffer); - } - - if (goog.isDef(options.url) || goog.isDef(options.urls)) { - this.setState(ol.source.State.LOADING); - - var type = this.format.getType(); - var responseType; - if (type == ol.format.FormatType.BINARY && - ol.BrowserFeature.HAS_ARRAY_BUFFER) { - responseType = goog.net.XhrIo.ResponseType.ARRAY_BUFFER; - } else { - responseType = goog.net.XhrIo.ResponseType.TEXT; - } - var xhrIo; - if (goog.isDef(options.url)) { - xhrIo = new goog.net.XhrIo(); - xhrIo.setResponseType(responseType); - goog.events.listen(xhrIo, goog.net.EventType.COMPLETE, - goog.bind(this.handleXhrIo_, this)); - xhrIo.send(options.url); - } - if (goog.isDef(options.urls)) { - var urls = options.urls; - var i, ii; - for (i = 0, ii = urls.length; i < ii; ++i) { - xhrIo = new goog.net.XhrIo(); - xhrIo.setResponseType(responseType); - goog.events.listen(xhrIo, goog.net.EventType.COMPLETE, - goog.bind(this.handleXhrIo_, this)); - xhrIo.send(urls[i]); - } - } - } - -}; -goog.inherits(ol.source.VectorFile, ol.source.Vector); - - -/** - * @param {Event} event Event. - * @private - */ -ol.source.VectorFile.prototype.handleXhrIo_ = function(event) { - var xhrIo = event.target; - goog.asserts.assertInstanceof(xhrIo, goog.net.XhrIo); - if (xhrIo.isSuccess()) { - var type = this.format.getType(); - /** @type {ArrayBuffer|Document|Node|Object|string|undefined} */ - var source; - if (type == ol.format.FormatType.BINARY && - ol.BrowserFeature.HAS_ARRAY_BUFFER) { - source = xhrIo.getResponse(); - goog.asserts.assertInstanceof(source, ArrayBuffer); - } else if (type == ol.format.FormatType.JSON) { - source = xhrIo.getResponseText(); - } else if (type == ol.format.FormatType.TEXT) { - source = xhrIo.getResponseText(); - } else if (type == ol.format.FormatType.XML) { - if (!goog.userAgent.IE) { - source = xhrIo.getResponseXml(); - } - if (!goog.isDefAndNotNull(source)) { - source = ol.xml.load(xhrIo.getResponseText()); - } - } else { - goog.asserts.fail(); - } - goog.dispose(xhrIo); - if (goog.isDefAndNotNull(source)) { - this.readFeatures_(source); - } else { - this.setState(ol.source.State.ERROR); - goog.asserts.fail(); - } - } else { - this.setState(ol.source.State.ERROR); - } -}; - - -/** - * @param {ArrayBuffer|Document|Node|Object|string} source Source. - * @private - */ -ol.source.VectorFile.prototype.readFeatures_ = function(source) { - var format = this.format; - var features = format.readFeatures(source); - var featureProjection = format.readProjection(source); - var projection = this.getProjection(); - if (!goog.isNull(projection)) { - if (!ol.proj.equivalent(featureProjection, projection)) { - var transform = ol.proj.getTransform(featureProjection, projection); - var i, ii; - for (i = 0, ii = features.length; i < ii; ++i) { - var feature = features[i]; - var geometry = feature.getGeometry(); - if (!goog.isNull(geometry)) { - geometry.transform(transform); - } - } - } - } - this.addFeaturesInternal(features); - this.setState(ol.source.State.READY); -}; diff --git a/src/ol/source/vectorsource.js b/src/ol/source/vectorsource.js index 6383b6dcd9..94ab64349a 100644 --- a/src/ol/source/vectorsource.js +++ b/src/ol/source/vectorsource.js @@ -13,6 +13,7 @@ goog.require('goog.events.Event'); goog.require('goog.events.EventType'); goog.require('goog.object'); goog.require('ol.ObjectEventType'); +goog.require('ol.proj'); goog.require('ol.source.Source'); goog.require('ol.structs.RBush'); @@ -207,6 +208,21 @@ ol.source.Vector.prototype.forEachFeatureInExtent = }; +/** + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @param {function(this: T, ol.Feature): S} f Callback. + * @param {T=} opt_this The object to use as `this` in `f`. + * @return {S|undefined} + * @template T,S + * @todo stability experimental + */ +ol.source.Vector.prototype.forEachFeatureInExtentAtResolution = + function(extent, resolution, f, opt_this) { + return this.forEachFeatureInExtent(extent, f, opt_this); +}; + + /** * @return {Array.} Features. * @todo stability experimental @@ -337,6 +353,14 @@ ol.source.Vector.prototype.isEmpty = function() { }; +/** + * @param {ol.Extent} extent Extent. + * @param {number} resolution Resolution. + * @param {ol.proj.Projection} projection Projection. + */ +ol.source.Vector.prototype.loadFeatures = goog.nullFunction; + + /** * @param {ol.Feature} feature Feature. * @todo stability experimental diff --git a/src/ol/tileurlfunction.js b/src/ol/tileurlfunction.js index 0626f0ec80..f99bfbcee2 100644 --- a/src/ol/tileurlfunction.js +++ b/src/ol/tileurlfunction.js @@ -10,11 +10,10 @@ goog.require('ol.TileCoord'); * A function that takes an {@link ol.TileCoord} for the tile coordinate, * a `{number}` representing the pixel ratio and an {@link ol.proj.Projection} * for the projection as arguments and returns a `{string}` or - * undefined representing the tile URL. The this keyword inside the function - * references the {@link ol.source.TileImage}. + * undefined representing the tile URL. * - * @typedef {function(this: ol.source.TileImage, ol.TileCoord, - * number, ol.proj.Projection): (string|undefined)} + * @typedef {function(ol.TileCoord, number, + * ol.proj.Projection): (string|undefined)} * @todo stability experimental */ ol.TileUrlFunctionType; @@ -34,7 +33,6 @@ ol.TileCoordTransformType; ol.TileUrlFunction.createFromTemplate = function(template) { return ( /** - * @this {ol.source.TileImage} * @param {ol.TileCoord} tileCoord Tile Coordinate. * @param {number} pixelRatio Pixel ratio. * @param {ol.proj.Projection} projection Projection. @@ -72,7 +70,6 @@ ol.TileUrlFunction.createFromTileUrlFunctions = function(tileUrlFunctions) { } return ( /** - * @this {ol.source.TileImage} * @param {ol.TileCoord} tileCoord Tile Coordinate. * @param {number} pixelRatio Pixel ratio. * @param {ol.proj.Projection} projection Projection. @@ -84,15 +81,13 @@ ol.TileUrlFunction.createFromTileUrlFunctions = function(tileUrlFunctions) { } else { var index = goog.math.modulo(tileCoord.hash(), tileUrlFunctions.length); - return tileUrlFunctions[index].call( - this, tileCoord, pixelRatio, projection); + return tileUrlFunctions[index](tileCoord, pixelRatio, projection); } }); }; /** - * @this {ol.source.TileImage} * @param {ol.TileCoord} tileCoord Tile coordinate. * @param {number} pixelRatio Pixel ratio. * @param {ol.proj.Projection} projection Projection. @@ -114,7 +109,6 @@ ol.TileUrlFunction.withTileCoordTransform = var tmpTileCoord = new ol.TileCoord(0, 0, 0); return ( /** - * @this {ol.source.TileImage} * @param {ol.TileCoord} tileCoord Tile Coordinate. * @param {number} pixelRatio Pixel ratio. * @param {ol.proj.Projection} projection Projection. @@ -124,9 +118,8 @@ ol.TileUrlFunction.withTileCoordTransform = if (goog.isNull(tileCoord)) { return undefined; } else { - return tileUrlFunction.call( - this, - transformFn.call(this, tileCoord, projection, tmpTileCoord), + return tileUrlFunction( + transformFn(tileCoord, projection, tmpTileCoord), pixelRatio, projection); }