diff --git a/base.json b/base.json index e0f8102db4..7862da8233 100644 --- a/base.json +++ b/base.json @@ -39,7 +39,9 @@ "disambiguate-properties": true, "externs": [ + "//json.js", "externs/bingmaps.js", + "externs/geojson.js", "externs/proj4js.js", "externs/tilejson.js" ], diff --git a/externs/geojson.js b/externs/geojson.js index 687eb4cecb..6645f8a79e 100644 --- a/externs/geojson.js +++ b/externs/geojson.js @@ -6,17 +6,29 @@ */ - /** * @constructor */ -var GeoJSONCRS = function() {}; +var GeoJSONObject = function() {}; /** * @type {string} */ -GeoJSONCRS.prototype.type; +GeoJSONObject.prototype.type; + + +/** + * @type {!GeoJSONCRS|undefined} + */ +GeoJSONObject.prototype.crs; + + +/** + * @constructor + * @extends {GeoJSONObject} + */ +var GeoJSONCRS = function() {}; /** @@ -28,35 +40,38 @@ GeoJSONCRS.prototype.properties; /** * @constructor + * @extends {GeoJSONObject} */ var GeoJSONGeometry = function() {}; /** - * @type {string} - */ -GeoJSONGeometry.prototype.type; - - -/** - * @type {!Array.|!Array.>} + * @type {!Array.|!Array.>| + * !Array.>>} */ GeoJSONGeometry.prototype.coordinates; +/** + * @constructor + * @extends {GeoJSONObject} + */ +var GeoJSONGeometryCollection = function() {}; + + +/** + * @type {!Array.} + */ +GeoJSONGeometryCollection.prototype.geometries; + /** * @constructor + * @extends {GeoJSONObject} */ var GeoJSONFeature = function() {}; -/** - * @type {string} - */ -GeoJSONFeature.prototype.type; - - /** * @type {GeoJSONGeometry} */ @@ -72,16 +87,11 @@ GeoJSONFeature.prototype.properties; /** * @constructor + * @extends {GeoJSONObject} */ var GeoJSONFeatureCollection = function() {}; -/** - * @type {string} - */ -GeoJSONFeatureCollection.prototype.type; - - /** * @type {!Array.} */ @@ -94,13 +104,3 @@ GeoJSONFeatureCollection.prototype.features; GeoJSONFeatureCollection.prototype.bbox; -/** - * @type {!GeoJSONCRS|undefined} - */ -GeoJSONFeatureCollection.prototype.crs; - - -/** - * @type {!Object.} - */ -GeoJSONFeatureCollection.prototype.properties; diff --git a/src/ol/io/geojson.js b/src/ol/io/geojson.js new file mode 100644 index 0000000000..9587a7a5d0 --- /dev/null +++ b/src/ol/io/geojson.js @@ -0,0 +1,145 @@ +goog.provide('ol.io.geojson'); + +goog.require('ol.geom.Geometry'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.MultiPoint'); +goog.require('ol.geom.MultiPolygon'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); + + +/** + * Parse a GeoJSON string. + * @param {string} str GeoJSON string. + * @return {ol.geom.Geometry|Array.} Parsed geometry or array + * of geometries. + */ +ol.io.geojson.read = function(str) { + // TODO: add options and accept projection + var json = /** @type {GeoJSONObject} */ (JSON.parse(str)); + return ol.io.geojson.parse_(json); +}; + + +/** + * @param {GeoJSONObject} json GeoJSON object. + * @return {ol.geom.Geometry|Array.} Parsed geometry or array + * of geometries. + * @private + */ +ol.io.geojson.parse_ = function(json) { + var result; + switch (json.type) { + case 'GeometryCollection': + result = ol.io.geojson.parseGeometryCollection_( + /** @type {GeoJSONGeometryCollection} */ (json)); + break; + case 'Point': + result = ol.io.geojson.parsePoint_( + /** @type {GeoJSONGeometry} */ (json)); + break; + case 'LineString': + result = ol.io.geojson.parseLineString_( + /** @type {GeoJSONGeometry} */ (json)); + break; + case 'Polygon': + result = ol.io.geojson.parsePolygon_( + /** @type {GeoJSONGeometry} */ (json)); + break; + case 'MultiPoint': + result = ol.io.geojson.parseMultiPoint_( + /** @type {GeoJSONGeometry} */ (json)); + break; + case 'MultiLineString': + result = ol.io.geojson.parseMultiLineString_( + /** @type {GeoJSONGeometry} */ (json)); + break; + case 'MultiPolygon': + result = ol.io.geojson.parseMultiPolygon_( + /** @type {GeoJSONGeometry} */ (json)); + break; + default: + throw new Error('GeoJSON parsing not implemented for type: ' + json.type); + } + return result; +}; + + +/** + * @param {GeoJSONGeometryCollection} json GeoJSON geometry collection. + * @return {Array.} Parsed array of geometries. + * @private + */ +ol.io.geojson.parseGeometryCollection_ = function(json) { + var geometries = json.geometries, + len = geometries.length, + result = new Array(len), + i; + + for (i = 0; i < len; ++i) { + result[i] = ol.io.geojson.parse_( + /** @type {GeoJSONGeometry} */ (geometries[i])); + } + return result; +}; + + +/** + * @param {GeoJSONGeometry} json GeoJSON linestring. + * @return {ol.geom.LineString} Parsed linestring. + * @private + */ +ol.io.geojson.parseLineString_ = function(json) { + return new ol.geom.LineString(json.coordinates); +}; + + +/** + * @param {GeoJSONGeometry} json GeoJSON multi-linestring. + * @return {ol.geom.MultiLineString} Parsed multi-linestring. + * @private + */ +ol.io.geojson.parseMultiLineString_ = function(json) { + return new ol.geom.MultiLineString(json.coordinates); +}; + + +/** + * @param {GeoJSONGeometry} json GeoJSON multi-point. + * @return {ol.geom.MultiPoint} Parsed multi-point. + * @private + */ +ol.io.geojson.parseMultiPoint_ = function(json) { + return new ol.geom.MultiPoint(json.coordinates); +}; + + +/** + * @param {GeoJSONGeometry} json GeoJSON multi-polygon. + * @return {ol.geom.MultiPolygon} Parsed multi-polygon. + * @private + */ +ol.io.geojson.parseMultiPolygon_ = function(json) { + return new ol.geom.MultiPolygon(json.coordinates); +}; + + +/** + * @param {GeoJSONGeometry} json GeoJSON point. + * @return {ol.geom.Point} Parsed multi-point. + * @private + */ +ol.io.geojson.parsePoint_ = function(json) { + return new ol.geom.Point(json.coordinates); +}; + + +/** + * @param {GeoJSONGeometry} json GeoJSON polygon. + * @return {ol.geom.Polygon} Parsed polygon. + * @private + */ +ol.io.geojson.parsePolygon_ = function(json) { + return new ol.geom.Polygon(json.coordinates); +}; diff --git a/test/ol.html b/test/ol.html index c71623217a..bdc279a547 100644 --- a/test/ol.html +++ b/test/ol.html @@ -80,6 +80,7 @@ + diff --git a/test/spec/ol/io/geojson.test.js b/test/spec/ol/io/geojson.test.js new file mode 100644 index 0000000000..fc2ab65b4b --- /dev/null +++ b/test/spec/ol/io/geojson.test.js @@ -0,0 +1,65 @@ +describe('ol.io.geojson', function() { + + describe('read()', function() { + + it('parses point', function() { + var str = JSON.stringify({ + type: 'Point', + coordinates: [10, 20] + }); + + var obj = ol.io.geojson.read(str); + expect(obj).toBeA(ol.geom.Point); + expect(obj.coordinates[0]).toBe(10); + expect(obj.coordinates[1]).toBe(20); + }); + + it('parses linestring', function() { + var str = JSON.stringify({ + type: 'LineString', + coordinates: [[10, 20], [30, 40]] + }); + + var obj = ol.io.geojson.read(str); + expect(obj).toBeA(ol.geom.LineString); + expect(obj.coordinates[0]).toBe(10); + expect(obj.coordinates[1]).toBe(20); + expect(obj.coordinates[2]).toBe(30); + expect(obj.coordinates[3]).toBe(40); + }); + + it('parses polygon', function() { + var outer = [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], + inner1 = [[1, 1], [2, 1], [2, 2], [1, 2], [1, 1]], + inner2 = [[8, 8], [9, 8], [9, 9], [8, 9], [8, 8]], + str = JSON.stringify({ + type: 'Polygon', + coordinates: [outer, inner1, inner2] + }); + + var obj = ol.io.geojson.read(str); + expect(obj).toBeA(ol.geom.Polygon); + expect(obj.rings.length).toBe(3); + expect(obj.rings[0]).toBeA(ol.geom.LinearRing); + expect(obj.rings[1]).toBeA(ol.geom.LinearRing); + expect(obj.rings[2]).toBeA(ol.geom.LinearRing); + }); + + it('parses geometry collection', function() { + var str = JSON.stringify({ + type: 'GeometryCollection', + geometries: [ + {type: 'Point', coordinates: [10, 20]}, + {type: 'LineString', coordinates: [[30, 40], [50, 60]]} + ] + }); + + var array = ol.io.geojson.read(str); + expect(array.length).toBe(2); + expect(array[0]).toBeA(ol.geom.Point); + expect(array[1]).toBeA(ol.geom.LineString); + }); + + }); + +});