Add precision parameter to all toGeoJSON functions (#5444)

* Add precision parameter to all toGeoJSON functions

* Replace usage of toPrecision with Utils.formatNum

* Always default to six decimal places

* Fix docs

* Allow precision of 0
This commit is contained in:
Matt Grande 2017-05-31 08:06:58 -04:00 committed by Per Liedman
parent 4f5fef2a56
commit 1120c46ed9
2 changed files with 123 additions and 21 deletions

View File

@ -73,6 +73,14 @@ describe("L.Marker#toGeoJSON", function () {
coordinates: [20, 10, 30] coordinates: [20, 10, 30]
}); });
}); });
it('should allow specific precisions', function () {
var marker = new L.Marker([10.123456, 20.123456, 30.123456]);
expect(marker.toGeoJSON(3).geometry).to.eql({
type: 'Point',
coordinates: [20.123, 10.123, 30.123]
});
});
}); });
describe("L.Circle#toGeoJSON", function () { describe("L.Circle#toGeoJSON", function () {
@ -91,6 +99,14 @@ describe("L.Circle#toGeoJSON", function () {
coordinates: [20, 10, 30] coordinates: [20, 10, 30]
}); });
}); });
it('should allow specific precisions', function () {
var circle = new L.Circle([10.1234, 20.1234, 30.1234], 100);
expect(circle.toGeoJSON(3).geometry).to.eql({
type: 'Point',
coordinates: [20.123, 10.123, 30.123]
});
});
}); });
describe("L.CircleMarker#toGeoJSON", function () { describe("L.CircleMarker#toGeoJSON", function () {
@ -109,6 +125,14 @@ describe("L.CircleMarker#toGeoJSON", function () {
coordinates: [20, 10, 30] coordinates: [20, 10, 30]
}); });
}); });
it("should allow specific precisions", function () {
var marker = new L.CircleMarker([10.1234, 20.1234]);
expect(marker.toGeoJSON(3).geometry).to.eql({
type: 'Point',
coordinates: [20.123, 10.123]
});
});
}); });
describe("L.Polyline#toGeoJSON", function () { describe("L.Polyline#toGeoJSON", function () {
@ -127,6 +151,14 @@ describe("L.Polyline#toGeoJSON", function () {
coordinates: [[20, 10, 30], [5, 2, 10]] coordinates: [[20, 10, 30], [5, 2, 10]]
}); });
}); });
it("should allow specific precisions", function () {
var polyline = new L.Polyline([[10.1234, 20.1234, 30.1234], [2.1234, 5.1234, 10.1234]]);
expect(polyline.toGeoJSON(3).geometry).to.eql({
type: 'LineString',
coordinates: [[20.123, 10.123, 30.123], [5.123, 2.123, 10.123]]
});
});
}); });
describe("L.Polyline (multi) #toGeoJSON", function () { describe("L.Polyline (multi) #toGeoJSON", function () {
@ -151,6 +183,17 @@ describe("L.Polyline (multi) #toGeoJSON", function () {
] ]
}); });
}); });
it("should allow specific precisions", function () {
var multiPolyline = new L.Polyline([[[10.1234, 20.1234, 30.1234], [2.1234, 5.1234, 10.1234]], [[1.1234, 2.1234, 3.1234], [4.1234, 5.1234, 6.1234]]]);
expect(multiPolyline.toGeoJSON(3).geometry).to.eql({
type: 'MultiLineString',
coordinates: [
[[20.123, 10.123, 30.123], [5.123, 2.123, 10.123]],
[[2.123, 1.123, 3.123], [5.123, 4.123, 6.123]]
]
});
});
}); });
describe("L.Polygon#toGeoJSON", function () { describe("L.Polygon#toGeoJSON", function () {
@ -212,6 +255,13 @@ describe("L.Polygon#toGeoJSON", function () {
}); });
}); });
it("should allow specific precisions", function () {
var polygon = new L.Polygon([[1.1234, 2.1234], [3.1234, 4.1234], [5.1234, 6.1234]]);
expect(polygon.toGeoJSON(3).geometry).to.eql({
type: 'Polygon',
coordinates: [[[2.123, 1.123], [4.123, 3.123], [6.123, 5.123], [2.123, 1.123]]]
});
});
}); });
describe("L.Polygon (multi) #toGeoJSON", function () { describe("L.Polygon (multi) #toGeoJSON", function () {
@ -256,6 +306,15 @@ describe("L.Polygon (multi) #toGeoJSON", function () {
}); });
}); });
it("should allow specific precisions", function () {
var multiPolygon = new L.Polygon([[[[1.1234, 2.1234], [3.1234, 4.1234], [5.1234, 6.1234]]]]);
expect(multiPolygon.toGeoJSON(3).geometry).to.eql({
type: 'MultiPolygon',
coordinates: [
[[[2.123, 1.123], [4.123, 3.123], [6.123, 5.123], [2.123, 1.123]]]
]
});
});
}); });
describe("L.LayerGroup#toGeoJSON", function () { describe("L.LayerGroup#toGeoJSON", function () {
@ -327,10 +386,29 @@ describe("L.LayerGroup#toGeoJSON", function () {
}] }]
}; };
expect(L.geoJSON(json).toGeoJSON()).to.eql(json); var expected = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "GeometryCollection",
"geometries": [{
"type": "LineString",
"coordinates": [[-122.442559, 37.806664], [-122.442838, 37.806636]]
}, {
"type": "LineString",
"coordinates": [[-122.442551, 37.806626], [-122.442834, 37.8066]]
}]
},
"properties": {
"name": "SF Marina Harbor Master"
}
}]
};
expect(L.geoJSON(json).toGeoJSON()).to.eql(expected);
}); });
it('roundtrips MiltiPoint features', function () { it('roundtrips MultiPoint features', function () {
var json = { var json = {
"type": "FeatureCollection", "type": "FeatureCollection",
"features": [{ "features": [{
@ -345,7 +423,20 @@ describe("L.LayerGroup#toGeoJSON", function () {
}] }]
}; };
expect(L.geoJSON(json).toGeoJSON()).to.eql(json); var expected = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "MultiPoint",
"coordinates": [[-122.442559, 37.806664], [-122.442838, 37.806636]]
},
"properties": {
"name": "Test MultiPoints"
}
}]
};
expect(L.geoJSON(json).toGeoJSON()).to.eql(expected);
}); });
it("omits layers which do not implement toGeoJSON", function () { it("omits layers which do not implement toGeoJSON", function () {
@ -369,4 +460,14 @@ describe("L.LayerGroup#toGeoJSON", function () {
expect(geoJSON.features[0].type).to.eql("Feature"); expect(geoJSON.features[0].type).to.eql("Feature");
expect(geoJSON.features[1].type).to.eql("Feature"); expect(geoJSON.features[1].type).to.eql("Feature");
}); });
it("should allow specific precisions", function () {
var marker = new L.Marker([10, 20]),
polyline = new L.Polyline([[10, 20], [2, 5]]),
layerGroup = new L.LayerGroup([marker, polyline]);
expect(layerGroup.toGeoJSON(3)).to.eql({
type: 'FeatureCollection',
features: [marker.toGeoJSON(3), polyline.toGeoJSON(3)]
});
});
}); });

View File

@ -240,24 +240,25 @@ export function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) {
return latlngs; return latlngs;
} }
// @function latLngToCoords(latlng: LatLng): Array // @function latLngToCoords(latlng: LatLng, precision?: Number): Array
// Reverse of [`coordsToLatLng`](#geojson-coordstolatlng) // Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)
export function latLngToCoords(latlng) { export function latLngToCoords(latlng, precision) {
precision = typeof precision === 'number' ? precision : 6;
return latlng.alt !== undefined ? return latlng.alt !== undefined ?
[latlng.lng, latlng.lat, latlng.alt] : [Util.formatNum(latlng.lng, precision), Util.formatNum(latlng.lat, precision), Util.formatNum(latlng.alt, precision)] :
[latlng.lng, latlng.lat]; [Util.formatNum(latlng.lng, precision), Util.formatNum(latlng.lat, precision)];
} }
// @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean): Array // @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean): Array
// Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs) // Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)
// `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default. // `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default.
export function latLngsToCoords(latlngs, levelsDeep, closed) { export function latLngsToCoords(latlngs, levelsDeep, closed, precision) {
var coords = []; var coords = [];
for (var i = 0, len = latlngs.length; i < len; i++) { for (var i = 0, len = latlngs.length; i < len; i++) {
coords.push(levelsDeep ? coords.push(levelsDeep ?
latLngsToCoords(latlngs[i], levelsDeep - 1, closed) : latLngsToCoords(latlngs[i], levelsDeep - 1, closed, precision) :
latLngToCoords(latlngs[i])); latLngToCoords(latlngs[i], precision));
} }
if (!levelsDeep && closed) { if (!levelsDeep && closed) {
@ -288,10 +289,10 @@ export function asFeature(geojson) {
} }
var PointToGeoJSON = { var PointToGeoJSON = {
toGeoJSON: function () { toGeoJSON: function (precision) {
return getFeature(this, { return getFeature(this, {
type: 'Point', type: 'Point',
coordinates: latLngToCoords(this.getLatLng()) coordinates: latLngToCoords(this.getLatLng(), precision)
}); });
} }
}; };
@ -312,10 +313,10 @@ CircleMarker.include(PointToGeoJSON);
// @method toGeoJSON(): Object // @method toGeoJSON(): Object
// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature). // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).
Polyline.include({ Polyline.include({
toGeoJSON: function () { toGeoJSON: function (precision) {
var multi = !LineUtil._flat(this._latlngs); var multi = !LineUtil._flat(this._latlngs);
var coords = latLngsToCoords(this._latlngs, multi ? 1 : 0); var coords = latLngsToCoords(this._latlngs, multi ? 1 : 0, false, precision);
return getFeature(this, { return getFeature(this, {
type: (multi ? 'Multi' : '') + 'LineString', type: (multi ? 'Multi' : '') + 'LineString',
@ -328,11 +329,11 @@ Polyline.include({
// @method toGeoJSON(): Object // @method toGeoJSON(): Object
// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature). // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).
Polygon.include({ Polygon.include({
toGeoJSON: function () { toGeoJSON: function (precision) {
var holes = !LineUtil._flat(this._latlngs), var holes = !LineUtil._flat(this._latlngs),
multi = holes && !LineUtil._flat(this._latlngs[0]); multi = holes && !LineUtil._flat(this._latlngs[0]);
var coords = latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true); var coords = latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true, precision);
if (!holes) { if (!holes) {
coords = [coords]; coords = [coords];
@ -348,11 +349,11 @@ Polygon.include({
// @namespace LayerGroup // @namespace LayerGroup
LayerGroup.include({ LayerGroup.include({
toMultiPoint: function () { toMultiPoint: function (precision) {
var coords = []; var coords = [];
this.eachLayer(function (layer) { this.eachLayer(function (layer) {
coords.push(layer.toGeoJSON().geometry.coordinates); coords.push(layer.toGeoJSON(precision).geometry.coordinates);
}); });
return getFeature(this, { return getFeature(this, {
@ -363,12 +364,12 @@ LayerGroup.include({
// @method toGeoJSON(): Object // @method toGeoJSON(): Object
// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`). // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`).
toGeoJSON: function () { toGeoJSON: function (precision) {
var type = this.feature && this.feature.geometry && this.feature.geometry.type; var type = this.feature && this.feature.geometry && this.feature.geometry.type;
if (type === 'MultiPoint') { if (type === 'MultiPoint') {
return this.toMultiPoint(); return this.toMultiPoint(precision);
} }
var isGeometryCollection = type === 'GeometryCollection', var isGeometryCollection = type === 'GeometryCollection',
@ -376,7 +377,7 @@ LayerGroup.include({
this.eachLayer(function (layer) { this.eachLayer(function (layer) {
if (layer.toGeoJSON) { if (layer.toGeoJSON) {
var json = layer.toGeoJSON(); var json = layer.toGeoJSON(precision);
if (isGeometryCollection) { if (isGeometryCollection) {
jsons.push(json.geometry); jsons.push(json.geometry);
} else { } else {