fix GeoJSON roundtripping

This commit is contained in:
Vladimir Agafonkin 2013-12-13 12:32:26 -05:00
parent 87bf1ff144
commit dc5151b81a
5 changed files with 88 additions and 94 deletions

View File

@ -147,7 +147,7 @@ var deps = {
GeoJSON: { GeoJSON: {
src: ['layer/GeoJSON.js'], src: ['layer/GeoJSON.js'],
deps: ['Polygon', 'Circle', 'Marker', 'FeatureGroup'], deps: ['Polygon', 'Circle', 'CircleMarker', 'Marker', 'FeatureGroup'],
desc: 'GeoJSON layer, parses the data and adds corresponding layers above.' desc: 'GeoJSON layer, parses the data and adds corresponding layers above.'
}, },

View File

@ -36,7 +36,7 @@
var circle = L.circle([35, 0], 700000, {color: 'green', renderer: canvas}).addTo(map).bindPopup('Hello Circle'); var circle = L.circle([35, 0], 700000, {color: 'green', renderer: canvas}).addTo(map).bindPopup('Hello Circle');
map.fitBounds(path); map.setView([36, 52], 3);
</script> </script>
</body> </body>
</html> </html>

View File

@ -95,9 +95,9 @@ describe("L.Polyline#toGeoJSON", function () {
}); });
}); });
describe("L.MultiPolyline#toGeoJSON", function () { describe("L.Polyline (multi) #toGeoJSON", function () {
it("returns a 2D MultiLineString object", function () { it("returns a 2D MultiLineString object", function () {
var multiPolyline = new L.MultiPolyline([[[10, 20], [2, 5]], [[1, 2], [3, 4]]]); var multiPolyline = new L.Polyline([[[10, 20], [2, 5]], [[1, 2], [3, 4]]]);
expect(multiPolyline.toGeoJSON().geometry).to.eql({ expect(multiPolyline.toGeoJSON().geometry).to.eql({
type: 'MultiLineString', type: 'MultiLineString',
coordinates: [ coordinates: [
@ -108,7 +108,7 @@ describe("L.MultiPolyline#toGeoJSON", function () {
}); });
it("returns a 3D MultiLineString object", function () { it("returns a 3D MultiLineString object", function () {
var multiPolyline = new L.MultiPolyline([[[10, 20, 30], [2, 5, 10]], [[1, 2, 3], [4, 5, 6]]]); var multiPolyline = new L.Polyline([[[10, 20, 30], [2, 5, 10]], [[1, 2, 3], [4, 5, 6]]]);
expect(multiPolyline.toGeoJSON().geometry).to.eql({ expect(multiPolyline.toGeoJSON().geometry).to.eql({
type: 'MultiLineString', type: 'MultiLineString',
coordinates: [ coordinates: [
@ -159,9 +159,9 @@ describe("L.Polygon#toGeoJSON", function () {
}); });
}); });
describe("L.MultiPolygon#toGeoJSON", function () { describe("L.Polygon (multi) #toGeoJSON", function () {
it("returns a 2D MultiPolygon object", function () { it("returns a 2D MultiPolygon object", function () {
var multiPolygon = new L.MultiPolygon([[[1, 2], [3, 4], [5, 6]]]); var multiPolygon = new L.Polygon([[[1, 2], [3, 4], [5, 6]]]);
expect(multiPolygon.toGeoJSON().geometry).to.eql({ expect(multiPolygon.toGeoJSON().geometry).to.eql({
type: 'MultiPolygon', type: 'MultiPolygon',
coordinates: [ coordinates: [
@ -171,7 +171,7 @@ describe("L.MultiPolygon#toGeoJSON", function () {
}); });
it("returns a 3D MultiPolygon object", function () { it("returns a 3D MultiPolygon object", function () {
var multiPolygon = new L.MultiPolygon([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]); var multiPolygon = new L.Polygon([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]);
expect(multiPolygon.toGeoJSON().geometry).to.eql({ expect(multiPolygon.toGeoJSON().geometry).to.eql({
type: 'MultiPolygon', type: 'MultiPolygon',
coordinates: [ coordinates: [

View File

@ -99,23 +99,14 @@ L.extend(L.GeoJSON, {
return new L.FeatureGroup(layers); return new L.FeatureGroup(layers);
case 'LineString': case 'LineString':
latlngs = this.coordsToLatLngs(coords, 0, coordsToLatLng); case 'MultiLineString':
latlngs = this.coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, coordsToLatLng);
return new L.Polyline(latlngs, options); return new L.Polyline(latlngs, options);
case 'Polygon': case 'Polygon':
if (coords.length === 2 && !coords[1].length) {
throw new Error('Invalid GeoJSON object.');
}
latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng);
return new L.Polygon(latlngs, options);
case 'MultiLineString':
latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng);
return new L.MultiPolyline(latlngs, options);
case 'MultiPolygon': case 'MultiPolygon':
latlngs = this.coordsToLatLngs(coords, 2, coordsToLatLng); latlngs = this.coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, coordsToLatLng);
return new L.MultiPolygon(latlngs, options); return new L.Polygon(latlngs, options);
case 'GeometryCollection': case 'GeometryCollection':
for (i = 0, len = geometry.geometries.length; i < len; i++) { for (i = 0, len = geometry.geometries.length; i < len; i++) {
@ -157,11 +148,17 @@ L.extend(L.GeoJSON, {
[latlng.lng, latlng.lat]; [latlng.lng, latlng.lat];
}, },
latLngsToCoords: function (latLngs) { latLngsToCoords: function (latlngs, levelsDeep, closed) {
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(L.GeoJSON.latLngToCoords(latLngs[i])); coords.push(levelsDeep ?
L.GeoJSON.latLngsToCoords(latlngs[i], levelsDeep - 1, closed):
L.GeoJSON.latLngToCoords(latlngs[i]));
}
if (!levelsDeep && closed) {
coords.push(coords[0]);
} }
return coords; return coords;
@ -199,90 +196,83 @@ L.Marker.include(PointToGeoJSON);
L.Circle.include(PointToGeoJSON); L.Circle.include(PointToGeoJSON);
L.CircleMarker.include(PointToGeoJSON); L.CircleMarker.include(PointToGeoJSON);
L.Polyline.include({ L.Polyline.prototype.toGeoJSON = function () {
toGeoJSON: function () { var multi = !this._flat(this._latlngs);
return L.GeoJSON.getFeature(this, {
type: 'LineString', var coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 1 : 0);
coordinates: L.GeoJSON.latLngsToCoords(this.getLatLngs())
}); return L.GeoJSON.getFeature(this, {
type: (multi ? 'Multi' : '') + 'LineString',
coordinates: coords
});
};
L.Polygon.prototype.toGeoJSON = function () {
var holes = !this._flat(this._latlngs),
multi = holes && !this._flat(this._latlngs[0]);
var coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true);
if (holes && this._latlngs.length === 1) {
multi = true;
coords = [coords];
}
if (!holes) {
coords = [coords];
} }
});
L.Polygon.include({ return L.GeoJSON.getFeature(this, {
toGeoJSON: function () { type: (multi ? 'Multi' : '') + 'Polygon',
var coords = [L.GeoJSON.latLngsToCoords(this.getLatLngs())], coordinates: coords
i, len, hole; });
};
coords[0].push(coords[0][0]);
if (this._holes) { L.LayerGroup.include({
for (i = 0, len = this._holes.length; i < len; i++) { toMultiPoint: function () {
hole = L.GeoJSON.latLngsToCoords(this._holes[i]); var coords = [];
hole.push(hole[0]);
coords.push(hole); this.eachLayer(function (layer) {
} coords.push(layer.toGeoJSON().geometry.coordinates);
} });
return L.GeoJSON.getFeature(this, { return L.GeoJSON.getFeature(this, {
type: 'Polygon', type: 'MultiPoint',
coordinates: coords coordinates: coords
}); });
} },
});
(function () { toGeoJSON: function () {
function multiToGeoJSON(type) {
return function () {
var coords = [];
this.eachLayer(function (layer) { var type = this.feature && this.feature.geometry && this.feature.geometry.type;
coords.push(layer.toGeoJSON().geometry.coordinates);
});
if (type === 'MultiPoint') {
return this.toMultiPoint();
}
var isGeometryCollection = type === 'GeometryCollection',
jsons = [];
this.eachLayer(function (layer) {
if (layer.toGeoJSON) {
var json = layer.toGeoJSON();
jsons.push(isGeometryCollection ? json.geometry : L.GeoJSON.asFeature(json));
}
});
if (isGeometryCollection) {
return L.GeoJSON.getFeature(this, { return L.GeoJSON.getFeature(this, {
type: type, geometries: jsons,
coordinates: coords type: 'GeometryCollection'
}); });
}
return {
type: 'FeatureCollection',
features: jsons
}; };
} }
});
L.MultiPolyline.include({toGeoJSON: multiToGeoJSON('MultiLineString')});
L.MultiPolygon.include({toGeoJSON: multiToGeoJSON('MultiPolygon')});
L.LayerGroup.include({
toGeoJSON: function () {
var geometry = this.feature && this.feature.geometry,
jsons = [],
json;
if (geometry && geometry.type === 'MultiPoint') {
return multiToGeoJSON('MultiPoint').call(this);
}
var isGeometryCollection = geometry && geometry.type === 'GeometryCollection';
this.eachLayer(function (layer) {
if (layer.toGeoJSON) {
json = layer.toGeoJSON();
jsons.push(isGeometryCollection ? json.geometry : L.GeoJSON.asFeature(json));
}
});
if (isGeometryCollection) {
return L.GeoJSON.getFeature(this, {
geometries: jsons,
type: 'GeometryCollection'
});
}
return {
type: 'FeatureCollection',
features: jsons
};
}
});
}());
L.geoJson = function (geojson, options) { L.geoJson = function (geojson, options) {
return new L.GeoJSON(geojson, options); return new L.GeoJSON(geojson, options);

View File

@ -72,7 +72,7 @@ L.Polyline = L.Path.extend({
_convertLatLngs: function (latlngs) { _convertLatLngs: function (latlngs) {
var result = [], var result = [],
flat = !L.Util.isArray(latlngs[0]) || typeof latlngs[0][0] === 'number'; flat = this._flat(latlngs);
for (var i = 0, len = latlngs.length; i < len; i++) { for (var i = 0, len = latlngs.length; i < len; i++) {
result[i] = flat ? L.latLng(latlngs[i]) : this._convertLatLngs(latlngs[i]); result[i] = flat ? L.latLng(latlngs[i]) : this._convertLatLngs(latlngs[i]);
@ -81,6 +81,10 @@ L.Polyline = L.Path.extend({
return result; return result;
}, },
_flat: function (latlngs) {
return !L.Util.isArray(latlngs[0]) || typeof latlngs[0][0] === 'number';
},
_project: function () { _project: function () {
this._rings = []; this._rings = [];
this._projectLatlngs(this._latlngs, this._rings); this._projectLatlngs(this._latlngs, this._rings);