diff --git a/examples/gml.js b/examples/gml.js index b61d50a199..373028937d 100644 --- a/examples/gml.js +++ b/examples/gml.js @@ -4,7 +4,6 @@ goog.require('ol.View2D'); goog.require('ol.layer.TileLayer'); goog.require('ol.layer.Vector'); goog.require('ol.parser.ogc.GML_v3'); -goog.require('ol.proj'); goog.require('ol.source.MapQuestOpenAerial'); goog.require('ol.source.Vector'); goog.require('ol.style.Polygon'); @@ -17,7 +16,8 @@ var raster = new ol.layer.TileLayer({ var vector = new ol.layer.Vector({ source: new ol.source.Vector({ - projection: ol.proj.get('EPSG:4326') + parser: new ol.parser.ogc.GML_v3({axisOrientation: 'neu'}), + url: 'data/gml/topp-states-wfs.xml' }), style: new ol.style.Style({rules: [ new ol.style.Rule({ @@ -39,22 +39,3 @@ var map = new ol.Map({ zoom: 4 }) }); - -var gml = new ol.parser.ogc.GML_v3({axisOrientation: 'neu'}); - -var url = 'data/gml/topp-states-wfs.xml'; -var xhr = new XMLHttpRequest(); -xhr.open('GET', url, true); - - -/** - * onload handler for the XHR request. - */ -xhr.onload = function() { - if (xhr.status == 200) { - // this is silly to have to tell the layer the destination projection - var projection = map.getView().getProjection(); - vector.parseFeatures(xhr.responseText, gml, projection); - } -}; -xhr.send(); diff --git a/examples/gpx.js b/examples/gpx.js index d709cdfcc0..44e307effb 100644 --- a/examples/gpx.js +++ b/examples/gpx.js @@ -4,7 +4,6 @@ goog.require('ol.View2D'); goog.require('ol.layer.TileLayer'); goog.require('ol.layer.Vector'); goog.require('ol.parser.GPX'); -goog.require('ol.proj'); goog.require('ol.source.OSM'); goog.require('ol.source.Vector'); @@ -14,7 +13,8 @@ var raster = new ol.layer.TileLayer({ var vector = new ol.layer.Vector({ source: new ol.source.Vector({ - projection: ol.proj.get('EPSG:4326') + parser: new ol.parser.GPX(), + url: 'data/gpx/yahoo.xml' }), transformFeatureInfo: function(features) { var info = []; @@ -44,22 +44,3 @@ map.on(['click', 'mousemove'], function(evt) { } }); }); - -var gpx = new ol.parser.GPX(); - -var url = 'data/gpx/yahoo.xml'; -var xhr = new XMLHttpRequest(); -xhr.open('GET', url, true); - - -/** - * onload handler for the XHR request. - */ -xhr.onload = function() { - if (xhr.status == 200) { - // this is silly to have to tell the layer the destination projection - var projection = map.getView().getProjection(); - vector.parseFeatures(xhr.responseText, gpx, projection); - } -}; -xhr.send(); diff --git a/examples/kml-timezones.js b/examples/kml-timezones.js index 7c5db6b48c..ff4209d03a 100644 --- a/examples/kml-timezones.js +++ b/examples/kml-timezones.js @@ -5,7 +5,6 @@ goog.require('ol.expr'); goog.require('ol.layer.TileLayer'); goog.require('ol.layer.Vector'); goog.require('ol.parser.KML'); -goog.require('ol.proj'); goog.require('ol.source.Stamen'); goog.require('ol.source.Vector'); goog.require('ol.style.Polygon'); @@ -55,7 +54,8 @@ var style = new ol.style.Style({rules: [ var vector = new ol.layer.Vector({ source: new ol.source.Vector({ - projection: ol.proj.get('EPSG:4326') + parser: new ol.parser.KML({dimension: 2}), + url: 'data/kml/timezones.kml' }), style: style }); @@ -103,21 +103,3 @@ map.on(['click', 'mousemove'], function(evt) { } }); }); - -var kml = new ol.parser.KML({dimension: 2}); - -var url = 'data/kml/timezones.kml'; -var xhr = new XMLHttpRequest(); -xhr.open('GET', url, true); - - -/** - * onload handler for the XHR request. - */ -xhr.onload = function() { - if (xhr.status == 200) { - var projection = map.getView().getProjection(); - vector.parseFeatures(xhr.responseText, kml, projection); - } -}; -xhr.send(); diff --git a/examples/kml.js b/examples/kml.js index 885ab94ff0..772eb74928 100644 --- a/examples/kml.js +++ b/examples/kml.js @@ -4,7 +4,6 @@ goog.require('ol.View2D'); goog.require('ol.layer.TileLayer'); goog.require('ol.layer.Vector'); goog.require('ol.parser.KML'); -goog.require('ol.proj'); goog.require('ol.source.TiledWMS'); goog.require('ol.source.Vector'); @@ -20,11 +19,12 @@ var raster = new ol.layer.TileLayer({ }) }); -var epsg4326 = ol.proj.get('EPSG:4326'); - var vector = new ol.layer.Vector({ source: new ol.source.Vector({ - projection: epsg4326 + parser: new ol.parser.KML({ + maxDepth: 1, dimension: 2, extractStyles: true, extractAttributes: true + }), + url: 'data/kml/lines.kml' }), transformFeatureInfo: function(features) { var info = []; @@ -40,15 +40,12 @@ var map = new ol.Map({ renderer: ol.RendererHint.CANVAS, target: 'map', view: new ol.View2D({ - projection: epsg4326, + projection: 'EPSG:4326', center: [-112.169, 36.099], zoom: 11 }) }); -var kml = new ol.parser.KML({ - maxDepth: 1, dimension: 2, extractStyles: true, extractAttributes: true}); - map.on(['click', 'mousemove'], function(evt) { map.getFeatureInfo({ pixel: evt.getPixel(), @@ -58,19 +55,3 @@ map.on(['click', 'mousemove'], function(evt) { } }); }); - -var url = 'data/kml/lines.kml'; -var xhr = new XMLHttpRequest(); -xhr.open('GET', url, true); - - -/** - * onload handler for the XHR request. - */ -xhr.onload = function() { - if (xhr.status == 200) { - // this is silly to have to tell the layer the destination projection - vector.parseFeatures(xhr.responseText, kml, epsg4326); - } -}; -xhr.send(); diff --git a/examples/style-rules.js b/examples/style-rules.js index eafea47bd7..6e98f675ec 100644 --- a/examples/style-rules.js +++ b/examples/style-rules.js @@ -60,112 +60,111 @@ var style = new ol.style.Style({rules: [ var vector = new ol.layer.Vector({ style: style, source: new ol.source.Vector({ + data: { + 'type': 'FeatureCollection', + 'features': [{ + 'type': 'Feature', + 'properties': { + 'color': '#BADA55', + 'where': 'inner' + }, + 'geometry': { + 'type': 'LineString', + 'coordinates': [[-10000000, -10000000], [10000000, 10000000]] + } + }, { + 'type': 'Feature', + 'properties': { + 'color': '#BADA55', + 'where': 'inner' + }, + 'geometry': { + 'type': 'LineString', + 'coordinates': [[-10000000, 10000000], [10000000, -10000000]] + } + }, { + 'type': 'Feature', + 'properties': { + 'color': '#013', + 'where': 'outer' + }, + 'geometry': { + 'type': 'LineString', + 'coordinates': [[-10000000, -10000000], [-10000000, 10000000]] + } + }, { + 'type': 'Feature', + 'properties': { + 'color': '#013', + 'where': 'outer' + }, + 'geometry': { + 'type': 'LineString', + 'coordinates': [[-10000000, 10000000], [10000000, 10000000]] + } + }, { + 'type': 'Feature', + 'properties': { + 'color': '#013', + 'where': 'outer' + }, + 'geometry': { + 'type': 'LineString', + 'coordinates': [[10000000, 10000000], [10000000, -10000000]] + } + }, { + 'type': 'Feature', + 'properties': { + 'color': '#013', + 'where': 'outer' + }, + 'geometry': { + 'type': 'LineString', + 'coordinates': [[10000000, -10000000], [-10000000, -10000000]] + } + }, { + 'type': 'Feature', + 'properties': { + 'label': 'South' + }, + 'geometry': { + 'type': 'Point', + 'coordinates': [0, -6000000] + } + }, { + 'type': 'Feature', + 'properties': { + 'label': 'West' + }, + 'geometry': { + 'type': 'Point', + 'coordinates': [-6000000, 0] + } + }, { + 'type': 'Feature', + 'properties': { + 'label': 'North' + }, + 'geometry': { + 'type': 'Point', + 'coordinates': [0, 6000000] + } + }, { + 'type': 'Feature', + 'properties': { + 'label': 'East' + }, + 'geometry': { + 'type': 'Point', + 'coordinates': [6000000, 0] + } + }] + }, + parser: new ol.parser.GeoJSON(), projection: ol.proj.get('EPSG:3857') }) }); -vector.parseFeatures({ - 'type': 'FeatureCollection', - 'features': [{ - 'type': 'Feature', - 'properties': { - 'color': '#BADA55', - 'where': 'inner' - }, - 'geometry': { - 'type': 'LineString', - 'coordinates': [[-10000000, -10000000], [10000000, 10000000]] - } - }, { - 'type': 'Feature', - 'properties': { - 'color': '#BADA55', - 'where': 'inner' - }, - 'geometry': { - 'type': 'LineString', - 'coordinates': [[-10000000, 10000000], [10000000, -10000000]] - } - }, { - 'type': 'Feature', - 'properties': { - 'color': '#013', - 'where': 'outer' - }, - 'geometry': { - 'type': 'LineString', - 'coordinates': [[-10000000, -10000000], [-10000000, 10000000]] - } - }, { - 'type': 'Feature', - 'properties': { - 'color': '#013', - 'where': 'outer' - }, - 'geometry': { - 'type': 'LineString', - 'coordinates': [[-10000000, 10000000], [10000000, 10000000]] - } - }, { - 'type': 'Feature', - 'properties': { - 'color': '#013', - 'where': 'outer' - }, - 'geometry': { - 'type': 'LineString', - 'coordinates': [[10000000, 10000000], [10000000, -10000000]] - } - }, { - 'type': 'Feature', - 'properties': { - 'color': '#013', - 'where': 'outer' - }, - 'geometry': { - 'type': 'LineString', - 'coordinates': [[10000000, -10000000], [-10000000, -10000000]] - } - }, { - 'type': 'Feature', - 'properties': { - 'label': 'South' - }, - 'geometry': { - 'type': 'Point', - 'coordinates': [0, -6000000] - } - }, { - 'type': 'Feature', - 'properties': { - 'label': 'West' - }, - 'geometry': { - 'type': 'Point', - 'coordinates': [-6000000, 0] - } - }, { - 'type': 'Feature', - 'properties': { - 'label': 'North' - }, - 'geometry': { - 'type': 'Point', - 'coordinates': [0, 6000000] - } - }, { - 'type': 'Feature', - 'properties': { - 'label': 'East' - }, - 'geometry': { - 'type': 'Point', - 'coordinates': [6000000, 0] - } - }] -}, new ol.parser.GeoJSON(), ol.proj.get('EPSG:3857')); - - var map = new ol.Map({ layers: [vector], controls: ol.control.defaults({ diff --git a/examples/vector-layer.js b/examples/vector-layer.js index 05774f56f5..23b8f9e4ee 100644 --- a/examples/vector-layer.js +++ b/examples/vector-layer.js @@ -5,7 +5,6 @@ goog.require('ol.expr'); goog.require('ol.layer.TileLayer'); goog.require('ol.layer.Vector'); goog.require('ol.parser.GeoJSON'); -goog.require('ol.proj'); goog.require('ol.source.MapQuestOpenAerial'); goog.require('ol.source.Vector'); goog.require('ol.style.Polygon'); @@ -25,7 +24,8 @@ ol.expr.register('resolution', function() { var vector = new ol.layer.Vector({ source: new ol.source.Vector({ - projection: ol.proj.get('EPSG:4326') + parser: new ol.parser.GeoJSON(), + url: 'data/countries.geojson' }), style: new ol.style.Style({rules: [ new ol.style.Rule({ @@ -72,22 +72,3 @@ map.on(['click', 'mousemove'], function(evt) { } }); }); - - -var geojson = new ol.parser.GeoJSON(); -var url = 'data/countries.geojson'; -var xhr = new XMLHttpRequest(); -xhr.open('GET', url, true); - - -/** - * onload handler for the XHR request. - */ -xhr.onload = function() { - if (xhr.status == 200) { - // this is silly to have to tell the layer the destination projection - var projection = map.getView().getProjection(); - vector.parseFeatures(xhr.responseText, geojson, projection); - } -}; -xhr.send(); diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 215f8d1328..fdbf4f59e7 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -499,6 +499,20 @@ * of `url` when the WMS supports multiple urls for GetMap requests. */ +/** + * @typedef {Object} ol.source.VectorOptions + * @property {Array.|undefined} attributions Attributions. + * @property {Object|string|undefined} data Data to parse. + * @property {ol.Extent|undefined} extent Extent. + * @property {string|undefined} logo Logo. + * @property {ol.parser.Parser} parser Parser instance to parse data + * provided as `data` or fetched from `url`. + * @property {ol.ProjectionLike|undefined} projection Projection. EPSG:4326 + * is assumed if not defined. TODO: Get projection from the parser instead + * of assuming EPSG:4326. + * @property {string|undefined} url Server url providing the vector data. + */ + /** * @typedef {Object} ol.source.VectorSource2Options * @property {Array.|undefined} attributions Attributions. diff --git a/src/ol/layer/vectorlayer.exports b/src/ol/layer/vectorlayer.exports index 669da99ad1..fa79c6b730 100644 --- a/src/ol/layer/vectorlayer.exports +++ b/src/ol/layer/vectorlayer.exports @@ -1,4 +1,3 @@ @exportClass ol.layer.Vector ol.layer.VectorLayerOptions @exportProperty ol.layer.Vector.prototype.addFeatures -@exportProperty ol.layer.Vector.prototype.parseFeatures diff --git a/src/ol/layer/vectorlayer.js b/src/ol/layer/vectorlayer.js index 264c4c9fa4..fdef16b75a 100644 --- a/src/ol/layer/vectorlayer.js +++ b/src/ol/layer/vectorlayer.js @@ -279,34 +279,26 @@ ol.layer.Vector.prototype.getVectorSource = function() { /** - * @param {ol.expr.Expression=} opt_expr Expression for filtering. - * @return {Array.} Array of features. - */ -ol.layer.Vector.prototype.getFeatures = function(opt_expr) { - return goog.object.getValues( - this.featureCache_.getFeaturesObject(opt_expr)); -}; - - -/** - * @param {ol.expr.Expression=} opt_expr Expression for filtering. - * @return {Object.} Features. - */ -ol.layer.Vector.prototype.getFeaturesObject = function(opt_expr) { - return this.featureCache_.getFeaturesObject(opt_expr); -}; - - -/** - * Get all features whose bounding box intersects the provided extent. + * Get all features whose bounding box intersects the provided extent. This + * method is intended for being called by the renderer. When null is returned, + * the renderer should not waste time rendering, and `opt_callback` is + * usually a function that requests a renderFrame, which will be called as soon + * as the data for `extent` is available. * * @param {ol.Extent} extent Bounding extent. + * @param {ol.Projection} projection Target projection. * @param {ol.geom.GeometryType=} opt_type Optional geometry type. - * @return {Object.} Features. + * @param {Function=} opt_callback Callback to call when data is parsed. + * @return {Object.} Features or null if source is loading + * data for `extent`. */ ol.layer.Vector.prototype.getFeaturesObjectForExtent = function(extent, - opt_type) { - return this.featureCache_.getFeaturesObjectForExtent(extent, opt_type); + projection, opt_type, opt_callback) { + var source = this.getSource(); + return source.prepareFeatures(this, extent, projection, opt_callback) == + ol.source.VectorLoadState.LOADING ? + null : + this.featureCache_.getFeaturesObjectForExtent(extent, opt_type); }; diff --git a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js index 343d783f72..bc378f465c 100644 --- a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js +++ b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js @@ -228,9 +228,11 @@ ol.renderer.canvas.VectorLayer.prototype.getFeatureInfoForPixel = * @param {function(Array., ol.layer.Layer)} success Callback for * successful queries. The passed arguments are the resulting features * and the layer. + * @param {function()=} opt_error Callback for unsuccessful queries. */ ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel = - function(pixel, success) { + function(pixel, success, opt_error) { + // TODO What do we want to pass to the error callback? var map = this.getMap(); var result = []; @@ -247,7 +249,15 @@ ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel = var locationMin = [location[0] - halfMaxWidth, location[1] - halfMaxHeight]; var locationMax = [location[0] + halfMaxWidth, location[1] + halfMaxHeight]; var locationBbox = ol.extent.boundingExtent([locationMin, locationMax]); - var candidates = layer.getFeaturesObjectForExtent(locationBbox); + var candidates = layer.getFeaturesObjectForExtent(locationBbox, + map.getView().getView2D().getProjection()); + if (goog.isNull(candidates)) { + // data is not loaded + if (goog.isDef(opt_error)) { + goog.global.setTimeout(function() { opt_error(); }, 0); + } + return; + } var candidate, geom, type, symbolBounds, symbolSize, halfWidth, halfHeight, coordinates, j; @@ -446,6 +456,7 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame = dirty = false, i, type, tileExtent, groups, group, j, numGroups, featuresObject, tileHasFeatures; + fetchTileData: for (x = tileRange.minX; x <= tileRange.maxX; ++x) { for (y = tileRange.minY; y <= tileRange.maxY; ++y) { tileCoord = new ol.TileCoord(0, x, y); @@ -464,7 +475,12 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame = if (!goog.isDef(featuresToRender[type])) { featuresToRender[type] = {}; } - featuresObject = layer.getFeaturesObjectForExtent(tileExtent, type); + featuresObject = layer.getFeaturesObjectForExtent(tileExtent, + projection, type, this.requestMapRenderFrame_); + if (goog.isNull(featuresObject)) { + deferred = true; + break fetchTileData; + } tileHasFeatures = tileHasFeatures || !goog.object.isEmpty(featuresObject); goog.object.extend(featuresToRender[type], featuresObject); diff --git a/src/ol/source/vectorsource.exports b/src/ol/source/vectorsource.exports index 27cbc2bea0..d7842f5b84 100644 --- a/src/ol/source/vectorsource.exports +++ b/src/ol/source/vectorsource.exports @@ -1 +1 @@ -@exportClass ol.source.Vector ol.source.SourceOptions +@exportClass ol.source.Vector ol.source.VectorOptions diff --git a/src/ol/source/vectorsource.js b/src/ol/source/vectorsource.js index 80a85b5d55..6dee9600cf 100644 --- a/src/ol/source/vectorsource.js +++ b/src/ol/source/vectorsource.js @@ -1,15 +1,97 @@ goog.provide('ol.source.Vector'); +goog.require('goog.asserts'); +goog.require('goog.net.XhrIo'); +goog.require('ol.proj'); goog.require('ol.source.Source'); +/** + * @enum {number} + */ +ol.source.VectorLoadState = { + IDLE: 0, + LOADING: 1, + LOADED: 2, + ERROR: 3 +}; + + /** * @constructor * @extends {ol.source.Source} - * @param {ol.source.SourceOptions} options Source options. + * @param {ol.source.VectorOptions} options Vector source options. */ ol.source.Vector = function(options) { - goog.base(this, options); + + /** + * @private + * @type {Object|string} + */ + this.data_ = goog.isDef(options.data) ? options.data : null; + + /** + * @private + * @type {ol.source.VectorLoadState} + */ + this.loadState_ = ol.source.VectorLoadState.IDLE; + + /** + * @private + * @type {ol.parser.Parser} + */ + this.parser_ = goog.isDef(options.parser) ? options.parser : null; + + /** + * @private + * @type {string|undefined} + */ + this.url_ = options.url; + + goog.base(this, { + attributions: options.attributions, + extent: options.extent, + logo: options.logo, + projection: goog.isDef(options.projection) ? + options.projection : ol.proj.get('EPSG:4326') + }); }; goog.inherits(ol.source.Vector, ol.source.Source); + + +/** + * @param {ol.layer.Vector} layer Layer that parses the data. + * @param {ol.Extent} extent Extent that needs to be fetched. + * @param {ol.Projection} projection Projection of the view. + * @param {function()=} opt_callback Callback which is called when features are + * parsed after loading. + * @return {ol.source.VectorLoadState} The current load state. + */ +ol.source.Vector.prototype.prepareFeatures = function(layer, extent, projection, + opt_callback) { + // TODO: Implement strategies. BBOX aware strategies will need the extent. + if (goog.isDef(this.url_) && + this.loadState_ == ol.source.VectorLoadState.IDLE) { + this.loadState_ = ol.source.VectorLoadState.LOADING; + goog.net.XhrIo.send(this.url_, goog.bind(function(event) { + var xhr = event.target; + if (xhr.isSuccess()) { + // TODO: Get source projection from data if supported by parser. + layer.parseFeatures(xhr.getResponseText(), this.parser_, projection); + this.loadState_ = ol.source.VectorLoadState.LOADED; + if (goog.isDef(opt_callback)) { + opt_callback(); + } + } else { + // TODO: Error handling. + this.loadState_ = ol.source.VectorLoadState.ERROR; + } + }, this)); + } else if (!goog.isNull(this.data_)) { + layer.parseFeatures(this.data_, this.parser_, projection); + this.data_ = null; + this.loadState_ = ol.source.VectorLoadState.LOADED; + } + return this.loadState_; +}; diff --git a/test/spec/ol/layer/vectorlayer.test.js b/test/spec/ol/layer/vectorlayer.test.js index 1525617d6a..8c6c9f06e1 100644 --- a/test/spec/ol/layer/vectorlayer.test.js +++ b/test/spec/ol/layer/vectorlayer.test.js @@ -9,11 +9,12 @@ describe('ol.layer.Vector', function() { source: new ol.source.Vector({}) }); layer.addFeatures([new ol.Feature(), new ol.Feature()]); - expect(layer.getFeatures().length).to.eql(2); + expect(goog.object.getCount(layer.featureCache_.getFeaturesObject())) + .to.eql(2); }); }); - describe('#getFeatures()', function() { + describe('ol.layer.FeatureCache#getFeaturesObject()', function() { var layer, features; @@ -55,18 +56,18 @@ describe('ol.layer.Vector', function() { it('can filter by geometry type using its GeometryType index', function() { sinon.spy(geomFilter, 'evaluate'); - var lineStrings = layer.getFeatures(geomFilter); + var lineStrings = layer.featureCache_.getFeaturesObject(geomFilter); expect(geomFilter.evaluate).to.not.be.called(); - expect(lineStrings.length).to.eql(4); - expect(lineStrings).to.contain(features[4]); + expect(goog.object.getCount(lineStrings)).to.eql(4); + expect(goog.object.getValues(lineStrings)).to.contain(features[4]); }); it('can filter by extent using its RTree', function() { sinon.spy(extentFilter, 'evaluate'); - var subset = layer.getFeatures(extentFilter); + var subset = layer.featureCache_.getFeaturesObject(extentFilter); expect(extentFilter.evaluate).to.not.be.called(); - expect(subset.length).to.eql(4); - expect(subset).not.to.contain(features[7]); + expect(goog.object.getCount(subset)).to.eql(4); + expect(goog.object.getValues(subset)).not.to.contain(features[7]); }); it('can filter by extent and geometry type using its index', function() { @@ -76,21 +77,21 @@ describe('ol.layer.Vector', function() { ol.expr.LogicalOp.AND, extentFilter, geomFilter); sinon.spy(filter1, 'evaluate'); sinon.spy(filter2, 'evaluate'); - var subset1 = layer.getFeatures(filter1); - var subset2 = layer.getFeatures(filter2); + var subset1 = layer.featureCache_.getFeaturesObject(filter1); + var subset2 = layer.featureCache_.getFeaturesObject(filter2); expect(filter1.evaluate).to.not.be.called(); expect(filter2.evaluate).to.not.be.called(); - expect(subset1.length).to.eql(0); - expect(subset2.length).to.eql(0); + expect(goog.object.getCount(subset1)).to.eql(0); + expect(goog.object.getCount(subset2)).to.eql(0); }); it('can handle query using the filter\'s evaluate function', function() { var filter = new ol.expr.Logical( ol.expr.LogicalOp.OR, geomFilter, extentFilter); sinon.spy(filter, 'evaluate'); - var subset = layer.getFeatures(filter); + var subset = layer.featureCache_.getFeaturesObject(filter); expect(filter.evaluate).to.be.called(); - expect(subset.length).to.eql(8); + expect(goog.object.getCount(subset)).to.eql(8); }); }); @@ -177,6 +178,7 @@ describe('ol.layer.Vector', function() { }); goog.require('goog.dispose'); +goog.require('goog.object'); goog.require('ol.Feature'); goog.require('ol.expr'); goog.require('ol.expr.Logical'); diff --git a/test/spec/ol/source/vectorsource.test.js b/test/spec/ol/source/vectorsource.test.js index bef91ced07..ee40475a22 100644 --- a/test/spec/ol/source/vectorsource.test.js +++ b/test/spec/ol/source/vectorsource.test.js @@ -11,7 +11,77 @@ describe('ol.source.Vector', function() { }); }); + describe('#prepareFeatures', function() { + it('loads and parses data from a file', function(done) { + var source = new ol.source.Vector({ + url: 'spec/ol/parser/geojson/countries.geojson', + parser: new ol.parser.GeoJSON() + }); + var layer = new ol.layer.Vector({ + source: source + }); + source.prepareFeatures(layer, [-180, 180, -90, 90], + ol.proj.get('EPSG:4326'), + function() { + expect(source.loadState_).to.be(ol.source.VectorLoadState.LOADED); + expect(goog.object.getCount( + layer.featureCache_.getFeaturesObject())).to.be(179); + done(); + }); + }); + + it('parses inline data', function() { + var source = new ol.source.Vector({ + data: { + 'type': 'FeatureCollection', + 'features': [{ + 'type': 'Feature', + 'geometry': { + 'type': 'Point', + 'coordinates': [0, -6000000] + } + }, { + 'type': 'Feature', + 'geometry': { + 'type': 'Point', + 'coordinates': [-6000000, 0] + } + }, { + 'type': 'Feature', + 'geometry': { + 'type': 'Point', + 'coordinates': [0, 6000000] + } + }, { + 'type': 'Feature', + 'geometry': { + 'type': 'Point', + 'coordinates': [6000000, 0] + } + }] + }, + parser: new ol.parser.GeoJSON(), + projection: ol.proj.get('EPSG:4326') + }); + var layer = new ol.layer.Vector({ + source: source + }); + source.prepareFeatures(layer, [-180, 180, -90, 90], + ol.proj.get('EPSG:4326'), + function() { + expect(source.loadState_).to.be(ol.source.VectorLoadState.LOADED); + expect(goog.object.getCount( + layer.featureCache_.getFeaturesObject())).to.be(4); + done(); + }); + }); + }); + }); +goog.require('goog.object'); +goog.require('ol.layer.Vector'); +goog.require('ol.parser.GeoJSON'); +goog.require('ol.proj'); goog.require('ol.source.Source'); goog.require('ol.source.Vector');