From 93b067b6bcd3e0222b89b98f49806c4e2e2bc03e Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Thu, 23 May 2013 14:39:18 +0200 Subject: [PATCH] Write support for ol.parser.GeoJSON Also add some convenience with static read and write methods based on the singleton. --- src/ol/parser/geojson.exports | 3 + src/ol/parser/geojson.js | 133 ++++++++++++++++++++++++++++ test/spec/ol/parser/geojson.test.js | 48 ++++++++++ 3 files changed, 184 insertions(+) diff --git a/src/ol/parser/geojson.exports b/src/ol/parser/geojson.exports index d7ec119aa5..7143cfbf11 100644 --- a/src/ol/parser/geojson.exports +++ b/src/ol/parser/geojson.exports @@ -1,3 +1,6 @@ @exportSymbol ol.parser.GeoJSON @exportProperty ol.parser.GeoJSON.prototype.read +@exportProperty ol.parser.GeoJSON.read +@exportProperty ol.parser.GeoJSON.prototype.write +@exportProperty ol.parser.GeoJSON.write diff --git a/src/ol/parser/geojson.js b/src/ol/parser/geojson.js index 83f711205e..ca55c5b923 100644 --- a/src/ol/parser/geojson.js +++ b/src/ol/parser/geojson.js @@ -1,8 +1,10 @@ goog.provide('ol.parser.GeoJSON'); goog.require('goog.asserts'); +goog.require('goog.object'); goog.require('ol.Feature'); goog.require('ol.geom.Geometry'); +goog.require('ol.geom.GeometryCollection'); goog.require('ol.geom.GeometryType'); goog.require('ol.geom.LineString'); goog.require('ol.geom.MultiLineString'); @@ -24,6 +26,7 @@ goog.require('ol.parser.StringFeatureParser'); */ ol.parser.GeoJSON = function() {}; goog.inherits(ol.parser.GeoJSON, ol.parser.Parser); +goog.addSingletonGetter(ol.parser.GeoJSON); /** @@ -39,6 +42,18 @@ ol.parser.GeoJSON.prototype.read = function(str) { }; +/** + * Parse a GeoJSON string. + * @param {string} str GeoJSON string. + * @return {ol.Feature|Array.| + * ol.geom.Geometry|Array.} Parsed geometry or array + * of geometries. + */ +ol.parser.GeoJSON.read = function(str) { + return ol.parser.GeoJSON.getInstance().read(str); +}; + + /** * Parse a GeoJSON feature collection. * @param {string} str GeoJSON feature collection. @@ -272,6 +287,124 @@ ol.parser.GeoJSON.prototype.parsePolygon_ = function(json, opt_vertices) { }; +/** + * @param {ol.geom.Geometry} geometry Geometry to encode. + * @return {GeoJSONGeometry} GeoJSON geometry. + * @private + */ +ol.parser.GeoJSON.prototype.encodeGeometry_ = function(geometry) { + var type = geometry.getType(); + return /** @type {GeoJSONGeometry} */({ + type: goog.object.findKey(ol.parser.GeoJSON.GeometryType, + function(value, key) { + return value === type; + } + ), + coordinates: geometry.getCoordinates() + }); +}; + + +/** + * @param {ol.geom.GeometryCollection} collection Geometry collection to + * encode. + * @return {GeoJSONGeometryCollection} GeoJSON geometry collection. + * @private + */ +ol.parser.GeoJSON.prototype.encodeGeometryCollection_ = function(collection) { + var geometries = []; + for (var i = 0, ii = collection.components.length; i < ii; ++i) { + geometries.push(this.encodeGeometry_(collection.components[i])); + } + return /** @type {GeoJSONGeometryCollection} */({ + type: 'GeometryCollection', + geometries: geometries + }); +}; + + +/** + * @param {Array.} collection Feature collection to encode. + * @return {GeoJSONFeatureCollection} GeoJSON feature collection. + * @private + */ +ol.parser.GeoJSON.prototype.encodeFeatureCollection_ = function(collection) { + var features = []; + for (var i = 0, ii = collection.length; i < ii; ++i) { + features.push(this.encodeFeature_(collection[i])); + } + return /** @type {GeoJSONFeatureCollection} */({ + type: 'FeatureCollection', + features: features + }); +}; + + +/** + * @param {ol.Feature} feature Feature to encode. + * @return {GeoJSONFeature} GeoJSON feature. + * @private + */ +ol.parser.GeoJSON.prototype.encodeFeature_ = function(feature) { + var geometry = feature.getGeometry(), + attributes = feature.getAttributes(); + var properties = goog.object.filter(attributes, + function(element, index, array) { + return !(element instanceof ol.geom.Geometry); + }); + return /** @type {GeoJSONFeature} */({ + type: 'Feature', + properties: properties, + geometry: this.encodeGeometry_(geometry) + }); +}; + + +/** + * @param {ol.geom.GeometryCollection|ol.geom.Geometry|Array.| + * ol.Feature} obj The object to encode. + * @return {string} The GeoJSON as string. + * @private + */ +ol.parser.GeoJSON.prototype.encode_ = function(obj) { + var result; + if (obj instanceof ol.geom.GeometryCollection) { + result = this.encodeGeometryCollection_(obj); + } else if (obj instanceof ol.geom.Geometry) { + result = this.encodeGeometry_(obj); + } else if (obj instanceof ol.Feature) { + result = this.encodeFeature_(obj); + } else if (goog.isArray(obj)) { + result = this.encodeFeatureCollection_(obj); + } + return JSON.stringify(result); +}; + + +/** + * Write out a geometry, geometry collection, feature or an array of features + * as a GeoJSON string. + * @param {ol.geom.Geometry|ol.geom.GeometryCollection|ol.Feature| + * Array.} obj The object to encode. + * @return {string} GeoJSON for the geometry. + */ +ol.parser.GeoJSON.write = function(obj) { + return ol.parser.GeoJSON.getInstance().write(obj); +}; + + +/** + * Write out a geometry, geometry collection, feature or an array of features + * as a GeoJSON string. + * @param {ol.geom.Geometry|ol.geom.GeometryCollection|ol.Feature| + * Array.} obj The object to encode. + * @return {string} GeoJSON for the geometry. + */ +ol.parser.GeoJSON.prototype.write = function(obj) { + return this.encode_(obj); +}; + + /** * @enum {ol.geom.GeometryType} */ diff --git a/test/spec/ol/parser/geojson.test.js b/test/spec/ol/parser/geojson.test.js index 053370ad2d..0d08cbdbda 100644 --- a/test/spec/ol/parser/geojson.test.js +++ b/test/spec/ol/parser/geojson.test.js @@ -68,6 +68,53 @@ describe('ol.parser.GeoJSON', function() { ] }; + describe('#write()', function() { + + it('encodes point', function() { + var point = new ol.geom.Point([10, 20]); + var geojson = parser.write(point); + expect(point).to.eql(parser.read(geojson)); + }); + + it('encodes linestring', function() { + var linestring = new ol.geom.LineString([[10, 20], [30, 40]]); + var geojson = parser.write(linestring); + expect(linestring).to.eql(parser.read(geojson)); + }); + + it('encodes 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]]; + var polygon = new ol.geom.Polygon([outer, inner1, inner2]); + var geojson = parser.write(polygon); + expect(polygon).to.eql(parser.read(geojson)); + }); + + it('encodes geometry collection', function() { + var collection = new ol.geom.GeometryCollection([ + new ol.geom.Point([10, 20]), + new ol.geom.LineString([[30, 40], [50, 60]]) + ]); + var geojson = parser.write(collection); + // surprised to see read return an Array of geometries instead of + // a true ol.geom.GeometryCollection, so compare collection.components + expect(collection.components).to.eql(parser.read(geojson)); + }); + + it('encodes feature collection', function() { + var str = JSON.stringify(data), + array = parser.read(str); + var geojson = parser.write(array); + var result = parser.read(geojson); + for (var i = 0, ii = array.length; i < ii; ++i) { + expect(array[i].getGeometry()).to.eql(result[i].getGeometry()); + expect(array[i].getAttributes()).to.eql(result[i].getAttributes()); + } + }); + + }); + describe('#read()', function() { it('parses point', function() { @@ -221,6 +268,7 @@ describe('ol.parser.GeoJSON', function() { goog.require('ol.Feature'); goog.require('ol.extent'); +goog.require('ol.geom.GeometryCollection'); goog.require('ol.geom.LinearRing'); goog.require('ol.geom.LineString'); goog.require('ol.geom.Point');