diff --git a/examples/tile-vector.js b/examples/tile-vector.js index eb73c81f75..e25042023a 100644 --- a/examples/tile-vector.js +++ b/examples/tile-vector.js @@ -11,9 +11,7 @@ goog.require('ol.tilegrid.XYZ'); var waterLayer = new ol.layer.Vector({ source: new ol.source.TileVector({ - format: new ol.format.TopoJSON({ - defaultProjection: 'EPSG:4326' - }), + format: new ol.format.TopoJSON(), projection: 'EPSG:3857', tileGrid: new ol.tilegrid.XYZ({ maxZoom: 19 @@ -31,9 +29,7 @@ var waterLayer = new ol.layer.Vector({ var roadStyleCache = {}; var roadLayer = new ol.layer.Vector({ source: new ol.source.TileVector({ - format: new ol.format.TopoJSON({ - defaultProjection: 'EPSG:4326' - }), + format: new ol.format.TopoJSON(), projection: 'EPSG:3857', tileGrid: new ol.tilegrid.XYZ({ maxZoom: 19 diff --git a/externs/olx.js b/externs/olx.js index d8ba2cbfbd..6e2d5add74 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -1153,7 +1153,10 @@ olx.format.ReadOptions; /** * Projection of the data we are reading. If not provided, the projection will - * be derived from the data (where possible). + * be derived from the data (where possible) or the `defaultDataProjection` of + * the format is assigned (where set). If the projection can not be derived from + * the data and if no `defaultDataProjection` is set for a format, the features + * will not be reprojected. * @type {ol.proj.ProjectionLike|undefined} */ olx.format.ReadOptions.prototype.dataProjection; @@ -1175,22 +1178,25 @@ olx.format.WriteOptions; /** - * Projection of the data we are writing. If not provided, features will be - * written in the `featureProjection`. + * Projection of the data we are writing. If not provided, the + * `defaultDataProjection` of the format is assigned (where set). If no + * `defaultDataProjection` is set for a format, the features will be returned + * in the `featureProjection`. * @type {ol.proj.ProjectionLike|undefined} */ olx.format.WriteOptions.prototype.dataProjection; /** - * Projection of the feature geometries serialized by the format writer. + * Projection of the feature geometries that will be serialized by the format + * writer. * @type {ol.proj.ProjectionLike} */ olx.format.WriteOptions.prototype.featureProjection; /** - * @typedef {{defaultProjection: ol.proj.ProjectionLike, + * @typedef {{defaultDataProjection: ol.proj.ProjectionLike, * geometryName: (string|undefined)}} * @api */ @@ -1198,10 +1204,10 @@ olx.format.GeoJSONOptions; /** - * Default projection. + * Default data projection. * @type {ol.proj.ProjectionLike} */ -olx.format.GeoJSONOptions.prototype.defaultProjection; +olx.format.GeoJSONOptions.prototype.defaultDataProjection; /** @@ -1226,17 +1232,17 @@ olx.format.PolylineOptions.prototype.factor; /** - * @typedef {{defaultProjection: ol.proj.ProjectionLike}} + * @typedef {{defaultDataProjection: ol.proj.ProjectionLike}} * @api */ olx.format.TopoJSONOptions; /** - * Default projection. + * Default data projection. * @type {ol.proj.ProjectionLike} */ -olx.format.TopoJSONOptions.prototype.defaultProjection; +olx.format.TopoJSONOptions.prototype.defaultDataProjection; /** diff --git a/src/ol/format/featureformat.js b/src/ol/format/featureformat.js index 0627c4b90c..229f7bb83d 100644 --- a/src/ol/format/featureformat.js +++ b/src/ol/format/featureformat.js @@ -17,6 +17,12 @@ goog.require('ol.proj'); * @constructor */ ol.format.Feature = function() { + + /** + * @protected + * @type {ol.proj.Projection} + */ + this.defaultDataProjection = null; }; @@ -43,7 +49,28 @@ ol.format.Feature.prototype.getReadOptions = function( featureProjection: opt_options.featureProjection }; } - return options; + return this.adaptOptionsWithDefaultDataProjection(options); +}; + + +/** + * @param {olx.format.WriteOptions|olx.format.ReadOptions|undefined} options + * Options. + * @protected + * @return {olx.format.WriteOptions|olx.format.ReadOptions|undefined} + * Updated options. + */ +ol.format.Feature.prototype.adaptOptionsWithDefaultDataProjection = function( + options) { + var updatedOptions; + if (goog.isDef(options)) { + updatedOptions = { + featureProjection: options.featureProjection, + dataProjection: goog.isDefAndNotNull(options.dataProjection) ? + options.dataProjection : this.defaultDataProjection + }; + } + return updatedOptions; }; @@ -146,25 +173,3 @@ ol.format.Feature.transformWithOptions = function( return geometry; } }; - - -/** - * @param {olx.format.WriteOptions|olx.format.ReadOptions|undefined} options - * Options. - * @param {ol.proj.ProjectionLike} defaultDataProjection Default projection. - * @protected - * @return {olx.format.WriteOptions|olx.format.ReadOptions|undefined} - * Updated options. - */ -ol.format.Feature.setDefaultDataProjection = function( - options, defaultDataProjection) { - if (goog.isDef(options)) { - if (!goog.isDef(options.dataProjection)) { - options = { - featureProjection: options.featureProjection, - dataProjection: defaultDataProjection - }; - } - } - return options; -}; diff --git a/src/ol/format/geojsonformat.js b/src/ol/format/geojsonformat.js index f6cfc07a70..3c34782ee9 100644 --- a/src/ol/format/geojsonformat.js +++ b/src/ol/format/geojsonformat.js @@ -37,11 +37,11 @@ ol.format.GeoJSON = function(opt_options) { goog.base(this); /** - * @private - * @type {ol.proj.Projection} + * @inheritDoc */ - this.defaultProjection_ = ol.proj.get(options.defaultProjection ? - options.defaultProjection : 'EPSG:4326'); + this.defaultDataProjection = ol.proj.get( + goog.isDefAndNotNull(options.defaultDataProjection) ? + options.defaultDataProjection : 'EPSG:4326'); /** @@ -472,7 +472,7 @@ ol.format.GeoJSON.prototype.readProjectionFromObject = function(object) { return null; } } else { - return this.defaultProjection_; + return this.defaultDataProjection; } }; diff --git a/src/ol/format/gpxformat.js b/src/ol/format/gpxformat.js index bcec5da2fb..707c11778f 100644 --- a/src/ol/format/gpxformat.js +++ b/src/ol/format/gpxformat.js @@ -5,7 +5,6 @@ goog.require('goog.asserts'); goog.require('goog.dom.NodeType'); goog.require('goog.object'); goog.require('ol.Feature'); -goog.require('ol.format.Feature'); goog.require('ol.format.XMLFeature'); goog.require('ol.format.XSD'); goog.require('ol.geom.LineString'); @@ -31,6 +30,11 @@ ol.format.GPX = function(opt_options) { goog.base(this); + /** + * @inheritDoc + */ + this.defaultDataProjection = ol.proj.get('EPSG:4326'); + /** * @type {function(ol.Feature, Node)|undefined} * @private @@ -498,7 +502,7 @@ ol.format.GPX.prototype.readProjection; * @inheritDoc */ ol.format.GPX.prototype.readProjectionFromDocument = function(doc) { - return ol.proj.get('EPSG:4326'); + return this.defaultDataProjection; }; @@ -506,7 +510,7 @@ ol.format.GPX.prototype.readProjectionFromDocument = function(doc) { * @inheritDoc */ ol.format.GPX.prototype.readProjectionFromNode = function(node) { - return ol.proj.get('EPSG:4326'); + return this.defaultDataProjection; }; @@ -866,9 +870,6 @@ ol.format.GPX.prototype.writeFeaturesNode = function(features, opt_options) { //FIXME Serialize metadata var gpx = ol.xml.createElementNS('http://www.topografix.com/GPX/1/1', 'gpx'); - // for convenience set a default dataProjection - opt_options = ol.format.Feature.setDefaultDataProjection( - opt_options, this.readProjectionFromDocument(null)); features = ol.format.XMLFeature.transformFeaturesWithOptions( features, true, opt_options); diff --git a/src/ol/format/igcformat.js b/src/ol/format/igcformat.js index 664cd35a10..d1347e9e39 100644 --- a/src/ol/format/igcformat.js +++ b/src/ol/format/igcformat.js @@ -37,6 +37,11 @@ ol.format.IGC = function(opt_options) { goog.base(this); + /** + * @inheritDoc + */ + this.defaultDataProjection = ol.proj.get('EPSG:4326'); + /** * @private * @type {ol.format.IGCZ} @@ -217,5 +222,5 @@ ol.format.IGC.prototype.readProjection; * @inheritDoc */ ol.format.IGC.prototype.readProjectionFromText = function(text) { - return ol.proj.get('EPSG:4326'); + return this.defaultDataProjection; }; diff --git a/src/ol/format/jsonfeatureformat.js b/src/ol/format/jsonfeatureformat.js index 3fe530b574..109613a1ce 100644 --- a/src/ol/format/jsonfeatureformat.js +++ b/src/ol/format/jsonfeatureformat.js @@ -128,7 +128,9 @@ ol.format.JSONFeature.prototype.readProjectionFromObject = goog.abstractMethod; * @inheritDoc */ ol.format.JSONFeature.prototype.writeFeature = function(feature, opt_options) { - return this.writeFeatureObject(feature, opt_options); + return this.writeFeatureObject( + feature, + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; @@ -146,7 +148,9 @@ ol.format.JSONFeature.prototype.writeFeatureObject = goog.abstractMethod; */ ol.format.JSONFeature.prototype.writeFeatures = function( features, opt_options) { - return this.writeFeaturesObject(features, opt_options); + return this.writeFeaturesObject( + features, + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; @@ -164,7 +168,9 @@ ol.format.JSONFeature.prototype.writeFeaturesObject = goog.abstractMethod; */ ol.format.JSONFeature.prototype.writeGeometry = function( geometry, opt_options) { - return this.writeGeometryObject(geometry, opt_options); + return this.writeGeometryObject( + geometry, + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; diff --git a/src/ol/format/kmlformat.js b/src/ol/format/kmlformat.js index 8dc1aaf0c8..fa4d28948a 100644 --- a/src/ol/format/kmlformat.js +++ b/src/ol/format/kmlformat.js @@ -16,7 +16,6 @@ goog.require('ol.Feature'); goog.require('ol.array'); goog.require('ol.color'); goog.require('ol.feature'); -goog.require('ol.format.Feature'); goog.require('ol.format.XMLFeature'); goog.require('ol.format.XSD'); goog.require('ol.geom.Geometry'); @@ -71,6 +70,11 @@ ol.format.KML = function(opt_options) { goog.base(this); + /** + * @inheritDoc + */ + this.defaultDataProjection = ol.proj.get('EPSG:4326'); + var defaultStyle = goog.isDef(options.defaultStyle) ? options.defaultStyle : ol.format.KML.DEFAULT_STYLE_ARRAY_; @@ -1654,7 +1658,7 @@ ol.format.KML.prototype.readProjection; * @inheritDoc */ ol.format.KML.prototype.readProjectionFromDocument = function(doc) { - return ol.proj.get('EPSG:4326'); + return this.defaultDataProjection; }; @@ -1662,7 +1666,7 @@ ol.format.KML.prototype.readProjectionFromDocument = function(doc) { * @inheritDoc */ ol.format.KML.prototype.readProjectionFromNode = function(node) { - return ol.proj.get('EPSG:4326'); + return this.defaultDataProjection; }; @@ -2523,9 +2527,6 @@ ol.format.KML.prototype.writeFeaturesNode = function(features, opt_options) { ol.xml.setAttributeNS(kml, xmlSchemaInstanceUri, 'xsi:schemaLocation', ol.format.KML.SCHEMA_LOCATION_); - // for convenience set a default dataProjection - opt_options = ol.format.Feature.setDefaultDataProjection( - opt_options, this.readProjectionFromDocument(null)); features = ol.format.XMLFeature.transformFeaturesWithOptions( features, true, opt_options); diff --git a/src/ol/format/osmxmlformat.js b/src/ol/format/osmxmlformat.js index 7627b428df..7831e7f32f 100644 --- a/src/ol/format/osmxmlformat.js +++ b/src/ol/format/osmxmlformat.js @@ -26,6 +26,11 @@ goog.require('ol.xml'); */ ol.format.OSMXML = function() { goog.base(this); + + /** + * @inheritDoc + */ + this.defaultDataProjection = ol.proj.get('EPSG:4326'); }; goog.inherits(ol.format.OSMXML, ol.format.XMLFeature); @@ -231,7 +236,7 @@ ol.format.OSMXML.prototype.readProjection; * @inheritDoc */ ol.format.OSMXML.prototype.readProjectionFromDocument = function(doc) { - return ol.proj.get('EPSG:4326'); + return this.defaultDataProjection; }; @@ -239,5 +244,5 @@ ol.format.OSMXML.prototype.readProjectionFromDocument = function(doc) { * @inheritDoc */ ol.format.OSMXML.prototype.readProjectionFromNode = function(node) { - return ol.proj.get('EPSG:4326'); + return this.defaultDataProjection; }; diff --git a/src/ol/format/polylineformat.js b/src/ol/format/polylineformat.js index 85b357c094..0cb41b57bb 100644 --- a/src/ol/format/polylineformat.js +++ b/src/ol/format/polylineformat.js @@ -23,6 +23,11 @@ ol.format.Polyline = function(opt_options) { goog.base(this); + /** + * @inheritDoc + */ + this.defaultDataProjection = ol.proj.get('EPSG:4326'); + /** * @private * @type {number} @@ -309,12 +314,9 @@ ol.format.Polyline.prototype.readGeometryFromText = var coordinates = ol.geom.flat.inflate.coordinates( flatCoordinates, 0, flatCoordinates.length, 2); - // for convenience set a default dataProjection - opt_options = ol.format.Feature.setDefaultDataProjection( - opt_options, this.readProjectionFromText('')); - return ol.format.Feature.transformWithOptions( - new ol.geom.LineString(coordinates), false, false, opt_options); + new ol.geom.LineString(coordinates), false, false, + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; @@ -333,7 +335,7 @@ ol.format.Polyline.prototype.readProjection; * @inheritDoc */ ol.format.Polyline.prototype.readProjectionFromText = function(text) { - return ol.proj.get('EPSG:4326'); + return this.defaultDataProjection; }; @@ -379,12 +381,10 @@ ol.format.Polyline.prototype.writeGeometry; ol.format.Polyline.prototype.writeGeometryText = function(geometry, opt_options) { goog.asserts.assertInstanceof(geometry, ol.geom.LineString); - // for convenience set a default dataProjection - opt_options = ol.format.Feature.setDefaultDataProjection( - opt_options, this.readProjectionFromText('')); geometry = /** @type {ol.geom.LineString} */ (ol.format.Feature.transformWithOptions( - geometry, true, true, opt_options)); + geometry, true, true, + this.adaptOptionsWithDefaultDataProjection(opt_options))); var flatCoordinates = geometry.getFlatCoordinates(); var stride = geometry.getStride(); return ol.format.Polyline.encodeDeltas(flatCoordinates, stride, this.factor_); diff --git a/src/ol/format/textfeatureformat.js b/src/ol/format/textfeatureformat.js index 0b30b5dc4a..583d0a3062 100644 --- a/src/ol/format/textfeatureformat.js +++ b/src/ol/format/textfeatureformat.js @@ -48,7 +48,9 @@ ol.format.TextFeature.prototype.getType = function() { * @inheritDoc */ ol.format.TextFeature.prototype.readFeature = function(source, opt_options) { - return this.readFeatureFromText(this.getText_(source), opt_options); + return this.readFeatureFromText( + this.getText_(source), + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; @@ -65,7 +67,9 @@ ol.format.TextFeature.prototype.readFeatureFromText = goog.abstractMethod; * @inheritDoc */ ol.format.TextFeature.prototype.readFeatures = function(source, opt_options) { - return this.readFeaturesFromText(this.getText_(source), opt_options); + return this.readFeaturesFromText( + this.getText_(source), + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; @@ -82,7 +86,9 @@ ol.format.TextFeature.prototype.readFeaturesFromText = goog.abstractMethod; * @inheritDoc */ ol.format.TextFeature.prototype.readGeometry = function(source, opt_options) { - return this.readGeometryFromText(this.getText_(source), opt_options); + return this.readGeometryFromText( + this.getText_(source), + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; @@ -115,7 +121,9 @@ ol.format.TextFeature.prototype.readProjectionFromText = goog.abstractMethod; * @inheritDoc */ ol.format.TextFeature.prototype.writeFeature = function(feature, opt_options) { - return this.writeFeatureText(feature, opt_options); + return this.writeFeatureText( + feature, + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; @@ -133,7 +141,9 @@ ol.format.TextFeature.prototype.writeFeatureText = goog.abstractMethod; */ ol.format.TextFeature.prototype.writeFeatures = function( features, opt_options) { - return this.writeFeaturesText(features, opt_options); + return this.writeFeaturesText( + features, + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; @@ -151,7 +161,9 @@ ol.format.TextFeature.prototype.writeFeaturesText = goog.abstractMethod; */ ol.format.TextFeature.prototype.writeGeometry = function( geometry, opt_options) { - return this.writeGeometryText(geometry, opt_options); + return this.writeGeometryText( + geometry, + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; diff --git a/src/ol/format/topojsonformat.js b/src/ol/format/topojsonformat.js index 5e272850d1..ab7bd47794 100644 --- a/src/ol/format/topojsonformat.js +++ b/src/ol/format/topojsonformat.js @@ -31,11 +31,11 @@ ol.format.TopoJSON = function(opt_options) { goog.base(this); /** - * @private - * @type {ol.proj.Projection} + * @inheritDoc */ - this.defaultProjection_ = - ol.proj.get(options.defaultProjection || 'EPSG:4326'); + this.defaultDataProjection = ol.proj.get( + goog.isDefAndNotNull(options.defaultDataProjection) ? + options.defaultDataProjection : 'EPSG:4326'); }; goog.inherits(ol.format.TopoJSON, ol.format.JSONFeature); @@ -391,7 +391,7 @@ ol.format.TopoJSON.transformVertex_ = function(vertex, scale, translate) { * @api */ ol.format.TopoJSON.prototype.readProjection = function(object) { - return this.defaultProjection_; + return this.defaultDataProjection; }; diff --git a/src/ol/format/xmlfeatureformat.js b/src/ol/format/xmlfeatureformat.js index d6c23aaeb0..90ecddc10f 100644 --- a/src/ol/format/xmlfeatureformat.js +++ b/src/ol/format/xmlfeatureformat.js @@ -199,7 +199,9 @@ ol.format.XMLFeature.prototype.readProjectionFromNode = goog.abstractMethod; * @inheritDoc */ ol.format.XMLFeature.prototype.writeFeature = function(feature, opt_options) { - return this.writeFeatureNode(feature, opt_options); + return this.writeFeatureNode( + feature, + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; @@ -216,7 +218,9 @@ ol.format.XMLFeature.prototype.writeFeatureNode = goog.abstractMethod; * @inheritDoc */ ol.format.XMLFeature.prototype.writeFeatures = function(features, opt_options) { - return this.writeFeaturesNode(features, opt_options); + return this.writeFeaturesNode( + features, + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; @@ -233,7 +237,9 @@ ol.format.XMLFeature.prototype.writeFeaturesNode = goog.abstractMethod; * @inheritDoc */ ol.format.XMLFeature.prototype.writeGeometry = function(geometry, opt_options) { - return this.writeGeometryNode(geometry, opt_options); + return this.writeGeometryNode( + geometry, + this.adaptOptionsWithDefaultDataProjection(opt_options)); }; diff --git a/src/ol/source/geojsonsource.js b/src/ol/source/geojsonsource.js index ab4ab5803a..b1f11c89c7 100644 --- a/src/ol/source/geojsonsource.js +++ b/src/ol/source/geojsonsource.js @@ -23,7 +23,7 @@ ol.source.GeoJSON = function(opt_options) { attributions: options.attributions, extent: options.extent, format: new ol.format.GeoJSON({ - defaultProjection: options.defaultProjection + defaultDataProjection: options.defaultProjection }), logo: options.logo, object: options.object, diff --git a/src/ol/source/topojsonsource.js b/src/ol/source/topojsonsource.js index 2befa91465..8eec88abd1 100644 --- a/src/ol/source/topojsonsource.js +++ b/src/ol/source/topojsonsource.js @@ -23,7 +23,7 @@ ol.source.TopoJSON = function(opt_options) { attributions: options.attributions, extent: options.extent, format: new ol.format.TopoJSON({ - defaultProjection: options.defaultProjection + defaultDataProjection: options.defaultProjection }), logo: options.logo, object: options.object, diff --git a/test/spec/ol/format/geojsonformat.test.js b/test/spec/ol/format/geojsonformat.test.js index 2c6b220ff5..a3da003c8f 100644 --- a/test/spec/ol/format/geojsonformat.test.js +++ b/test/spec/ol/format/geojsonformat.test.js @@ -486,7 +486,6 @@ describe('ol.format.GeoJSON', function() { var str = JSON.stringify(data), array = format.readFeatures(str); var geojson = format.writeFeatures(array, { - dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' }); var result = format.readFeatures(geojson); @@ -554,6 +553,20 @@ describe('ol.format.GeoJSON', function() { }); }); + it('transforms and encodes a point', function() { + var point = new ol.geom.Point([2, 3]); + var geojson = format.writeGeometry(point, { + featureProjection: 'EPSG:3857' + }); + var newPoint = format.readGeometry(geojson, { + featureProjection: 'EPSG:3857' + }); + expect(point.getCoordinates()[0]).to.eql(newPoint.getCoordinates()[0]); + expect( + Math.abs(point.getCoordinates()[1] - newPoint.getCoordinates()[1])) + .to.be.lessThan(0.0000001); + }); + }); }); diff --git a/test/spec/ol/format/igcformat.test.js b/test/spec/ol/format/igcformat.test.js index 24921941b0..c3b9c88440 100644 --- a/test/spec/ol/format/igcformat.test.js +++ b/test/spec/ol/format/igcformat.test.js @@ -47,7 +47,6 @@ describe('ol.format.IGC', function() { it('does transform and read a feature', function() { var feature = format.readFeature(igc, { - dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' }); expect(feature).to.be.an(ol.Feature); @@ -91,7 +90,6 @@ describe('ol.format.IGC', function() { it('does transform and read features', function() { var features = format.readFeatures(igc, { - dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' }); expect(features.length).to.eql(1);