diff --git a/src/ol/parser/geojson.js b/src/ol/parser/geojson.js index ac6859e8d1..b67332b9f4 100644 --- a/src/ol/parser/geojson.js +++ b/src/ol/parser/geojson.js @@ -63,7 +63,7 @@ ol.parser.GeoJSON.read = function(str) { ol.parser.GeoJSON.prototype.readFeaturesFromString = function(str, opt_options) { var json = /** @type {GeoJSONFeatureCollection} */ (JSON.parse(str)); - return {features: this.parseFeatureCollection_(json, opt_options), + return {features: this.parseAsFeatureCollection_(json, opt_options), metadata: {projection: 'EPSG:4326'}}; }; @@ -77,64 +77,82 @@ ol.parser.GeoJSON.prototype.readFeaturesFromString = */ ol.parser.GeoJSON.prototype.readFeaturesFromObject = function(object, opt_options) { - return {features: this.parseFeatureCollection_(object, opt_options), + return {features: this.parseAsFeatureCollection_(object, opt_options), metadata: {projection: 'EPSG:4326'}}; }; /** + * Parse any GeoJSON object. Note that this method should not be called + * recursively due to the shared vertex creation. + * * @param {GeoJSONObject} json GeoJSON object. + * @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options. * @return {ol.Feature|Array.| * ol.geom.Geometry|Array.} Parsed geometry or array * of geometries. * @private */ -ol.parser.GeoJSON.prototype.parse_ = function(json) { +ol.parser.GeoJSON.prototype.parse_ = function(json, opt_options) { var result; - switch (json.type) { - case 'FeatureCollection': - result = this.parseFeatureCollection_( - /** @type {GeoJSONFeatureCollection} */ (json)); - break; - case 'Feature': - result = this.parseFeature_( - /** @type {GeoJSONFeature} */ (json)); - break; - case 'GeometryCollection': - result = this.parseGeometryCollection_( - /** @type {GeoJSONGeometryCollection} */ (json)); - break; - case 'Point': - result = this.parsePoint_( - /** @type {GeoJSONGeometry} */ (json)); - break; - case 'LineString': - result = this.parseLineString_( - /** @type {GeoJSONGeometry} */ (json)); - break; - case 'Polygon': - result = this.parsePolygon_( - /** @type {GeoJSONGeometry} */ (json)); - break; - case 'MultiPoint': - result = this.parseMultiPoint_( - /** @type {GeoJSONGeometry} */ (json)); - break; - case 'MultiLineString': - result = this.parseMultiLineString_( - /** @type {GeoJSONGeometry} */ (json)); - break; - case 'MultiPolygon': - result = this.parseMultiPolygon_( - /** @type {GeoJSONGeometry} */ (json)); - break; - default: - throw new Error('GeoJSON parsing not implemented for type: ' + json.type); + if (json.type === 'FeatureCollection') { + result = this.parseFeatureCollection_( + /** @type {GeoJSONFeatureCollection} */ (json), opt_options); + } else if (json.type === 'Feature') { + result = this.parseFeature_( + /** @type {GeoJSONFeature} */ (json), opt_options); + } else if (json.type === 'GeometryCollection') { + result = this.parseGeometryCollection_( + /** @type {GeoJSONGeometryCollection} */ (json), opt_options); + } else { + // we've been called with a geometry or an unknown object + // create a feature to get shared vertices handling + var feature = this.parseFeature_( + /** @type {GeoJSONFeature} */ ({type: 'Feature', geometry: json}), + opt_options); + result = feature.getGeometry(); } return result; }; +/** + * @param {GeoJSONObject} json GeoJSON object. + * @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options. + * @return {Array.} Parsed object coerced into array of features. + * @private + */ +ol.parser.GeoJSON.prototype.parseAsFeatureCollection_ = function(json, + opt_options) { + var obj = this.parse_(json, opt_options); + var features = []; + var feature; + if (obj instanceof ol.Feature) { + features = [obj]; + } else if (obj instanceof ol.geom.Geometry) { + feature = new ol.Feature(); + feature.setGeometry(obj); + features = [feature]; + } else if (goog.isArray(obj)) { + var item, geomArray; + for (var i = 0, ii = obj.length; i < ii; ++i) { + item = obj[i]; + geomArray = geomArray || (item instanceof ol.geom.Geometry); + if (!geomArray) { + goog.asserts.assert(item instanceof ol.Feature, 'expected feature'); + features = obj; + break; + } else { + feature = new ol.Feature(); + feature.setGeometry(item); + features[i] = feature; + } + } + } + return features; +}; + + /** * @param {GeoJSONFeature} json GeoJSON feature. * @param {ol.parser.ReadFeaturesOptions=} opt_options Read options. @@ -209,17 +227,20 @@ ol.parser.GeoJSON.prototype.parseFeatureCollection_ = function( /** * @param {GeoJSONGeometryCollection} json GeoJSON geometry collection. + * @param {ol.parser.ReadFeaturesOptions=} opt_options Read options. * @return {Array.} Parsed array of geometries. * @private */ -ol.parser.GeoJSON.prototype.parseGeometryCollection_ = function(json) { +ol.parser.GeoJSON.prototype.parseGeometryCollection_ = function(json, + opt_options) { var geometries = json.geometries, len = geometries.length, result = new Array(len), i; for (i = 0; i < len; ++i) { - result[i] = this.parse_(/** @type {GeoJSONGeometry} */ (geometries[i])); + result[i] = this.parse_(/** @type {GeoJSONGeometry} */ (geometries[i]), + opt_options); } return result; }; diff --git a/test/spec/ol/parser/geojson.test.js b/test/spec/ol/parser/geojson.test.js index 92132db407..f49221fdc2 100644 --- a/test/spec/ol/parser/geojson.test.js +++ b/test/spec/ol/parser/geojson.test.js @@ -267,6 +267,267 @@ describe('ol.parser.GeoJSON', function() { }); + describe('#parseAsFeatureCollection_()', function() { + + it('returns an array of features for FeatureCollection', function() { + var pointVertices = new ol.geom.SharedVertices(); + var lineVertices = new ol.geom.SharedVertices(); + var polygonVertices = new ol.geom.SharedVertices(); + + var lookup = { + 'point': pointVertices, + 'linestring': lineVertices, + 'polygon': polygonVertices, + 'multipoint': pointVertices, + 'multilinstring': lineVertices, + 'multipolygon': polygonVertices + }; + + var callback = function(feature, type) { + return lookup[type]; + }; + + var parser = new ol.parser.GeoJSON(); + var json = { + type: 'FeatureCollection', + features: [{ + type: 'Feature', + properties: { + foo: 'bar' + }, + geometry: { + type: 'Point', + coordinates: [1, 2] + } + }, { + type: 'Feature', + properties: { + bam: 'baz' + }, + geometry: { + type: 'LineString', + coordinates: [[1, 2], [3, 4]] + } + }] + }; + var features = parser.parseAsFeatureCollection_(json, + {callback: callback}); + + expect(features.length).to.be(2); + + var first = features[0]; + expect(first).to.be.a(ol.Feature); + expect(first.get('foo')).to.be('bar'); + expect(first.getGeometry()).to.be.a(ol.geom.Point); + + var second = features[1]; + expect(second).to.be.a(ol.Feature); + expect(second.get('bam')).to.be('baz'); + expect(second.getGeometry()).to.be.a(ol.geom.LineString); + + expect(pointVertices.coordinates.length).to.be(2); + expect(lineVertices.coordinates.length).to.be(4); + expect(polygonVertices.coordinates.length).to.be(0); + }); + + it('returns an array of features for Feature', function() { + var pointVertices = new ol.geom.SharedVertices(); + var lineVertices = new ol.geom.SharedVertices(); + var polygonVertices = new ol.geom.SharedVertices(); + + var lookup = { + 'point': pointVertices, + 'linestring': lineVertices, + 'polygon': polygonVertices, + 'multipoint': pointVertices, + 'multilinstring': lineVertices, + 'multipolygon': polygonVertices + }; + + var callback = function(feature, type) { + return lookup[type]; + }; + + var parser = new ol.parser.GeoJSON(); + var json = { + type: 'Feature', + properties: { + bam: 'baz' + }, + geometry: { + type: 'LineString', + coordinates: [[1, 2], [3, 4]] + } + }; + var features = parser.parseAsFeatureCollection_(json, + {callback: callback}); + + expect(features.length).to.be(1); + + var first = features[0]; + expect(first).to.be.a(ol.Feature); + expect(first.get('bam')).to.be('baz'); + expect(first.getGeometry()).to.be.a(ol.geom.LineString); + + expect(pointVertices.coordinates.length).to.be(0); + expect(lineVertices.coordinates.length).to.be(4); + expect(polygonVertices.coordinates.length).to.be(0); + }); + + it('returns an array of features for GeometryCollection', function() { + var pointVertices = new ol.geom.SharedVertices(); + var lineVertices = new ol.geom.SharedVertices(); + var polygonVertices = new ol.geom.SharedVertices(); + + var lookup = { + 'point': pointVertices, + 'linestring': lineVertices, + 'polygon': polygonVertices, + 'multipoint': pointVertices, + 'multilinstring': lineVertices, + 'multipolygon': polygonVertices + }; + + var callback = function(feature, type) { + return lookup[type]; + }; + + var parser = new ol.parser.GeoJSON(); + var json = { + type: 'GeometryCollection', + geometries: [{ + type: 'Point', + coordinates: [1, 2] + }, { + type: 'LineString', + coordinates: [[3, 4], [5, 6]] + }, { + type: 'Polygon', + coordinates: [[[7, 8], [9, 10], [11, 12], [7, 8]]] + }] + }; + var features = parser.parseAsFeatureCollection_(json, + {callback: callback}); + + expect(features.length).to.be(3); + + expect(features[0].getGeometry()).to.be.a(ol.geom.Point); + expect(features[1].getGeometry()).to.be.a(ol.geom.LineString); + expect(features[2].getGeometry()).to.be.a(ol.geom.Polygon); + + expect(pointVertices.coordinates.length).to.be(2); + expect(lineVertices.coordinates.length).to.be(4); + expect(polygonVertices.coordinates.length).to.be(8); + }); + + it('returns an array of features for Point', function() { + var pointVertices = new ol.geom.SharedVertices(); + var lineVertices = new ol.geom.SharedVertices(); + var polygonVertices = new ol.geom.SharedVertices(); + + var lookup = { + 'point': pointVertices, + 'linestring': lineVertices, + 'polygon': polygonVertices, + 'multipoint': pointVertices, + 'multilinstring': lineVertices, + 'multipolygon': polygonVertices + }; + + var callback = function(feature, type) { + return lookup[type]; + }; + + var parser = new ol.parser.GeoJSON(); + var json = { + type: 'Point', + coordinates: [1, 2] + }; + var features = parser.parseAsFeatureCollection_(json, + {callback: callback}); + + expect(features.length).to.be(1); + + expect(features[0].getGeometry()).to.be.a(ol.geom.Point); + + expect(pointVertices.coordinates.length).to.be(2); + expect(lineVertices.coordinates.length).to.be(0); + expect(polygonVertices.coordinates.length).to.be(0); + }); + + it('returns an array of features for LineString', function() { + var pointVertices = new ol.geom.SharedVertices(); + var lineVertices = new ol.geom.SharedVertices(); + var polygonVertices = new ol.geom.SharedVertices(); + + var lookup = { + 'point': pointVertices, + 'linestring': lineVertices, + 'polygon': polygonVertices, + 'multipoint': pointVertices, + 'multilinstring': lineVertices, + 'multipolygon': polygonVertices + }; + + var callback = function(feature, type) { + return lookup[type]; + }; + + var parser = new ol.parser.GeoJSON(); + var json = { + type: 'LineString', + coordinates: [[3, 4], [5, 6]] + }; + var features = parser.parseAsFeatureCollection_(json, + {callback: callback}); + + expect(features.length).to.be(1); + + expect(features[0].getGeometry()).to.be.a(ol.geom.LineString); + + expect(pointVertices.coordinates.length).to.be(0); + expect(lineVertices.coordinates.length).to.be(4); + expect(polygonVertices.coordinates.length).to.be(0); + }); + + it('returns an array of features for Polygon', function() { + var pointVertices = new ol.geom.SharedVertices(); + var lineVertices = new ol.geom.SharedVertices(); + var polygonVertices = new ol.geom.SharedVertices(); + + var lookup = { + 'point': pointVertices, + 'linestring': lineVertices, + 'polygon': polygonVertices, + 'multipoint': pointVertices, + 'multilinstring': lineVertices, + 'multipolygon': polygonVertices + }; + + var callback = function(feature, type) { + return lookup[type]; + }; + + var parser = new ol.parser.GeoJSON(); + var json = { + type: 'Polygon', + coordinates: [[[7, 8], [9, 10], [11, 12], [7, 8]]] + }; + var features = parser.parseAsFeatureCollection_(json, + {callback: callback}); + + expect(features.length).to.be(1); + + expect(features[0].getGeometry()).to.be.a(ol.geom.Polygon); + + expect(pointVertices.coordinates.length).to.be(0); + expect(lineVertices.coordinates.length).to.be(0); + expect(polygonVertices.coordinates.length).to.be(8); + }); + + + }); + }); goog.require('ol.Feature');